]> granicus.if.org Git - postgresql/blobdiff - src/backend/postmaster/postmaster.c
Replace the BufMgrLock with separate locks on the lookup hashtable and
[postgresql] / src / backend / postmaster / postmaster.c
index c9a0d737c44cbb390015425f9e9d5bc753710829..d84bf2775768ee2628cbc09ee84bfbff89959964 100644 (file)
@@ -7,10 +7,10 @@
  *       message to setup a backend process.
  *
  *       The postmaster also manages system-wide operations such as
- *       startup, shutdown, and periodic checkpoints.  The postmaster
- *       itself doesn't do those operations, mind you --- it just forks
- *       off a subprocess to do them at the right times.  It also takes
- *       care of resetting the system if a backend crashes.
+ *       startup and shutdown. The postmaster itself doesn't do those
+ *       operations, mind you --- it just forks off a subprocess to do them
+ *       at the right times.  It also takes care of resetting the system
+ *       if a backend crashes.
  *
  *       The postmaster process creates the shared memory and semaphore
  *       pools during startup, but as a rule does not touch them itself.
  *       clients.
  *
  *
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.389 2004/05/18 20:18:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.445 2005/02/22 04:36:36 momjian Exp $
  *
  * NOTES
  *
  * Initialization:
- *             The Postmaster sets up a few shared memory data structures
- *             for the backends.  It should at the very least initialize the
- *             lock manager.
+ *             The Postmaster sets up shared memory data structures
+ *             for the backends.
  *
  * Synchronization:
  *             The Postmaster shares memory with the backends but should avoid
  *             The Postmaster cleans up after backends if they have an emergency
  *             exit and/or core dump.
  *
+ * Error Reporting:
+ *             Use write_stderr() only for reporting "interactive" errors
+ *             (essentially, bogus arguments on the command line).  Once the
+ *             postmaster is launched, use ereport().  In particular, don't use
+ *             write_stderr() for anything that occurs after pmdaemonize.
+ *
  *-------------------------------------------------------------------------
  */
 
 
 #include <unistd.h>
 #include <signal.h>
+#include <time.h>
 #include <sys/wait.h>
 #include <ctype.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/socket.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <time.h>
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -89,6 +92,7 @@
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 #endif
 
+#include "catalog/pg_control.h"
 #include "catalog/pg_database.h"
 #include "commands/async.h"
 #include "lib/dllist.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "nodes/nodes.h"
+#include "postmaster/postmaster.h"
+#include "postmaster/pgarch.h"
+#include "postmaster/syslogger.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 #include "storage/bufmgr.h"
 #include "access/xlog.h"
 #include "tcop/tcopprot.h"
+#include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "bootstrap/bootstrap.h"
 #include "pgstat.h"
 
-
-#define INVALID_SOCK   (-1)
-
-#ifdef HAVE_SIGPROCMASK
-sigset_t       UnBlockSig,
-                       BlockSig,
-                       AuthBlockSig;
-
-#else
-int                    UnBlockSig,
-                       BlockSig,
-                       AuthBlockSig;
+#ifdef EXEC_BACKEND
+#include "storage/spin.h"
 #endif
 
+
 /*
  * List of active backends (or child processes anyway; we don't actually
  * know whether a given child has become a backend or is still in the
  * authorization phase).  This is used mainly to keep track of how many
  * children we have and send them appropriate signals when necessary.
+ *
+ * "Special" children such as the startup and bgwriter tasks are not in
+ * this list.
  */
 typedef struct bkend
 {
@@ -151,15 +153,6 @@ int                        PostPortNumber;
 char      *UnixSocketDir;
 char      *ListenAddresses;
 
-/*
- * MaxBackends is the limit on the number of backends we can start.
- * Note that a larger MaxBackends value will increase the size of the
- * shared memory area as well as cause the postmaster to grab more
- * kernel semaphores, even if you never actually use that many
- * backends.
- */
-int                    MaxBackends;
-
 /*
  * ReservedBackends is the number of backends reserved for superuser use.
  * This number is taken out of the pool size given by MaxBackends so
@@ -175,16 +168,9 @@ int                        ReservedBackends;
 static const char *progname = NULL;
 
 /* The socket(s) we're listening to. */
-#define MAXLISTEN      10
+#define MAXLISTEN      64
 static int     ListenSocket[MAXLISTEN];
 
-/* Used to reduce macros tests */
-#ifdef EXEC_BACKEND
-const bool     ExecBackend = true;
-#else
-const bool     ExecBackend = false;
-#endif
-
 /*
  * Set by the -o option
  */
@@ -206,9 +192,6 @@ bool                SilentMode = false; /* silent mode (-S) */
 
 int                    PreAuthDelay = 0;
 int                    AuthenticationTimeout = 60;
-int                    CheckPointTimeout = 300;
-int                    CheckPointWarning = 30;
-time_t         LastSignalledCheckpoint = 0;
 
 bool           log_hostname;           /* for ps display and logging */
 bool           Log_connections = false;
@@ -219,13 +202,14 @@ char         *rendezvous_name;
 /* list of library:init-function to be preloaded */
 char      *preload_libraries_string = NULL;
 
-/* Startup/shutdown state */
+/* PIDs of special child processes; 0 when not running */
 static pid_t StartupPID = 0,
-                       ShutdownPID = 0,
-                       CheckPointPID = 0,
-                       BgWriterPID = 0;
-static time_t checkpointed = 0;
+                       BgWriterPID = 0,
+                       PgArchPID = 0,
+                       PgStatPID = 0,
+                       SysLoggerPID = 0;
 
+/* Startup/shutdown state */
 #define                        NoShutdown              0
 #define                        SmartShutdown   1
 #define                        FastShutdown    2
@@ -242,11 +226,8 @@ bool               ClientAuthInProgress = false;           /* T during new-client
  * Also, the global MyCancelKey passes the cancel key assigned to a given
  * backend from the postmaster to that backend (via fork).
  */
-
 static unsigned int random_seed = 0;
 
-static int     debug_flag = 0;
-
 extern char *optarg;
 extern int     optind,
                        opterr;
@@ -258,7 +239,13 @@ extern int optreset;
 /*
  * postmaster.c - function prototypes
  */
-static void pmdaemonize(int argc, char *argv[]);
+static void checkDataDir(void);
+
+#ifdef USE_RENDEZVOUS
+static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
+                 void *context);
+#endif
+static void pmdaemonize(void);
 static Port *ConnCreate(int serverFd);
 static void ConnFree(Port *port);
 static void reset_shared(unsigned short port);
@@ -267,11 +254,11 @@ static void pmdie(SIGNAL_ARGS);
 static void reaper(SIGNAL_ARGS);
 static void sigusr1_handler(SIGNAL_ARGS);
 static void dummy_handler(SIGNAL_ARGS);
-static void CleanupProc(int pid, int exitstatus);
+static void CleanupBackend(int pid, int exitstatus);
+static void HandleChildCrash(int pid, int exitstatus, const char *procname);
 static void LogChildExit(int lev, const char *procname,
                         int pid, int exitstatus);
-static void BackendInit(Port *port);
-static int  BackendRun(Port *port);
+static int     BackendRun(Port *port);
 static void ExitPostmaster(int status);
 static void usage(const char *);
 static int     ServerLoop(void);
@@ -286,132 +273,108 @@ static void RandomSalt(char *cryptSalt, char *md5Salt);
 static void SignalChildren(int signal);
 static int     CountChildren(void);
 static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
-NON_EXEC_STATIC void SSDataBaseInit(int xlop);
-static pid_t SSDataBase(int xlop);
-static void
-postmaster_error(const char *fmt,...)
-/* This lets gcc check the format string for consistency. */
-__attribute__((format(printf, 1, 2)));
+static pid_t StartChildProcess(int xlop);
 
 #ifdef EXEC_BACKEND
 
 #ifdef WIN32
-pid_t win32_forkexec(const char* path, char *argv[]);
-
-static void  win32_AddChild(pid_t pid, HANDLE handle);
-static void  win32_RemoveChild(pid_t pid);
+static void win32_AddChild(pid_t pid, HANDLE handle);
+static void win32_RemoveChild(pid_t pid);
 static pid_t win32_waitpid(int *exitstatus);
 static DWORD WINAPI win32_sigchld_waiter(LPVOID param);
 
-static pid_t  *win32_childPIDArray;
+static pid_t *win32_childPIDArray;
 static HANDLE *win32_childHNDArray;
 static unsigned long win32_numChildren = 0;
-#endif
-
-static pid_t Backend_forkexec(Port *port);
 
-static unsigned long tmpBackendFileNum = 0;
-void read_backend_variables(unsigned long id, Port *port);
-static bool write_backend_variables(Port *port);
-
-static void    ShmemBackendArrayAdd(Backend *bn);
-static void ShmemBackendArrayRemove(pid_t pid);
+HANDLE         PostmasterHandle;
 #endif
 
-#define StartupDataBase()              SSDataBase(BS_XLOG_STARTUP)
-#define CheckPointDataBase()   SSDataBase(BS_XLOG_CHECKPOINT)
-#define StartBackgroundWriter()        SSDataBase(BS_XLOG_BGWRITER)
-#define ShutdownDataBase()             SSDataBase(BS_XLOG_SHUTDOWN)
+static pid_t backend_forkexec(Port *port);
+static pid_t internal_forkexec(int argc, char *argv[], Port *port);
 
-static void
-checkDataDir(const char *checkdir)
+/* Type for a socket that can be inherited to a client process */
+#ifdef WIN32
+typedef struct
 {
-       char            path[MAXPGPATH];
-       FILE       *fp;
-       struct stat stat_buf;
-
-       if (checkdir == NULL)
-       {
-               fprintf(stderr,
-                               gettext("%s does not know where to find the database system data.\n"
-                                               "You must specify the directory that contains the database system\n"
-                                               "either by specifying the -D invocation option or by setting the\n"
-                                               "PGDATA environment variable.\n"),
-                               progname);
-               ExitPostmaster(2);
-       }
-
-       if (stat(checkdir, &stat_buf) == -1)
-       {
-               if (errno == ENOENT)
-                       ereport(FATAL,
-                                       (errcode_for_file_access(),
-                                        errmsg("data directory \"%s\" does not exist",
-                                                       checkdir)));
-               else
-                       ereport(FATAL,
-                                       (errcode_for_file_access(),
-                        errmsg("could not read permissions of directory \"%s\": %m",
-                                       checkdir)));
-       }
-
-       /*
-        * Check if the directory has group or world access.  If so, reject.
-        *
-        * XXX temporarily suppress check when on Windows, because there may not
-        * be proper support for Unix-y file permissions.  Need to think of a
-        * reasonable check to apply on Windows.
-        */
-#if !defined(__CYGWIN__) && !defined(WIN32)
-       if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
-               ereport(FATAL,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("data directory \"%s\" has group or world access",
-                                               checkdir),
-                                errdetail("Permissions should be u=rwx (0700).")));
+       SOCKET origsocket; /* Original socket value, or -1 if not a socket */
+       WSAPROTOCOL_INFO wsainfo;
+} InheritableSocket;
+#else
+typedef int InheritableSocket;
 #endif
 
-       /* Look for PG_VERSION before looking for pg_control */
-       ValidatePgVersion(checkdir);
+typedef struct LWLock LWLock;  /* ugly kluge */
 
-       snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
+/*
+ * Structure contains all variables passed to exec:ed backends
+ */
+typedef struct
+{
+       Port port;
+       InheritableSocket portsocket;
+       char DataDir[MAXPGPATH];
+       int ListenSocket[MAXLISTEN];
+       long MyCancelKey;
+       unsigned long UsedShmemSegID;
+       void *UsedShmemSegAddr;
+       slock_t *ShmemLock;
+       slock_t *ShmemIndexLock;
+       VariableCache ShmemVariableCache;
+       void *ShmemIndexAlloc;
+       Backend *ShmemBackendArray;
+       LWLock *LWLockArray;
+       slock_t *ProcStructLock;
+       InheritableSocket pgStatSock;
+       InheritableSocket pgStatPipe0;
+       InheritableSocket pgStatPipe1;
+       pid_t PostmasterPid;
+#ifdef WIN32
+       HANDLE PostmasterHandle;
+       HANDLE initial_signal_pipe;
+       HANDLE syslogPipe[2];
+#else
+       int syslogPipe[2];
+#endif
+       char my_exec_path[MAXPGPATH];
+       char ExtraOptions[MAXPGPATH];
+       char lc_collate[LOCALE_NAME_BUFLEN];
+       char lc_ctype[LOCALE_NAME_BUFLEN];
+} BackendParameters;
 
-       fp = AllocateFile(path, PG_BINARY_R);
-       if (fp == NULL)
-       {
-               fprintf(stderr,
-                               gettext("%s: could not find the database system\n"
-                                               "Expected to find it in the directory \"%s\",\n"
-                                               "but could not open file \"%s\": %s\n"),
-                               progname, checkdir, path, strerror(errno));
-               ExitPostmaster(2);
-       }
-       FreeFile(fp);
-}
+static void read_backend_variables(char *id, Port *port);
+static void restore_backend_variables(BackendParameters *param, Port *port);
+#ifndef WIN32
+static bool save_backend_variables(BackendParameters *param, Port *port);
+#else
+static bool save_backend_variables(BackendParameters *param, Port *port,
+                                                                  HANDLE childProcess, pid_t childPid);
+#endif
 
+static void ShmemBackendArrayAdd(Backend *bn);
+static void ShmemBackendArrayRemove(pid_t pid);
 
-#ifdef USE_RENDEZVOUS
+#endif   /* EXEC_BACKEND */
 
-/* reg_reply -- empty callback function for DNSServiceRegistrationCreate() */
-static void
-reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
-{
+#define StartupDataBase()              StartChildProcess(BS_XLOG_STARTUP)
+#define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
 
-}
-#endif
 
+/*
+ * Postmaster main entry point
+ */
 int
 PostmasterMain(int argc, char *argv[])
 {
        int                     opt;
        int                     status;
-       char            original_extraoptions[MAXPGPATH];
-       char       *potential_DataDir = NULL;
+       char       *userDoption = NULL;
        int                     i;
 
-       *original_extraoptions = '\0';
+       /* This will call exit() if strdup() fails. */
+       progname = get_progname(argv[0]);       
 
-       progname = get_progname(argv[0]);
+       MyProcPid = PostmasterPid = getpid();
 
        IsPostmasterEnvironment = true;
 
@@ -433,14 +396,17 @@ PostmasterMain(int argc, char *argv[])
                }
        }
 
+#ifdef WIN32
+       /* Start our win32 signal implementation */
+       pgwin32_signal_initialize();
+#endif
+
        /*
         * for security, no dir or file created can be group or other
         * accessible
         */
        umask((mode_t) 0077);
 
-       MyProcPid = PostmasterPid = getpid();
-
        /*
         * Fire up essential subsystems: memory management
         */
@@ -461,13 +427,17 @@ PostmasterMain(int argc, char *argv[])
 
        IgnoreSystemIndexes(false);
 
+       if (find_my_exec(argv[0], my_exec_path) < 0)
+               elog(FATAL, "%s: could not locate my own executable path",
+                        argv[0]);
+
+       get_pkglib_path(my_exec_path, pkglib_path);
+
        /*
         * Options setup
         */
        InitializeGUCOptions();
 
-       potential_DataDir = getenv("PGDATA");           /* default value */
-
        opterr = 1;
 
        while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
@@ -478,7 +448,7 @@ PostmasterMain(int argc, char *argv[])
 #ifdef USE_ASSERT_CHECKING
                                SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);
 #else
-                               postmaster_error("assert checking is not compiled in");
+                               write_stderr("%s: assert checking is not compiled in\n", progname);
 #endif
                                break;
                        case 'a':
@@ -491,20 +461,11 @@ PostmasterMain(int argc, char *argv[])
                                /* Can no longer set the backend executable file to use. */
                                break;
                        case 'D':
-                               potential_DataDir = optarg;
+                               userDoption = optarg;
                                break;
                        case 'd':
-                               {
-                                       /* Turn on debugging for the postmaster. */
-                                       char       *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
-
-                                       sprintf(debugstr, "debug%s", optarg);
-                                       SetConfigOption("log_min_messages", debugstr,
-                                                                       PGC_POSTMASTER, PGC_S_ARGV);
-                                       pfree(debugstr);
-                                       debug_flag = atoi(optarg);
-                                       break;
-                               }
+                               set_debug_options(atoi(optarg), PGC_POSTMASTER, PGC_S_ARGV);
+                               break;
                        case 'F':
                                SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
                                break;
@@ -545,11 +506,11 @@ PostmasterMain(int argc, char *argv[])
 
                                /*
                                 * Other options to pass to the backend on the command
-                                * line -- useful only for debugging.
+                                * line
                                 */
-                               strcat(ExtraOptions, " ");
-                               strcat(ExtraOptions, optarg);
-                               strcpy(original_extraoptions, optarg);
+                               snprintf(ExtraOptions + strlen(ExtraOptions),
+                                                sizeof(ExtraOptions) - strlen(ExtraOptions),
+                                                " %s", optarg);
                                break;
                        case 'p':
                                SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV);
@@ -603,9 +564,8 @@ PostmasterMain(int argc, char *argv[])
                                }
 
                        default:
-                               fprintf(stderr,
-                                         gettext("Try \"%s --help\" for more information.\n"),
-                                               progname);
+                               write_stderr("Try \"%s --help\" for more information.\n",
+                                                        progname);
                                ExitPostmaster(1);
                }
        }
@@ -615,23 +575,22 @@ PostmasterMain(int argc, char *argv[])
         */
        if (optind < argc)
        {
-               postmaster_error("invalid argument: \"%s\"", argv[optind]);
-               fprintf(stderr,
-                               gettext("Try \"%s --help\" for more information.\n"),
-                               progname);
+               write_stderr("%s: invalid argument: \"%s\"\n",
+                                        progname, argv[optind]);
+               write_stderr("Try \"%s --help\" for more information.\n",
+                                        progname);
                ExitPostmaster(1);
        }
 
        /*
-        * Now we can set the data directory, and then read postgresql.conf.
+        * Locate the proper configuration files and data directory, and
+        * read postgresql.conf for the first time.
         */
-       checkDataDir(potential_DataDir);        /* issues error messages */
-       SetDataDir(potential_DataDir);
+       if (!SelectConfigFiles(userDoption, progname))
+               ExitPostmaster(2);
 
-       ProcessConfigFile(PGC_POSTMASTER);
-#ifdef EXEC_BACKEND
-       write_nondefault_variables(PGC_POSTMASTER);
-#endif
+       /* Verify that DataDir looks reasonable */
+       checkDataDir();
 
        /*
         * Check for invalid combinations of GUC settings.
@@ -643,13 +602,13 @@ PostmasterMain(int argc, char *argv[])
                 * for lack of buffers.  The specific choices here are somewhat
                 * arbitrary.
                 */
-               postmaster_error("the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16");
+               write_stderr("%s: the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16\n", progname);
                ExitPostmaster(1);
        }
 
        if (ReservedBackends >= MaxBackends)
        {
-               postmaster_error("superuser_reserved_connections must be less than max_connections");
+               write_stderr("%s: superuser_reserved_connections must be less than max_connections\n", progname);
                ExitPostmaster(1);
        }
 
@@ -658,7 +617,7 @@ PostmasterMain(int argc, char *argv[])
         */
        if (!CheckDateTokenTables())
        {
-               postmaster_error("invalid datetoken tables, please fix");
+               write_stderr("%s: invalid datetoken tables, please fix\n", progname);
                ExitPostmaster(1);
        }
 
@@ -677,27 +636,25 @@ PostmasterMain(int argc, char *argv[])
                char      **p;
 
                ereport(DEBUG3,
-                               (errmsg_internal("%s: PostmasterMain: initial environ dump:",
-                                                                progname)));
+                       (errmsg_internal("%s: PostmasterMain: initial environ dump:",
+                                                        progname)));
                ereport(DEBUG3,
-                               (errmsg_internal("-----------------------------------------")));
+                (errmsg_internal("-----------------------------------------")));
                for (p = environ; *p; ++p)
                        ereport(DEBUG3,
                                        (errmsg_internal("\t%s", *p)));
                ereport(DEBUG3,
-                               (errmsg_internal("-----------------------------------------")));
+                (errmsg_internal("-----------------------------------------")));
        }
 
-       if (strlen(pkglib_path) == 0)
-               get_pkglib_path(my_exec_path, pkglib_path);
-
 #ifdef EXEC_BACKEND
-       if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR, postgres_exec_path) < 0)
+       if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
+                                               postgres_exec_path) < 0)
                ereport(FATAL,
-                               (errmsg("%s: could not locate postgres executable or non-matching version",
-                                               progname)));
+                        (errmsg("%s: could not locate matching postgres executable",
+                                        progname)));
 #endif
-                                               
+
        /*
         * Initialize SSL library, if specified.
         */
@@ -720,7 +677,7 @@ PostmasterMain(int argc, char *argv[])
         * will show the wrong PID.
         */
        if (SilentMode)
-               pmdaemonize(argc, argv);
+               pmdaemonize();
 
        /*
         * Create lockfile for data directory.
@@ -728,8 +685,8 @@ PostmasterMain(int argc, char *argv[])
         * We want to do this before we try to grab the input sockets, because
         * the data directory interlock is more reliable than the socket-file
         * interlock (thanks to whoever decided to put socket files in /tmp
-        * :-(). For the same reason, it's best to grab the TCP socket before
-        * the Unix socket.
+        * :-(). For the same reason, it's best to grab the TCP socket(s)
+        * before the Unix socket.
         */
        CreateDataDirLockFile(DataDir, true);
 
@@ -748,24 +705,27 @@ PostmasterMain(int argc, char *argv[])
 
        if (ListenAddresses)
        {
-               char       *curhost,
-                                  *endptr;
-               char            c;
+               char       *rawstring;
+               List       *elemlist;
+               ListCell   *l;
+
+               /* Need a modifiable copy of ListenAddresses */
+               rawstring = pstrdup(ListenAddresses);
 
-               curhost = ListenAddresses;
-               for (;;)
+               /* Parse string into list of identifiers */
+               if (!SplitIdentifierString(rawstring, ',', &elemlist))
                {
-                       /* ignore whitespace */
-                       while (isspace((unsigned char) *curhost))
-                               curhost++;
-                       if (*curhost == '\0')
-                               break;
-                       endptr = curhost;
-                       while (*endptr != '\0' && !isspace((unsigned char) *endptr))
-                               endptr++;
-                       c = *endptr;
-                       *endptr = '\0';
-                       if (strcmp(curhost,"*") == 0)
+                       /* syntax error in list */
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                               errmsg("invalid list syntax for \"listen_addresses\"")));
+               }
+
+               foreach(l, elemlist)
+               {
+                       char       *curhost = (char *) lfirst(l);
+
+                       if (strcmp(curhost, "*") == 0)
                                status = StreamServerPort(AF_UNSPEC, NULL,
                                                                                  (unsigned short) PostPortNumber,
                                                                                  UnixSocketDir,
@@ -777,14 +737,12 @@ PostmasterMain(int argc, char *argv[])
                                                                                  ListenSocket, MAXLISTEN);
                        if (status != STATUS_OK)
                                ereport(WARNING,
-                                               (errmsg("could not create listen socket for \"%s\"",
-                                                               curhost)));
-                       *endptr = c;
-                       if (c != '\0')
-                               curhost = endptr+1;
-                       else
-                               break;
+                                        (errmsg("could not create listen socket for \"%s\"",
+                                                        curhost)));
                }
+
+               list_free(elemlist);
+               pfree(rawstring);
        }
 
 #ifdef USE_RENDEZVOUS
@@ -796,7 +754,7 @@ PostmasterMain(int argc, char *argv[])
                                                                         "",
                                                                         htonl(PostPortNumber),
                                                                         "",
-                                                                        (DNSServiceRegistrationReply) reg_reply,
+                                                                (DNSServiceRegistrationReply) reg_reply,
                                                                         NULL);
        }
 #endif
@@ -826,8 +784,9 @@ PostmasterMain(int argc, char *argv[])
        reset_shared(PostPortNumber);
 
        /*
-        * Estimate number of openable files.  This must happen after setting up
-        * semaphores, because on some platforms semaphores count as open files.
+        * Estimate number of openable files.  This must happen after setting
+        * up semaphores, because on some platforms semaphores count as open
+        * files.
         */
        set_max_safe_fds();
 
@@ -837,15 +796,33 @@ PostmasterMain(int argc, char *argv[])
        BackendList = DLNewList();
 
 #ifdef WIN32
+
        /*
-        * Initialize the child pid/HANDLE arrays
+        * Initialize the child pid/HANDLE arrays for signal handling.
         */
-       win32_childPIDArray = (pid_t*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(pid_t));
-       win32_childHNDArray = (HANDLE*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(HANDLE));
+       win32_childPIDArray = (pid_t *)
+               malloc(NUM_BACKENDARRAY_ELEMS * sizeof(pid_t));
+       win32_childHNDArray = (HANDLE *)
+               malloc(NUM_BACKENDARRAY_ELEMS * sizeof(HANDLE));
        if (!win32_childPIDArray || !win32_childHNDArray)
                ereport(FATAL,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
                                 errmsg("out of memory")));
+
+       /*
+        * Set up a handle that child processes can use to check whether the
+        * postmaster is still running.
+        */
+       if (DuplicateHandle(GetCurrentProcess(),
+                                               GetCurrentProcess(),
+                                               GetCurrentProcess(),
+                                               &PostmasterHandle,
+                                               0,
+                                               TRUE,
+                                               DUPLICATE_SAME_ACCESS) == 0)
+               ereport(FATAL,
+                       (errmsg_internal("could not duplicate postmaster handle: error code %d",
+                                                        (int) GetLastError())));
 #endif
 
        /*
@@ -856,21 +833,44 @@ PostmasterMain(int argc, char *argv[])
        if (!CreateOptsFile(argc, argv, my_exec_path))
                ExitPostmaster(1);
 
+#ifdef EXEC_BACKEND
+       write_nondefault_variables(PGC_POSTMASTER);
+#endif
+
+       /*
+        * Write the external PID file if requested
+        */
+       if (external_pid_file)
+       {
+               FILE       *fpidfile = fopen(external_pid_file, "w");
+
+               if (fpidfile)
+               {
+                       fprintf(fpidfile, "%d\n", MyProcPid);
+                       fclose(fpidfile);
+                       /* Should we remove the pid file on postmaster exit? */
+               }
+               else
+                       write_stderr("%s: could not write external PID file \"%s\": %s\n",
+                                                progname, external_pid_file, strerror(errno));
+       }
+
        /*
         * Set up signal handlers for the postmaster process.
         *
         * CAUTION: when changing this list, check for side-effects on the signal
         * handling setup of child processes.  See tcop/postgres.c,
-        * bootstrap/bootstrap.c, and postmaster/pgstat.c.
+        * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgarch.c,
+        * postmaster/pgstat.c, and postmaster/syslogger.c.
         */
        pqinitmask();
        PG_SETMASK(&BlockSig);
 
        pqsignal(SIGHUP, SIGHUP_handler);       /* reread config file and have
                                                                                 * children do same */
-       pqsignal(SIGINT, pmdie);        /* send SIGTERM and ShutdownDataBase */
+       pqsignal(SIGINT, pmdie);        /* send SIGTERM and shut down */
        pqsignal(SIGQUIT, pmdie);       /* send SIGQUIT and die */
-       pqsignal(SIGTERM, pmdie);       /* wait for children and ShutdownDataBase */
+       pqsignal(SIGTERM, pmdie);       /* wait for children and shut down */
        pqsignal(SIGALRM, SIG_IGN); /* ignored */
        pqsignal(SIGPIPE, SIG_IGN); /* ignored */
        pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */
@@ -884,40 +884,29 @@ PostmasterMain(int argc, char *argv[])
 #endif
 
        /*
-        * Reset whereToSendOutput from Debug (its starting state) to None.
-        * This prevents ereport from sending log messages to stderr unless
-        * the syslog/stderr switch permits.  We don't do this until the
-        * postmaster is fully launched, since startup failures may as well be
-        * reported to stderr.
+        * If enabled, start up syslogger collection subprocess
         */
-       whereToSendOutput = None;
+       SysLoggerPID = SysLogger_Start();
 
        /*
-        * On many platforms, the first call of localtime() incurs significant
-        * overhead to load timezone info from the system configuration files.
-        * By doing it once in the postmaster, we avoid having to do it in
-        * every started child process.  The savings are not huge, but they
-        * add up...
+        * Reset whereToSendOutput from Debug (its starting state) to None.
+        * This stops ereport from sending log messages to stderr unless
+        * Log_destination permits.  We don't do this until the postmaster is
+        * fully launched, since startup failures may as well be reported to
+        * stderr.
         */
-       {
-               time_t          now = time(NULL);
-
-               (void) localtime(&now);
-       }
+       whereToSendOutput = None;
 
        /*
-        * Initialize and try to startup the statistics collector process
+        * Initialize the statistics collector stuff
         */
        pgstat_init();
-       pgstat_start();
 
        /*
-        * Load cached files for client authentication.
+        * Load configuration files for client authentication.
         */
        load_hba();
        load_ident();
-       load_user();
-       load_group();
 
        /*
         * We're ready to rock and roll...
@@ -935,13 +924,87 @@ PostmasterMain(int argc, char *argv[])
        return 0;                                       /* not reached */
 }
 
+
+/*
+ * Validate the proposed data directory
+ */
 static void
-pmdaemonize(int argc, char *argv[])
+checkDataDir(void)
 {
-#ifdef WIN32
-       /* not supported */
-       elog(FATAL,"SilentMode not supported under WIN32");
-#else
+       char            path[MAXPGPATH];
+       FILE       *fp;
+       struct stat stat_buf;
+
+       Assert(DataDir);
+
+       if (stat(DataDir, &stat_buf) != 0)
+       {
+               if (errno == ENOENT)
+                       ereport(FATAL,
+                                       (errcode_for_file_access(),
+                                        errmsg("data directory \"%s\" does not exist",
+                                                       DataDir)));
+               else
+                       ereport(FATAL,
+                                       (errcode_for_file_access(),
+                        errmsg("could not read permissions of directory \"%s\": %m",
+                                       DataDir)));
+       }
+
+       /*
+        * Check if the directory has group or world access.  If so, reject.
+        *
+        * XXX temporarily suppress check when on Windows, because there may not
+        * be proper support for Unix-y file permissions.  Need to think of a
+        * reasonable check to apply on Windows.
+        */
+#if !defined(WIN32) && !defined(__CYGWIN__)
+       if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+               ereport(FATAL,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("data directory \"%s\" has group or world access",
+                                               DataDir),
+                                errdetail("Permissions should be u=rwx (0700).")));
+#endif
+
+       /* Look for PG_VERSION before looking for pg_control */
+       ValidatePgVersion(DataDir);
+
+       snprintf(path, sizeof(path), "%s/global/pg_control", DataDir);
+
+       fp = AllocateFile(path, PG_BINARY_R);
+       if (fp == NULL)
+       {
+               write_stderr("%s: could not find the database system\n"
+                                        "Expected to find it in the directory \"%s\",\n"
+                                        "but could not open file \"%s\": %s\n",
+                                        progname, DataDir, path, strerror(errno));
+               ExitPostmaster(2);
+       }
+       FreeFile(fp);
+}
+
+
+#ifdef USE_RENDEZVOUS
+
+/*
+ * empty callback function for DNSServiceRegistrationCreate()
+ */
+static void
+reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
+{
+
+}
+#endif   /* USE_RENDEZVOUS */
+
+
+/*
+ * Fork away from the controlling terminal (-S option)
+ */
+static void
+pmdaemonize(void)
+{
+#ifndef WIN32
        int                     i;
        pid_t           pid;
 
@@ -950,15 +1013,15 @@ pmdaemonize(int argc, char *argv[])
 #endif
 
 #ifdef LINUX_PROFILE
-       /* see comments in BackendRun */
+       /* see comments in BackendStartup */
        getitimer(ITIMER_PROF, &prof_itimer);
 #endif
 
        pid = fork();
        if (pid == (pid_t) -1)
        {
-               postmaster_error("could not fork background process: %s",
-                                                strerror(errno));
+               write_stderr("%s: could not fork background process: %s\n",
+                                        progname, strerror(errno));
                ExitPostmaster(1);
        }
        else if (pid)
@@ -971,7 +1034,7 @@ pmdaemonize(int argc, char *argv[])
        setitimer(ITIMER_PROF, &prof_itimer, NULL);
 #endif
 
-       MyProcPid = getpid();           /* reset MyProcPid to child */
+       MyProcPid = PostmasterPid = getpid();           /* reset PID vars to child */
 
 /* GH: If there's no setsid(), we hopefully don't need silent mode.
  * Until there's a better solution.
@@ -979,72 +1042,80 @@ pmdaemonize(int argc, char *argv[])
 #ifdef HAVE_SETSID
        if (setsid() < 0)
        {
-               postmaster_error("could not dissociate from controlling TTY: %s",
-                                                strerror(errno));
+               write_stderr("%s: could not dissociate from controlling TTY: %s\n",
+                                        progname, strerror(errno));
                ExitPostmaster(1);
        }
 #endif
-       i = open(NULL_DEV, O_RDWR | PG_BINARY);
+       i = open(NULL_DEV, O_RDWR);
        dup2(i, 0);
        dup2(i, 1);
        dup2(i, 2);
        close(i);
-#endif
+#else                                                  /* WIN32 */
+       /* not supported */
+       elog(FATAL, "SilentMode not supported under WIN32");
+#endif   /* WIN32 */
 }
 
 
-
 /*
  * Print out help message
  */
 static void
 usage(const char *progname)
 {
-       printf(gettext("%s is the PostgreSQL server.\n\n"), progname);
-       printf(gettext("Usage:\n  %s [OPTION]...\n\n"), progname);
-       printf(gettext("Options:\n"));
+       printf(_("%s is the PostgreSQL server.\n\n"), progname);
+       printf(_("Usage:\n  %s [OPTION]...\n\n"), progname);
+       printf(_("Options:\n"));
 #ifdef USE_ASSERT_CHECKING
-       printf(gettext("  -A 1|0          enable/disable run-time assert checking\n"));
-#endif
-       printf(gettext("  -B NBUFFERS     number of shared buffers\n"));
-       printf(gettext("  -c NAME=VALUE   set run-time parameter\n"));
-       printf(gettext("  -d 1-5          debugging level\n"));
-       printf(gettext("  -D DATADIR      database directory\n"));
-       printf(gettext("  -F              turn fsync off\n"));
-       printf(gettext("  -h HOSTNAME     host name or IP address to listen on\n"));
-       printf(gettext("  -i              enable TCP/IP connections\n"));
-       printf(gettext("  -k DIRECTORY    Unix-domain socket location\n"));
+       printf(_("  -A 1|0          enable/disable run-time assert checking\n"));
+#endif
+       printf(_("  -B NBUFFERS     number of shared buffers\n"));
+       printf(_("  -c NAME=VALUE   set run-time parameter\n"));
+       printf(_("  -d 1-5          debugging level\n"));
+       printf(_("  -D DATADIR      database directory\n"));
+       printf(_("  -F              turn fsync off\n"));
+       printf(_("  -h HOSTNAME     host name or IP address to listen on\n"));
+       printf(_("  -i              enable TCP/IP connections\n"));
+       printf(_("  -k DIRECTORY    Unix-domain socket location\n"));
 #ifdef USE_SSL
-       printf(gettext("  -l              enable SSL connections\n"));
+       printf(_("  -l              enable SSL connections\n"));
 #endif
-       printf(gettext("  -N MAX-CONNECT  maximum number of allowed connections\n"));
-       printf(gettext("  -o OPTIONS      pass \"OPTIONS\" to each server process\n"));
-       printf(gettext("  -p PORT         port number to listen on\n"));
-       printf(gettext("  -S              silent mode (start in background without logging output)\n"));
-       printf(gettext("  --help          show this help, then exit\n"));
-       printf(gettext("  --version       output version information, then exit\n"));
-
-       printf(gettext("\nDeveloper options:\n"));
-       printf(gettext("  -n              do not reinitialize shared memory after abnormal exit\n"));
-       printf(gettext("  -s              send SIGSTOP to all backend servers if one dies\n"));
-
-       printf(gettext("\nPlease read the documentation for the complete list of run-time\n"
+       printf(_("  -N MAX-CONNECT  maximum number of allowed connections\n"));
+       printf(_("  -o OPTIONS      pass \"OPTIONS\" to each server process\n"));
+       printf(_("  -p PORT         port number to listen on\n"));
+       printf(_("  -S              silent mode (start in background without logging output)\n"));
+       printf(_("  --help          show this help, then exit\n"));
+       printf(_("  --version       output version information, then exit\n"));
+
+       printf(_("\nDeveloper options:\n"));
+       printf(_("  -n              do not reinitialize shared memory after abnormal exit\n"));
+       printf(_("  -s              send SIGSTOP to all backend servers if one dies\n"));
+
+       printf(_("\nPlease read the documentation for the complete list of run-time\n"
                                   "configuration settings and how to set them on the command line or in\n"
                                   "the configuration file.\n\n"
                                   "Report bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
+
+/*
+ * Main idle loop of postmaster
+ */
 static int
 ServerLoop(void)
 {
        fd_set          readmask;
        int                     nSockets;
-       struct timeval now,
+       time_t          now,
+                               last_touch_time;
+       struct timeval earlier,
                                later;
        struct timezone tz;
-       int                     i;
 
-       gettimeofday(&now, &tz);
+       gettimeofday(&earlier, &tz);
+       last_touch_time = time(NULL);
 
        nSockets = initMasks(&readmask);
 
@@ -1053,140 +1124,136 @@ ServerLoop(void)
                Port       *port;
                fd_set          rmask;
                struct timeval timeout;
+               int                     selres;
+               int                     i;
 
                /*
-                * The timeout for the select() below is normally set on the basis
-                * of the time to the next checkpoint.  However, if for some
-                * reason we don't have a next-checkpoint time, time out after 60
-                * seconds. This keeps checkpoint scheduling from locking up when
-                * we get new connection requests infrequently (since we are
-                * likely to detect checkpoint completion just after enabling
-                * signals below, after we've already made the decision about how
-                * long to wait this time).
+                * Wait for something to happen.
+                *
+                * We wait at most one minute, to ensure that the other background
+                * tasks handled below get done even when no requests are
+                * arriving.
                 */
+               memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
+
                timeout.tv_sec = 60;
                timeout.tv_usec = 0;
 
-               if (CheckPointPID == 0 && checkpointed &&
-                       StartupPID == 0 && Shutdown == NoShutdown &&
-                       !FatalError && random_seed != 0)
-               {
-                       time_t          now = time(NULL);
+               PG_SETMASK(&UnBlockSig);
+
+               selres = select(nSockets, &rmask, NULL, NULL, &timeout);
+
+               /*
+                * Block all signals until we wait again.  (This makes it safe for
+                * our signal handlers to do nontrivial work.)
+                */
+               PG_SETMASK(&BlockSig);
 
-                       if (CheckPointTimeout + checkpointed > now)
+               if (selres < 0)
+               {
+                       if (errno != EINTR && errno != EWOULDBLOCK)
                        {
-                               /*
-                                * Not time for checkpoint yet, so set select timeout
-                                */
-                               timeout.tv_sec = CheckPointTimeout + checkpointed - now;
+                               ereport(LOG,
+                                               (errcode_for_socket_access(),
+                                                errmsg("select() failed in postmaster: %m")));
+                               return STATUS_ERROR;
                        }
-                       else
+               }
+
+               /*
+                * New connection pending on any of our sockets? If so, fork a
+                * child process to deal with it.
+                */
+               if (selres > 0)
+               {
+                       /*
+                        * Select a random seed at the time of first receiving a
+                        * request.
+                        */
+                       while (random_seed == 0)
                        {
-                               /* Time to make the checkpoint... */
-                               CheckPointPID = CheckPointDataBase();
+                               gettimeofday(&later, &tz);
 
                                /*
-                                * if fork failed, schedule another try at 0.1 normal
-                                * delay
+                                * We are not sure how much precision is in tv_usec, so we
+                                * swap the high and low 16 bits of 'later' and XOR them with
+                                * 'earlier'. On the off chance that the result is 0, we
+                                * loop until it isn't.
                                 */
-                               if (CheckPointPID == 0)
+                               random_seed = earlier.tv_usec ^
+                                       ((later.tv_usec << 16) |
+                                        ((later.tv_usec >> 16) & 0xffff));
+                       }
+
+                       for (i = 0; i < MAXLISTEN; i++)
+                       {
+                               if (ListenSocket[i] == -1)
+                                       break;
+                               if (FD_ISSET(ListenSocket[i], &rmask))
                                {
-                                       timeout.tv_sec = CheckPointTimeout / 10;
-                                       checkpointed = now + timeout.tv_sec - CheckPointTimeout;
+                                       port = ConnCreate(ListenSocket[i]);
+                                       if (port)
+                                       {
+                                               BackendStartup(port);
+
+                                               /*
+                                                * We no longer need the open socket or port
+                                                * structure in this process
+                                                */
+                                               StreamClose(port->sock);
+                                               ConnFree(port);
+                                       }
                                }
                        }
                }
 
+               /* If we have lost the system logger, try to start a new one */
+               if (SysLoggerPID == 0 && Redirect_stderr)
+                       SysLoggerPID = SysLogger_Start();
+
                /*
-                * If no background writer process is running and we should
-                * do background writing, start one. It doesn't matter if
-                * this fails, we'll just try again later.
+                * If no background writer process is running, and we are not in a
+                * state that prevents it, start one.  It doesn't matter if this
+                * fails, we'll just try again later.
                 */
-               if (BgWriterPID == 0 && BgWriterPercent > 0 &&
-                       StartupPID == 0 && Shutdown == NoShutdown &&
-                       !FatalError && random_seed != 0)
+               if (BgWriterPID == 0 && StartupPID == 0 && !FatalError)
                {
                        BgWriterPID = StartBackgroundWriter();
+                       /* If shutdown is pending, set it going */
+                       if (Shutdown > NoShutdown && BgWriterPID != 0)
+                               kill(BgWriterPID, SIGUSR2);
                }
 
-               /*
-                * Wait for something to happen.
-                */
-               memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
-
-               PG_SETMASK(&UnBlockSig);
-
-               if (select(nSockets, &rmask, NULL, NULL, &timeout) < 0)
-               {
-                       PG_SETMASK(&BlockSig);
-                       if (errno == EINTR || errno == EWOULDBLOCK)
-                               continue;
-                       ereport(LOG,
-                                       (errcode_for_socket_access(),
-                                        errmsg("select() failed in postmaster: %m")));
-                       return STATUS_ERROR;
-               }
-
-               /*
-                * Block all signals until we wait again.  (This makes it safe for
-                * our signal handlers to do nontrivial work.)
-                */
-               PG_SETMASK(&BlockSig);
-
-               /*
-                * Select a random seed at the time of first receiving a request.
-                */
-               while (random_seed == 0)
-               {
-                       gettimeofday(&later, &tz);
+               /* If we have lost the archiver, try to start a new one */
+               if (XLogArchivingActive() && PgArchPID == 0 &&
+                       StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                       PgArchPID = pgarch_start();
 
-                       /*
-                        * We are not sure how much precision is in tv_usec, so we
-                        * swap the nibbles of 'later' and XOR them with 'now'. On the
-                        * off chance that the result is 0, we loop until it isn't.
-                        */
-                       random_seed = now.tv_usec ^
-                               ((later.tv_usec << 16) |
-                                ((later.tv_usec >> 16) & 0xffff));
-               }
+               /* If we have lost the stats collector, try to start a new one */
+               if (PgStatPID == 0 &&
+                       StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                       PgStatPID = pgstat_start();
 
                /*
-                * New connection pending on any of our sockets? If so, fork a
-                * child process to deal with it.
+                * Touch the socket and lock file at least every ten minutes, to
+                * ensure that they are not removed by overzealous /tmp-cleaning
+                * tasks.
                 */
-               for (i = 0; i < MAXLISTEN; i++)
+               now = time(NULL);
+               if (now - last_touch_time >= 10 * 60)
                {
-                       if (ListenSocket[i] == -1)
-                               break;
-                       if (FD_ISSET(ListenSocket[i], &rmask))
-                       {
-                               port = ConnCreate(ListenSocket[i]);
-                               if (port)
-                               {
-                                       BackendStartup(port);
-
-                                       /*
-                                        * We no longer need the open socket or port structure
-                                        * in this process
-                                        */
-                                       StreamClose(port->sock);
-                                       ConnFree(port);
-                               }
-                       }
+                       TouchSocketFile();
+                       TouchSocketLockFile();
+                       last_touch_time = now;
                }
-
-               /* If we have lost the stats collector, try to start a new one */
-               if (!pgstat_is_running)
-                       pgstat_start();
        }
 }
 
 
 /*
- * Initialise the masks for select() for the ports
- * we are listening on.  Return the number of sockets to listen on.
+ * Initialise the masks for select() for the ports we are listening on.
+ * Return the number of sockets to listen on.
  */
-
 static int
 initMasks(fd_set *rmask)
 {
@@ -1342,7 +1409,7 @@ ProcessStartupPacket(Port *port, bool SSLdone)
         * Now fetch parameters out of startup packet and save them into the
         * Port structure.      All data structures attached to the Port struct
         * must be allocated in TopMemoryContext so that they won't disappear
-        * when we pass them to PostgresMain (see BackendRun).  We need not
+        * when we pass them to PostgresMain (see BackendRun).  We need not
         * worry about leaking this storage on failure, since we aren't in the
         * postmaster process anymore.
         */
@@ -1519,28 +1586,17 @@ processCancelRequest(Port *port, void *pkt)
 #ifndef EXEC_BACKEND
        Dlelem     *curr;
 #else
-       int i;
+       int                     i;
 #endif
 
        backendPID = (int) ntohl(canc->backendPID);
        cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
 
-       if (backendPID == CheckPointPID)
-       {
-               ereport(DEBUG2,
-                               (errmsg_internal("ignoring cancel request for checkpoint process %d",
-                                                                backendPID)));
-               return;
-       }
-       else if (backendPID == BgWriterPID)
-       {
-               ereport(DEBUG2,
-                               (errmsg_internal("ignoring cancel request for bgwriter process %d",
-                                                                backendPID)));
-               return;
-       }
-
-       /* See if we have a matching backend */
+       /*
+        * See if we have a matching backend.  In the EXEC_BACKEND case, we
+        * can no longer access the postmaster's own backend list, and must
+        * rely on the duplicate array in shared memory.
+        */
 #ifndef EXEC_BACKEND
        for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
        {
@@ -1548,7 +1604,7 @@ processCancelRequest(Port *port, void *pkt)
 #else
        for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
        {
-               bp = (Backend*) &ShmemBackendArray[i];
+               bp = (Backend *) &ShmemBackendArray[i];
 #endif
                if (bp->pid == backendPID)
                {
@@ -1663,9 +1719,12 @@ ConnFree(Port *conn)
  * This is called during child process startup to release file descriptors
  * that are not needed by that child process.  The postmaster still has
  * them open, of course.
+ *
+ * Note: we pass am_syslogger as a boolean because we don't want to set
+ * the global variable yet when this is called.
  */
 void
-ClosePostmasterPorts(bool pgstat_too)
+ClosePostmasterPorts(bool am_syslogger)
 {
        int                     i;
 
@@ -1679,9 +1738,19 @@ ClosePostmasterPorts(bool pgstat_too)
                }
        }
 
-       /* Close pgstat control sockets, unless we're starting pgstat itself */
-       if (pgstat_too)
-               pgstat_close_sockets();
+       /* If using syslogger, close the read side of the pipe */
+       if (!am_syslogger)
+       {
+#ifndef WIN32
+               if (syslogPipe[0] >= 0)
+                       close(syslogPipe[0]);
+               syslogPipe[0] = -1;
+#else
+               if (syslogPipe[0])
+                       CloseHandle(syslogPipe[0]);
+               syslogPipe[0] = 0;
+#endif
+       }
 }
 
 
@@ -1718,19 +1787,23 @@ SIGHUP_handler(SIGNAL_ARGS)
                ereport(LOG,
                         (errmsg("received SIGHUP, reloading configuration files")));
                ProcessConfigFile(PGC_SIGHUP);
-#ifdef EXEC_BACKEND
-               write_nondefault_variables(PGC_SIGHUP);
-#endif
                SignalChildren(SIGHUP);
+               if (BgWriterPID != 0)
+                       kill(BgWriterPID, SIGHUP);
+               if (PgArchPID != 0)
+                       kill(PgArchPID, SIGHUP);
+               if (SysLoggerPID != 0)
+                       kill(SysLoggerPID, SIGHUP);
+               /* PgStatPID does not currently need SIGHUP */
+
+               /* Reload authentication config files too */
                load_hba();
                load_ident();
 
-               /*
-                * Tell the background writer to terminate so that we
-                * will start a new one with a possibly changed config
-                */
-               if (BgWriterPID != 0)
-                       kill(BgWriterPID, SIGTERM);
+#ifdef EXEC_BACKEND
+               /* Update the starting-point file for future children */
+               write_nondefault_variables(PGC_SIGHUP);
+#endif
        }
 
        PG_SETMASK(&UnBlockSig);
@@ -1739,7 +1812,6 @@ SIGHUP_handler(SIGNAL_ARGS)
 }
 
 
-
 /*
  * pmdie -- signal handler for processing various postmaster signals.
  */
@@ -1761,7 +1833,7 @@ pmdie(SIGNAL_ARGS)
                        /*
                         * Smart Shutdown:
                         *
-                        * Wait for children to end their work and ShutdownDataBase.
+                        * Wait for children to end their work, then shut down.
                         */
                        if (Shutdown >= SmartShutdown)
                                break;
@@ -1769,27 +1841,26 @@ pmdie(SIGNAL_ARGS)
                        ereport(LOG,
                                        (errmsg("received smart shutdown request")));
 
-                       /* Must tell bgwriter to quit, or it never will... */
-                       if (BgWriterPID != 0)
-                               kill(BgWriterPID, SIGTERM);
-
-                       if (DLGetHead(BackendList)) /* let reaper() handle this */
-                               break;
+                       if (DLGetHead(BackendList))
+                               break;                  /* let reaper() handle this */
 
                        /*
-                        * No children left. Shutdown data base system.
+                        * No children left. Begin shutdown of data base system.
                         */
-                       if (StartupPID > 0 || FatalError)       /* let reaper() handle
-                                                                                                * this */
-                               break;
-                       if (ShutdownPID > 0)
-                       {
-                               elog(PANIC, "shutdown process %d already running",
-                                        (int) ShutdownPID);
-                               abort();
-                       }
-
-                       ShutdownPID = ShutdownDataBase();
+                       if (StartupPID != 0 || FatalError)
+                               break;                  /* let reaper() handle this */
+                       /* Start the bgwriter if not running */
+                       if (BgWriterPID == 0)
+                               BgWriterPID = StartBackgroundWriter();
+                       /* And tell it to shut down */
+                       if (BgWriterPID != 0)
+                               kill(BgWriterPID, SIGUSR2);
+                       /* Tell pgarch to shut down too; nothing left for it to do */
+                       if (PgArchPID != 0)
+                               kill(PgArchPID, SIGQUIT);
+                       /* Tell pgstat to shut down too; nothing left for it to do */
+                       if (PgStatPID != 0)
+                               kill(PgStatPID, SIGQUIT);
                        break;
 
                case SIGINT:
@@ -1798,7 +1869,7 @@ pmdie(SIGNAL_ARGS)
                         * Fast Shutdown:
                         *
                         * Abort all children with SIGTERM (rollback active transactions
-                        * and exit) and ShutdownDataBase when they are gone.
+                        * and exit) and shut down when they are gone.
                         */
                        if (Shutdown >= FastShutdown)
                                break;
@@ -1819,17 +1890,25 @@ pmdie(SIGNAL_ARGS)
                        }
 
                        /*
-                        * No children left. Shutdown data base system.
+                        * No children left. Begin shutdown of data base system.
                         *
-                        * Unlike the previous case, it is not an error for the shutdown
-                        * process to be running already (we could get SIGTERM followed
-                        * shortly later by SIGINT).
+                        * Note: if we previously got SIGTERM then we may send SIGUSR2 to
+                        * the bgwriter a second time here.  This should be harmless.
                         */
-                       if (StartupPID > 0 || FatalError)       /* let reaper() handle
-                                                                                                * this */
-                               break;
-                       if (ShutdownPID == 0)
-                               ShutdownPID = ShutdownDataBase();
+                       if (StartupPID != 0 || FatalError)
+                               break;                  /* let reaper() handle this */
+                       /* Start the bgwriter if not running */
+                       if (BgWriterPID == 0)
+                               BgWriterPID = StartBackgroundWriter();
+                       /* And tell it to shut down */
+                       if (BgWriterPID != 0)
+                               kill(BgWriterPID, SIGUSR2);
+                       /* Tell pgarch to shut down too; nothing left for it to do */
+                       if (PgArchPID != 0)
+                               kill(PgArchPID, SIGQUIT);
+                       /* Tell pgstat to shut down too; nothing left for it to do */
+                       if (PgStatPID != 0)
+                               kill(PgStatPID, SIGQUIT);
                        break;
 
                case SIGQUIT:
@@ -1838,14 +1917,18 @@ pmdie(SIGNAL_ARGS)
                         * Immediate Shutdown:
                         *
                         * abort all children with SIGQUIT and exit without attempt to
-                        * properly shutdown data base system.
+                        * properly shut down data base system.
                         */
                        ereport(LOG,
                                        (errmsg("received immediate shutdown request")));
-                       if (ShutdownPID > 0)
-                               kill(ShutdownPID, SIGQUIT);
-                       if (StartupPID > 0)
+                       if (StartupPID != 0)
                                kill(StartupPID, SIGQUIT);
+                       if (BgWriterPID != 0)
+                               kill(BgWriterPID, SIGQUIT);
+                       if (PgArchPID != 0)
+                               kill(PgArchPID, SIGQUIT);
+                       if (PgStatPID != 0)
+                               kill(PgStatPID, SIGQUIT);
                        if (DLGetHead(BackendList))
                                SignalChildren(SIGQUIT);
                        ExitPostmaster(0);
@@ -1867,6 +1950,7 @@ reaper(SIGNAL_ARGS)
 
 #ifdef HAVE_WAITPID
        int                     status;                 /* backend exit status */
+
 #else
 #ifndef WIN32
        union wait      status;                 /* backend exit status */
@@ -1892,102 +1976,160 @@ reaper(SIGNAL_ARGS)
        while ((pid = win32_waitpid(&exitstatus)) > 0)
        {
                /*
-                * We need to do this here, and not in CleanupProc, since this
+                * We need to do this here, and not in CleanupBackend, since this
                 * is to be called on all children when we are done with them.
                 * Could move to LogChildExit, but that seems like asking for
                 * future trouble...
                 */
                win32_RemoveChild(pid);
-#endif
-#endif
-
-               /*
-                * Check if this child was the statistics collector. If so, try to
-                * start a new one.  (If fail, we'll try again in future cycles of
-                * the main loop.)
-                */
-               if (pgstat_ispgstat(pid))
-               {
-                       LogChildExit(LOG, gettext("statistics collector process"),
-                                                pid, exitstatus);
-                       pgstat_start();
-                       continue;
-               }
+#endif   /* WIN32 */
+#endif   /* HAVE_WAITPID */
 
                /*
-                * Check if this child was a shutdown or startup process.
+                * Check if this child was a startup process.
                 */
-               if (ShutdownPID > 0 && pid == ShutdownPID)
-               {
-                       if (exitstatus != 0)
-                       {
-                               LogChildExit(LOG, gettext("shutdown process"),
-                                                        pid, exitstatus);
-                               ExitPostmaster(1);
-                       }
-                       /* Normal postmaster exit is here */
-                       ExitPostmaster(0);
-               }
-
-               if (StartupPID > 0 && pid == StartupPID)
+               if (StartupPID != 0 && pid == StartupPID)
                {
+                       StartupPID = 0;
                        if (exitstatus != 0)
                        {
-                               LogChildExit(LOG, gettext("startup process"),
+                               LogChildExit(LOG, _("startup process"),
                                                         pid, exitstatus);
                                ereport(LOG,
                                                (errmsg("aborting startup due to startup process failure")));
                                ExitPostmaster(1);
                        }
-                       StartupPID = 0;
 
                        /*
-                        * Startup succeeded - remember its ID and RedoRecPtr.
-                        *
-                        * NB: this MUST happen before we fork a checkpoint or shutdown
-                        * subprocess, else they will have wrong local ThisStartUpId.
+                        * Startup succeeded - we are done with system startup or
+                        * recovery.
                         */
-                       SetThisStartUpID();
+                       FatalError = false;
 
-                       FatalError = false; /* done with recovery */
+                       /*
+                        * Load the flat user/group files into postmaster's caches.
+                        * The startup process has recomputed these from the database
+                        * contents, so we wait till it finishes before loading them.
+                        */
+                       load_user();
+                       load_group();
 
                        /*
-                        * Arrange for first checkpoint to occur after standard delay.
+                        * Crank up the background writer.      It doesn't matter if this
+                        * fails, we'll just try again later.
                         */
-                       CheckPointPID = 0;
-                       checkpointed = time(NULL);
+                       Assert(BgWriterPID == 0);
+                       BgWriterPID = StartBackgroundWriter();
 
                        /*
                         * Go to shutdown mode if a shutdown request was pending.
+                        * Otherwise, try to start the archiver and stats collector
+                        * too.
                         */
-                       if (Shutdown > NoShutdown)
+                       if (Shutdown > NoShutdown && BgWriterPID != 0)
+                               kill(BgWriterPID, SIGUSR2);
+                       else if (Shutdown == NoShutdown)
                        {
-                               if (ShutdownPID > 0)
-                               {
-                                       elog(PANIC, "startup process %d died while shutdown process %d already running",
-                                                pid, (int) ShutdownPID);
-                                       abort();
-                               }
-                               ShutdownPID = ShutdownDataBase();
+                               if (XLogArchivingActive() && PgArchPID == 0)
+                                       PgArchPID = pgarch_start();
+                               if (PgStatPID == 0)
+                                       PgStatPID = pgstat_start();
                        }
 
-                       goto reaper_done;
+                       continue;
+               }
+
+               /*
+                * Was it the bgwriter?
+                */
+               if (BgWriterPID != 0 && pid == BgWriterPID)
+               {
+                       BgWriterPID = 0;
+                       if (exitstatus == 0 && Shutdown > NoShutdown &&
+                               !FatalError && !DLGetHead(BackendList))
+                       {
+                               /*
+                                * Normal postmaster exit is here: we've seen normal exit
+                                * of the bgwriter after it's been told to shut down. We
+                                * expect that it wrote a shutdown checkpoint.  (If for
+                                * some reason it didn't, recovery will occur on next
+                                * postmaster start.)
+                                *
+                                * Note: we do not wait around for exit of the archiver or
+                                * stats processes.  They've been sent SIGQUIT by this
+                                * point, and in any case contain logic to commit
+                                * hara-kiri if they notice the postmaster is gone.
+                                */
+                               ExitPostmaster(0);
+                       }
+
+                       /*
+                        * Any unexpected exit of the bgwriter is treated as a crash.
+                        */
+                       HandleChildCrash(pid, exitstatus,
+                                                        _("background writer process"));
+                       continue;
+               }
+
+               /*
+                * Was it the archiver?  If so, just try to start a new one; no
+                * need to force reset of the rest of the system.  (If fail, we'll
+                * try again in future cycles of the main loop.)
+                */
+               if (PgArchPID != 0 && pid == PgArchPID)
+               {
+                       PgArchPID = 0;
+                       if (exitstatus != 0)
+                               LogChildExit(LOG, _("archiver process"),
+                                                        pid, exitstatus);
+                       if (XLogArchivingActive() &&
+                               StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                               PgArchPID = pgarch_start();
+                       continue;
                }
 
                /*
-                * Else do standard child cleanup.
+                * Was it the statistics collector?  If so, just try to start a
+                * new one; no need to force reset of the rest of the system.  (If
+                * fail, we'll try again in future cycles of the main loop.)
                 */
-               CleanupProc(pid, exitstatus);
+               if (PgStatPID != 0 && pid == PgStatPID)
+               {
+                       PgStatPID = 0;
+                       if (exitstatus != 0)
+                               LogChildExit(LOG, _("statistics collector process"),
+                                                        pid, exitstatus);
+                       if (StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                               PgStatPID = pgstat_start();
+                       continue;
+               }
+
+               /* Was it the system logger? try to start a new one */
+               if (SysLoggerPID != 0 && pid == SysLoggerPID)
+               {
+                       SysLoggerPID = 0;
+                       /* for safety's sake, launch new logger *first* */
+                       SysLoggerPID = SysLogger_Start();
+                       if (exitstatus != 0)
+                               LogChildExit(LOG, _("system logger process"),
+                                                        pid, exitstatus);
+                       continue;
+               }
 
+               /*
+                * Else do standard backend child cleanup.
+                */
+               CleanupBackend(pid, exitstatus);
        }                                                       /* loop over pending child-death reports */
 
        if (FatalError)
        {
                /*
-                * Wait for all children exit, then reset shmem and
-                * StartupDataBase.
+                * Wait for all important children to exit, then reset shmem and
+                * StartupDataBase.  (We can ignore the archiver and stats
+                * processes here since they are not connected to shmem.)
                 */
-               if (DLGetHead(BackendList) || StartupPID > 0 || ShutdownPID > 0)
+               if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
                        goto reaper_done;
                ereport(LOG,
                        (errmsg("all server processes terminated; reinitializing")));
@@ -2002,11 +2144,20 @@ reaper(SIGNAL_ARGS)
 
        if (Shutdown > NoShutdown)
        {
-               if (DLGetHead(BackendList))
-                       goto reaper_done;
-               if (StartupPID > 0 || ShutdownPID > 0)
+               if (DLGetHead(BackendList) || StartupPID != 0)
                        goto reaper_done;
-               ShutdownPID = ShutdownDataBase();
+               /* Start the bgwriter if not running */
+               if (BgWriterPID == 0)
+                       BgWriterPID = StartBackgroundWriter();
+               /* And tell it to shut down */
+               if (BgWriterPID != 0)
+                       kill(BgWriterPID, SIGUSR2);
+               /* Tell pgarch to shut down too; nothing left for it to do */
+               if (PgArchPID != 0)
+                       kill(PgArchPID, SIGQUIT);
+               /* Tell pgstat to shut down too; nothing left for it to do */
+               if (PgStatPID != 0)
+                       kill(PgStatPID, SIGQUIT);
        }
 
 reaper_done:
@@ -2017,19 +2168,17 @@ reaper_done:
 
 
 /*
- * CleanupProc -- cleanup after terminated backend.
+ * CleanupBackend -- cleanup after terminated backend.
  *
  * Remove all local state associated with backend.
  */
 static void
-CleanupProc(int pid,
-                       int exitstatus)         /* child's exit status. */
+CleanupBackend(int pid,
+                          int exitstatus)      /* child's exit status. */
 {
-       Dlelem     *curr,
-                          *next;
-       Backend    *bp;
+       Dlelem     *curr;
 
-       LogChildExit(DEBUG2, gettext("child process"), pid, exitstatus);
+       LogChildExit(DEBUG2, _("server process"), pid, exitstatus);
 
        /*
         * If a backend dies in an ugly way (i.e. exit status not 0) then we
@@ -2037,63 +2186,77 @@ CleanupProc(int pid,
         * we assume everything is hunky dory and simply remove the backend
         * from the active backend list.
         */
-       if (exitstatus == 0)
+       if (exitstatus != 0)
+       {
+               HandleChildCrash(pid, exitstatus, _("server process"));
+               return;
+       }
+
+       for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
        {
-               curr = DLGetHead(BackendList);
-               while (curr)
+               Backend    *bp = (Backend *) DLE_VAL(curr);
+
+               if (bp->pid == pid)
                {
-                       bp = (Backend *) DLE_VAL(curr);
-                       if (bp->pid == pid)
-                       {
+                       DLRemove(curr);
+                       free(bp);
+                       DLFreeElem(curr);
 #ifdef EXEC_BACKEND
-                               ShmemBackendArrayRemove(bp->pid);
+                       ShmemBackendArrayRemove(pid);
 #endif
-                               DLRemove(curr);
-                               free(bp);
-                               DLFreeElem(curr);
-                               break;
-                       }
-                       curr = DLGetSucc(curr);
-               }
-
-               if (pid == CheckPointPID)
-               {
-                       CheckPointPID = 0;
-                       if (!FatalError)
-                       {
-                               checkpointed = time(NULL);
-                               /* Update RedoRecPtr for future child backends */
-                               GetSavedRedoRecPtr();
-                       }
-               }
-               else if (pid == BgWriterPID)
-                       BgWriterPID = 0;
-               else
+                       /* Tell the collector about backend termination */
                        pgstat_beterm(pid);
-
-               return;
+                       break;
+               }
        }
+}
 
-       /* below here we're dealing with a non-normal exit */
+/*
+ * HandleChildCrash -- cleanup after failed backend or bgwriter.
+ *
+ * The objectives here are to clean up our local state about the child
+ * process, and to signal all other remaining children to quickdie.
+ */
+static void
+HandleChildCrash(int pid, int exitstatus, const char *procname)
+{
+       Dlelem     *curr,
+                          *next;
+       Backend    *bp;
 
-       /* Make log entry unless we did so already */
+       /*
+        * Make log entry unless there was a previous crash (if so, nonzero
+        * exit status is to be expected in SIGQUIT response; don't clutter
+        * log)
+        */
        if (!FatalError)
        {
-               LogChildExit(LOG,
-                                        (pid == CheckPointPID) ? gettext("checkpoint process") :
-                                        (pid == BgWriterPID) ? gettext("bgwriter process") :
-                                        gettext("server process"),
-                                        pid, exitstatus);
+               LogChildExit(LOG, procname, pid, exitstatus);
                ereport(LOG,
                          (errmsg("terminating any other active server processes")));
        }
 
-       curr = DLGetHead(BackendList);
-       while (curr)
+       /* Process regular backends */
+       for (curr = DLGetHead(BackendList); curr; curr = next)
        {
                next = DLGetSucc(curr);
                bp = (Backend *) DLE_VAL(curr);
-               if (bp->pid != pid)
+               if (bp->pid == pid)
+               {
+                       /*
+                        * Found entry for freshly-dead backend, so remove it.
+                        */
+                       DLRemove(curr);
+                       free(bp);
+                       DLFreeElem(curr);
+#ifdef EXEC_BACKEND
+                       ShmemBackendArrayRemove(pid);
+#endif
+                       /* Tell the collector about backend termination */
+                       pgstat_beterm(pid);
+                       /* Keep looping so we can signal remaining backends */
+               }
+               else
                {
                        /*
                         * This backend is still alive.  Unless we did so already,
@@ -2108,43 +2271,49 @@ CleanupProc(int pid,
                        {
                                ereport(DEBUG2,
                                                (errmsg_internal("sending %s to process %d",
-                                                                                (SendStop ? "SIGSTOP" : "SIGQUIT"),
+                                                                         (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                                                                 (int) bp->pid)));
                                kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
                        }
                }
-               else
-               {
-                       /*
-                        * Found entry for freshly-dead backend, so remove it.
-                        */
-#ifdef EXEC_BACKEND
-                       ShmemBackendArrayRemove(bp->pid);
-#endif
-                       DLRemove(curr);
-                       free(bp);
-                       DLFreeElem(curr);
-               }
-               curr = next;
        }
 
-       if (pid == CheckPointPID)
+       /* Take care of the bgwriter too */
+       if (pid == BgWriterPID)
+               BgWriterPID = 0;
+       else if (BgWriterPID != 0 && !FatalError)
        {
-               CheckPointPID = 0;
-               checkpointed = 0;
+               ereport(DEBUG2,
+                               (errmsg_internal("sending %s to process %d",
+                                                                (SendStop ? "SIGSTOP" : "SIGQUIT"),
+                                                                (int) BgWriterPID)));
+               kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
        }
-       else if (pid == BgWriterPID)
+
+       /* Force a power-cycle of the pgarch process too */
+       /* (Shouldn't be necessary, but just for luck) */
+       if (PgArchPID != 0 && !FatalError)
        {
-               BgWriterPID = 0;
+               ereport(DEBUG2,
+                               (errmsg_internal("sending %s to process %d",
+                                                                "SIGQUIT",
+                                                                (int) PgArchPID)));
+               kill(PgArchPID, SIGQUIT);
        }
-       else
+
+       /* Force a power-cycle of the pgstat processes too */
+       /* (Shouldn't be necessary, but just for luck) */
+       if (PgStatPID != 0 && !FatalError)
        {
-               /*
-                * Tell the collector about backend termination
-                */
-               pgstat_beterm(pid);
+               ereport(DEBUG2,
+                               (errmsg_internal("sending %s to process %d",
+                                                                "SIGQUIT",
+                                                                (int) PgStatPID)));
+               kill(PgStatPID, SIGQUIT);
        }
 
+       /* We do NOT restart the syslogger */
+
        FatalError = true;
 }
 
@@ -2184,31 +2353,21 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus)
 }
 
 /*
- * Send a signal to all backend children.
+ * Send a signal to all backend children (but NOT special children)
  */
 static void
 SignalChildren(int signal)
 {
-       Dlelem     *curr,
-                          *next;
-       Backend    *bp;
+       Dlelem     *curr;
 
-       curr = DLGetHead(BackendList);
-       while (curr)
+       for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
        {
-               next = DLGetSucc(curr);
-               bp = (Backend *) DLE_VAL(curr);
-
-               if (bp->pid != MyProcPid)
-               {
-                       ereport(DEBUG2,
-                                       (errmsg_internal("sending signal %d to process %d",
-                                                                        signal,
-                                                                        (int) bp->pid)));
-                       kill(bp->pid, signal);
-               }
+               Backend    *bp = (Backend *) DLE_VAL(curr);
 
-               curr = next;
+               ereport(DEBUG4,
+                               (errmsg_internal("sending signal %d to process %d",
+                                                                signal, (int) bp->pid)));
+               kill(bp->pid, signal);
        }
 }
 
@@ -2247,6 +2406,9 @@ BackendStartup(Port *port)
                return STATUS_ERROR;
        }
 
+       /* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
+       port->canAcceptConnections = canAcceptConnections();
+
        /*
         * Flush stdio channels just before fork, to avoid double-output
         * problems. Ideally we'd use fflush(NULL) here, but there are still a
@@ -2258,6 +2420,12 @@ BackendStartup(Port *port)
        fflush(stdout);
        fflush(stderr);
 
+#ifdef EXEC_BACKEND
+
+       pid = backend_forkexec(port);
+
+#else                                                  /* !EXEC_BACKEND */
+
 #ifdef LINUX_PROFILE
 
        /*
@@ -2275,10 +2443,6 @@ BackendStartup(Port *port)
        beos_before_backend_startup();
 #endif
 
-       port->canAcceptConnections = canAcceptConnections();
-#ifdef EXEC_BACKEND
-       pid = Backend_forkexec(port);
-#else
        pid = fork();
 
        if (pid == 0)                           /* child */
@@ -2295,11 +2459,11 @@ BackendStartup(Port *port)
 
                proc_exit(BackendRun(port));
        }
-#endif
+#endif   /* EXEC_BACKEND */
 
-       /* in parent, error */
        if (pid < 0)
        {
+               /* in parent, fork failed */
                int                     save_errno = errno;
 
 #ifdef __BEOS__
@@ -2314,7 +2478,7 @@ BackendStartup(Port *port)
                return STATUS_ERROR;
        }
 
-       /* in parent, normal */
+       /* in parent, successful fork */
        ereport(DEBUG2,
                        (errmsg_internal("forked new backend, pid=%d socket=%d",
                                                         (int) pid, port->sock)));
@@ -2325,10 +2489,10 @@ BackendStartup(Port *port)
         */
        bn->pid = pid;
        bn->cancel_key = MyCancelKey;
+       DLAddHead(BackendList, DLNewElem(bn));
 #ifdef EXEC_BACKEND
        ShmemBackendArrayAdd(bn);
 #endif
-       DLAddHead(BackendList, DLNewElem(bn));
 
        return STATUS_OK;
 }
@@ -2348,7 +2512,7 @@ report_fork_failure_to_client(Port *port, int errnum)
 
        /* Format the error message packet (always V2 protocol) */
        snprintf(buffer, sizeof(buffer), "E%s%s\n",
-                        gettext("could not fork new process for connection: "),
+                        _("could not fork new process for connection: "),
                         strerror(errnum));
 
        /* Set port to non-blocking.  Don't do send() if this fails */
@@ -2390,27 +2554,33 @@ split_opts(char **argv, int *argcp, char *s)
 
 
 /*
- * BackendInit/Run -- perform authentication [BackendInit], and if successful,
- *              set up the backend's argument list [BackendRun] and invoke
- *              backend main()
+ * BackendRun -- perform authentication, and if successful,
+ *                             set up the backend's argument list and invoke PostgresMain()
  *
  * returns:
  *             Shouldn't return at all.
  *             If PostgresMain() fails, return status.
  */
-static void
-BackendInit(Port *port)
+static int
+BackendRun(Port *port)
 {
        int                     status;
-       struct timeval now;
-       struct timezone tz;
        char            remote_host[NI_MAXHOST];
        char            remote_port[NI_MAXSERV];
        char            remote_ps_data[NI_MAXHOST];
+       char      **av;
+       int                     maxac;
+       int                     ac;
+       char            protobuf[32];
+       int                     i;
 
        IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
 
-       ClientAuthInProgress = true;    /* limit visibility of log messages */
+       /*
+        * Let's clean up ourselves as the postmaster child, and close the
+        * postmaster's listen sockets
+        */
+       ClosePostmasterPorts(false);
 
        /* We don't want the postmaster's proc_exit() handlers */
        on_exit_reset();
@@ -2419,20 +2589,32 @@ BackendInit(Port *port)
         * Signal handlers setting is moved to tcop/postgres...
         */
 
-       /* save start time for end of session reporting */
-       gettimeofday(&(port->session_start),NULL);
-
-       /* set these to empty in case they are needed before we set them up */
-       port->remote_host = "";
-       port->remote_port = "";
-       port->commandTag = "";
-
        /* Save port etc. for ps status */
        MyProcPort = port;
 
        /* Reset MyProcPid to new backend's pid */
        MyProcPid = getpid();
 
+       /*
+        * PreAuthDelay is a debugging aid for investigating problems in the
+        * authentication cycle: it can be set in postgresql.conf to allow
+        * time to attach to the newly-forked backend with a debugger. (See
+        * also the -W backend switch, which we allow clients to pass through
+        * PGOPTIONS, but it is not honored until after authentication.)
+        */
+       if (PreAuthDelay > 0)
+               pg_usleep(PreAuthDelay * 1000000L);
+
+       ClientAuthInProgress = true;    /* limit visibility of log messages */
+
+       /* save start time for end of session reporting */
+       gettimeofday(&(port->session_start), NULL);
+
+       /* set these to empty in case they are needed before we set them up */
+       port->remote_host = "";
+       port->remote_port = "";
+       port->commandTag = "";
+
        /*
         * Initialize libpq and enable reporting of ereport errors to the
         * client. Must do this now because authentication uses libpq to send
@@ -2462,10 +2644,15 @@ BackendInit(Port *port)
                                                remote_port, sizeof(remote_port),
                                   (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV))
        {
-               getnameinfo_all(&port->raddr.addr, port->raddr.salen,
-                                               remote_host, sizeof(remote_host),
-                                               remote_port, sizeof(remote_port),
-                                               NI_NUMERICHOST | NI_NUMERICSERV);
+               int                     ret = getnameinfo_all(&port->raddr.addr, port->raddr.salen,
+                                                                               remote_host, sizeof(remote_host),
+                                                                               remote_port, sizeof(remote_port),
+                                                                               NI_NUMERICHOST | NI_NUMERICSERV);
+
+               if (ret)
+                       ereport(WARNING,
+                                       (errmsg("getnameinfo_all() failed: %s",
+                                                       gai_strerror(ret))));
        }
        snprintf(remote_ps_data, sizeof(remote_ps_data),
                         remote_port[0] == '\0' ? "%s" : "%s(%s)",
@@ -2482,6 +2669,29 @@ BackendInit(Port *port)
        port->remote_host = strdup(remote_host);
        port->remote_port = strdup(remote_port);
 
+       /*
+        * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf
+        * etcetera from the postmaster, and have to load them ourselves.
+        * Build the PostmasterContext (which didn't exist before, in this
+        * process) to contain the data.
+        *
+        * FIXME: [fork/exec] Ugh.      Is there a way around this overhead?
+        */
+#ifdef EXEC_BACKEND
+       Assert(PostmasterContext == NULL);
+       PostmasterContext = AllocSetContextCreate(TopMemoryContext,
+                                                                                         "Postmaster",
+                                                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                                                         ALLOCSET_DEFAULT_MAXSIZE);
+       MemoryContextSwitchTo(PostmasterContext);
+
+       load_hba();
+       load_ident();
+       load_user();
+       load_group();
+#endif
+
        /*
         * Ready to begin client interaction.  We will give up and exit(0)
         * after a time delay, so that a broken client can't hog a connection
@@ -2531,40 +2741,7 @@ BackendInit(Port *port)
         * start a new random sequence in the random() library function.
         */
        random_seed = 0;
-       gettimeofday(&now, &tz);
-       srandom((unsigned int) now.tv_usec);
-}
-
-
-static int
-BackendRun(Port *port)
-{
-       char      **av;
-       int                     maxac;
-       int                     ac;
-       char            debugbuf[32];
-       char            protobuf[32];
-       int                     i;
-
-       /*
-        * Let's clean up ourselves as the postmaster child, and
-        * close the postmaster's other sockets
-        */
-       ClosePostmasterPorts(true);
-
-       /*
-        * PreAuthDelay is a debugging aid for investigating problems in the
-        * authentication cycle: it can be set in postgresql.conf to allow
-        * time to attach to the newly-forked backend with a debugger. (See
-        * also the -W backend switch, which we allow clients to pass through
-        * PGOPTIONS, but it is not honored until after authentication.)
-        */
-       if (PreAuthDelay > 0)
-               pg_usleep(PreAuthDelay*1000000L);
-
-       /* Will exit on failure */
-       BackendInit(port);
-
+       srandom((unsigned int) (MyProcPid ^ port->session_start.tv_usec));
 
        /* ----------------
         * Now, build the argv vector that will be given to PostgresMain.
@@ -2589,18 +2766,10 @@ BackendRun(Port *port)
 
        av[ac++] = "postgres";
 
-       /*
-        * Pass the requested debugging level along to the backend.
-        */
-       if (debug_flag > 0)
-       {
-               snprintf(debugbuf, sizeof(debugbuf), "-d%d", debug_flag);
-               av[ac++] = debugbuf;
-       }
-
        /*
         * Pass any backend switches specified with -o in the postmaster's own
-        * command line.  We assume these are secure.
+        * command line.  We assume these are secure.  (It's OK to mangle
+        * ExtraOptions now, since we're safely inside a subprocess.)
         */
        split_opts(av, &ac, ExtraOptions);
 
@@ -2608,12 +2777,6 @@ BackendRun(Port *port)
        snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
        av[ac++] = protobuf;
 
-#ifdef EXEC_BACKEND
-       /* pass data dir before end of secure switches (-p) */
-       av[ac++] = "-D";
-       av[ac++] = DataDir;
-#endif
-
        /*
         * Tell the backend it is being called from the postmaster, and which
         * database to use.  -p marks the end of secure switches.
@@ -2640,9 +2803,7 @@ BackendRun(Port *port)
         * username isn't lost either; see ProcessStartupPacket().
         */
        MemoryContextSwitchTo(TopMemoryContext);
-#ifndef EXEC_BACKEND
        MemoryContextDelete(PostmasterContext);
-#endif
        PostmasterContext = NULL;
 
        /*
@@ -2650,7 +2811,7 @@ BackendRun(Port *port)
         */
        ereport(DEBUG3,
                        (errmsg_internal("%s child[%d]: starting with (",
-                                                        progname, getpid())));
+                                                        progname, (int)getpid())));
        for (i = 0; i < ac; ++i)
                ereport(DEBUG3,
                                (errmsg_internal("\t%s", av[i])));
@@ -2666,109 +2827,458 @@ BackendRun(Port *port)
 
 #ifdef EXEC_BACKEND
 
+/*
+ * postmaster_forkexec -- fork and exec a postmaster subprocess
+ *
+ * The caller must have set up the argv array already, except for argv[2]
+ * which will be filled with the name of the temp variable file.
+ *
+ * Returns the child process PID, or -1 on fork failure (a suitable error
+ * message has been logged on failure).
+ *
+ * All uses of this routine will dispatch to SubPostmasterMain in the
+ * child process.
+ */
+pid_t
+postmaster_forkexec(int argc, char *argv[])
+{
+       Port            port;
+
+       /* This entry point passes dummy values for the Port variables */
+       memset(&port, 0, sizeof(port));
+       return internal_forkexec(argc, argv, &port);
+}
 
 /*
- * SubPostmasterMain -- prepare the fork/exec'd process to be in an equivalent
- *                     state (for calling BackendRun) as a forked process.
+ * backend_forkexec -- fork/exec off a backend process
  *
- * returns:
- *             Shouldn't return at all.
+ * returns the pid of the fork/exec'd process, or -1 on failure
  */
-void
-SubPostmasterMain(int argc, char* argv[])
+static pid_t
+backend_forkexec(Port *port)
 {
-       unsigned long   backendID;
-       Port                    port;
+       char       *av[4];
+       int                     ac = 0;
 
-       memset((void*)&port, 0, sizeof(Port));
-       Assert(argc == 2);
+       av[ac++] = "postgres";
+       av[ac++] = "-forkbackend";
+       av[ac++] = NULL;                        /* filled in by internal_forkexec */
 
-       /* Do this sooner rather than later... */
-       IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
+       av[ac] = NULL;
+       Assert(ac < lengthof(av));
 
-       /* In EXEC case we will not have inherited these settings */
-       IsPostmasterEnvironment = true;
-       whereToSendOutput = None;
+       return internal_forkexec(ac, av, port);
+}
 
-       /* Setup global context */
-       MemoryContextInit();
-       InitializeGUCOptions();
+#ifndef WIN32
 
-       /* Parse passed-in context */
-       argc = 0;
-       backendID               = (unsigned long)atol(argv[argc++]);
-       DataDir                 = strdup(argv[argc++]);
+/*
+ * internal_forkexec non-win32 implementation
+ *
+ * - writes out backend variables to the parameter file
+ * - fork():s, and then exec():s the child process
+ */
+static pid_t
+internal_forkexec(int argc, char *argv[], Port *port)
+{
+       static unsigned long tmpBackendFileNum = 0;
+       pid_t           pid;
+       char            tmpfilename[MAXPGPATH];
+       BackendParameters param;
+       FILE       *fp;
 
-       /* Read in file-based context */
-       read_nondefault_variables();
-       read_backend_variables(backendID,&port);
+       if (!save_backend_variables(&param, port))
+               return -1;                              /* log made by save_backend_variables */
 
-       /* Remaining initialization */
-       pgstat_init_forkexec_backend();
+       /* Calculate name for temp file */
+       Assert(DataDir);
+       snprintf(tmpfilename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu",
+                        DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
+                        MyProcPid, ++tmpBackendFileNum);
 
-       /* FIXME: [fork/exec] Ugh */
-       load_hba();
-       load_ident();
-       load_user();
-       load_group();
+       /* Open file */
+       fp = AllocateFile(tmpfilename, PG_BINARY_W);
+       if (!fp)
+       {
+               /* As per OpenTemporaryFile... */
+               char            dirname[MAXPGPATH];
 
-       /* Attach process to shared segments */
-       CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+               snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
+               mkdir(dirname, S_IRWXU);
 
-       /* Run backend */
-       proc_exit(BackendRun(&port));
+               fp = AllocateFile(tmpfilename, PG_BINARY_W);
+               if (!fp)
+               {
+                       ereport(LOG,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not create file \"%s\": %m",
+                                                       tmpfilename)));
+                       return -1;
+               }
+       }
+
+       if (fwrite(&param, sizeof(param), 1, fp) != 1)
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not write to file \"%s\": %m", tmpfilename)));
+               FreeFile(fp);
+               return -1;
+       }
+
+       /* Release file */
+       if (FreeFile(fp))
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not write to file \"%s\": %m", tmpfilename)));
+               return -1;
+       }
+
+       /* Make sure caller set up argv properly */
+       Assert(argc >= 3);
+       Assert(argv[argc] == NULL);
+       Assert(strncmp(argv[1], "-fork", 5) == 0);
+       Assert(argv[2] == NULL);
+
+       /* Insert temp file name after -fork argument */
+       argv[2] = tmpfilename;
+
+       /* Fire off execv in child */
+       if ((pid = fork()) == 0)
+       {
+               if (execv(postgres_exec_path, argv) < 0)
+               {
+                       ereport(LOG,
+                                       (errmsg("could not execute server process \"%s\": %m",
+                                                       postgres_exec_path)));
+                       /* We're already in the child process here, can't return */
+                       exit(1);
+               }
+       }
+
+       return pid;                                     /* Parent returns pid, or -1 on fork
+                                                                * failure */
 }
 
+#else /* WIN32 */
 
 /*
- * Backend_forkexec -- fork/exec off a backend process
+ * internal_forkexec win32 implementation
  *
- * returns:
- *             the pid of the fork/exec'd process
+ * - starts backend using CreateProcess(), in suspended state
+ * - writes out backend variables to the parameter file
+ *  - during this, duplicates handles and sockets required for
+ *    inheritance into the new process
+ * - resumes execution of the new process once the backend parameter
+ *   file is complete.
  */
 static pid_t
-Backend_forkexec(Port *port)
+internal_forkexec(int argc, char *argv[], Port *port)
 {
-       pid_t pid;
-       char *av[5];
-       int ac = 0, bufc = 0, i;
-       char buf[2][MAXPGPATH];
+       STARTUPINFO si;
+       PROCESS_INFORMATION pi;
+       int                     i;
+       int                     j;
+       char            cmdLine[MAXPGPATH * 2];
+       HANDLE          childHandleCopy;
+       HANDLE          waiterThread;
+       HANDLE      paramHandle;
+       BackendParameters *param;
+       SECURITY_ATTRIBUTES sa;
+       char        paramHandleStr[32];
+
+       /* Make sure caller set up argv properly */
+       Assert(argc >= 3);
+       Assert(argv[argc] == NULL);
+       Assert(strncmp(argv[1], "-fork", 5) == 0);
+       Assert(argv[2] == NULL);
+
+       /* Set up shared memory for parameter passing */
+       ZeroMemory(&sa,sizeof(sa));
+       sa.nLength = sizeof(sa);
+       sa.bInheritHandle = TRUE;
+       paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
+                                                                       &sa,
+                                                                       PAGE_READWRITE,
+                                                                       0,
+                                                                       sizeof(BackendParameters),
+                                                                       NULL);
+       if (paramHandle == INVALID_HANDLE_VALUE)
+       {
+               elog(LOG, "could not create backend parameter file mapping: error code %d",
+                        (int) GetLastError());
+               return -1;
+       }
 
-       if (!write_backend_variables(port))
-               return -1; /* log made by write_backend_variables */
+       param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
+       if (!param)
+       {
+               elog(LOG, "could not map backend parameter memory: error code %d",
+                        (int) GetLastError());
+               CloseHandle(paramHandle);
+               return -1;
+       }
 
-       av[ac++] = "postgres";
-       av[ac++] = "-forkexec";
+       /* Insert temp file name after -fork argument */
+       sprintf(paramHandleStr, "%lu", (DWORD)paramHandle);
+       argv[2] = paramHandleStr;
+
+       /* Format the cmd line */
+       cmdLine[sizeof(cmdLine) - 1] = '\0';
+       cmdLine[sizeof(cmdLine) - 2] = '\0';
+       snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path);
+       i = 0;
+       while (argv[++i] != NULL)
+       {
+               j = strlen(cmdLine);
+               snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
+       }
+       if (cmdLine[sizeof(cmdLine) - 2] != '\0')
+       {
+               elog(LOG, "subprocess command line too long");
+               return -1;
+       }
+
+       memset(&pi, 0, sizeof(pi));
+       memset(&si, 0, sizeof(si));
+       si.cb = sizeof(si);
+       /*
+        * Create the subprocess in a suspended state. This will be resumed
+        * later, once we have written out the parameter file.
+        */
+       if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED,
+                                          NULL, NULL, &si, &pi))
+       {
+               elog(LOG, "CreateProcess call failed: %m (error code %d)",
+                        (int) GetLastError());
+               return -1;
+       }
 
-       /* Format up context to pass to exec'd process */
-       snprintf(buf[bufc++],MAXPGPATH,"%lu",tmpBackendFileNum);
-       snprintf(buf[bufc++],MAXPGPATH,"\"%s\"",DataDir);
+       if (!save_backend_variables(param, port, pi.hProcess, pi.dwProcessId))
+       {
+               /*
+                * log made by save_backend_variables, but we have to clean
+                * up the mess with the half-started process
+                */
+               if (!TerminateProcess(pi.hProcess, 255))
+                       ereport(ERROR,
+                                       (errmsg_internal("could not terminate unstarted process: error code %d",
+                                                                        (int) GetLastError())));
+               CloseHandle(pi.hProcess);
+               CloseHandle(pi.hThread);
+               return -1;                              /* log made by save_backend_variables */
+       }
 
-       /* Add to the arg list */
-       Assert(bufc <= lengthof(buf));
-       for (i = 0; i < bufc; i++)
-               av[ac++] = buf[i];
+       /* Drop the shared memory that is now inherited to the backend */
+       if (!UnmapViewOfFile(param))
+               elog(LOG, "could not unmap view of backend parameter file: error code %d",
+                        (int) GetLastError());
+       if (!CloseHandle(paramHandle))
+               elog(LOG, "could not close handle to backend parameter file: error code %d",
+                        (int) GetLastError());
 
-       /* FIXME: [fork/exec] ExtraOptions? */
+       /*
+        * Now that the backend variables are written out, we start the
+        * child thread so it can start initializing while we set up
+        * the rest of the parent state.
+        */
+       if (ResumeThread(pi.hThread) == -1)
+       {
+               if (!TerminateProcess(pi.hProcess, 255))
+               {
+                       ereport(ERROR,
+                                       (errmsg_internal("could not terminate unstartable process: error code %d",
+                                                                        (int) GetLastError())));
+                       CloseHandle(pi.hProcess);
+                       CloseHandle(pi.hThread);
+                       return -1;
+               }
+               CloseHandle(pi.hProcess);
+               CloseHandle(pi.hThread);
+               ereport(ERROR,
+                               (errmsg_internal("could not resume thread of unstarted process: error code %d",
+                                                                (int) GetLastError())));
+               return -1;
+       }
 
-       av[ac++] = NULL;
-       Assert(ac <= lengthof(av));
+       if (!IsUnderPostmaster)
+       {
+               /* We are the Postmaster creating a child... */
+               win32_AddChild(pi.dwProcessId, pi.hProcess);
+       }
+
+       /* Set up the thread to handle the SIGCHLD for this process */
+       if (DuplicateHandle(GetCurrentProcess(),
+                                               pi.hProcess,
+                                               GetCurrentProcess(),
+                                               &childHandleCopy,
+                                               0,
+                                               FALSE,
+                                               DUPLICATE_SAME_ACCESS) == 0)
+               ereport(FATAL,
+                               (errmsg_internal("could not duplicate child handle: error code %d",
+                                                                (int) GetLastError())));
+
+       waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
+                                                               (LPVOID) childHandleCopy, 0, NULL);
+       if (!waiterThread)
+               ereport(FATAL,
+                  (errmsg_internal("could not create sigchld waiter thread: error code %d",
+                                                       (int) GetLastError())));
+       CloseHandle(waiterThread);
+
+       if (IsUnderPostmaster)
+               CloseHandle(pi.hProcess);
+       CloseHandle(pi.hThread);
 
+       return pi.dwProcessId;
+}
+
+#endif /* WIN32 */
+
+
+/*
+ * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
+ *                     to what it would be if we'd simply forked on Unix, and then
+ *                     dispatch to the appropriate place.
+ *
+ * The first two command line arguments are expected to be "-forkFOO"
+ * (where FOO indicates which postmaster child we are to become), and
+ * the name of a variables file that we can read to load data that would
+ * have been inherited by fork() on Unix.  Remaining arguments go to the
+ * subprocess FooMain() routine.
+ */
+int
+SubPostmasterMain(int argc, char *argv[])
+{
+       Port            port;
+
+       /* Do this sooner rather than later... */
+       IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
+
+       MyProcPid = getpid();           /* reset MyProcPid */
+
+       /* In EXEC_BACKEND case we will not have inherited these settings */
+       IsPostmasterEnvironment = true;
+       whereToSendOutput = None;
+
+       /* Setup essential subsystems (to ensure elog() behaves sanely) */
+       MemoryContextInit();
+       InitializeGUCOptions();
+
+       /* Read in the variables file */
+       memset(&port, 0, sizeof(Port));
+       read_backend_variables(argv[2], &port);
+
+       /* Check we got appropriate args */
+       if (argc < 3)
+               elog(FATAL, "invalid subpostmaster invocation");
+
+       /*
+        * If appropriate, physically re-attach to shared memory segment.
+        * We want to do this before going any further to ensure that we
+        * can attach at the same address the postmaster used.
+        */
+       if (strcmp(argv[1], "-forkbackend") == 0 ||
+               strcmp(argv[1], "-forkboot") == 0)
+               PGSharedMemoryReAttach();
+
+       /*
+        * Start our win32 signal implementation. This has to be done
+        * after we read the backend variables, because we need to pick
+        * up the signal pipe from the parent process.
+        */
 #ifdef WIN32
-       pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
-       /* Fire off execv in child */
-       if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
+       pgwin32_signal_initialize();
+#endif
+
+       /* In EXEC_BACKEND case we will not have inherited these settings */
+       pqinitmask();
+       PG_SETMASK(&BlockSig);
+
+       /* Read in remaining GUC variables */
+       read_nondefault_variables();
+
+       /* Run backend or appropriate child */
+       if (strcmp(argv[1], "-forkbackend") == 0)
+       {
+               /* BackendRun will close sockets */
+
+               /* Attach process to shared data structures */
+               CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+
+#ifdef USE_SSL
                /*
-                * FIXME: [fork/exec] suggestions for what to do here?
-                *  Probably OK to issue error (unlike pgstat case)
+                *      Need to reinitialize the SSL library in the backend,
+                *      since the context structures contain function pointers
+                *      and cannot be passed through the parameter file.
                 */
-               abort();
+               if (EnableSSL)
+                       secure_initialize();
 #endif
-       return pid; /* Parent returns pid */
+
+               Assert(argc == 3);              /* shouldn't be any more args */
+               proc_exit(BackendRun(&port));
+       }
+       if (strcmp(argv[1], "-forkboot") == 0)
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
+
+               /* Attach process to shared data structures */
+               CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+
+               BootstrapMain(argc - 2, argv + 2);
+               proc_exit(0);
+       }
+       if (strcmp(argv[1], "-forkarch") == 0)
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
+
+               /* Do not want to attach to shared memory */
+
+               PgArchiverMain(argc, argv);
+               proc_exit(0);
+       }
+       if (strcmp(argv[1], "-forkbuf") == 0)
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
+
+               /* Do not want to attach to shared memory */
+
+               PgstatBufferMain(argc, argv);
+               proc_exit(0);
+       }
+       if (strcmp(argv[1], "-forkcol") == 0)
+       {
+               /*
+                * Do NOT close postmaster sockets here, because we are forking
+                * from pgstat buffer process, which already did it.
+                */
+
+               /* Do not want to attach to shared memory */
+
+               PgstatCollectorMain(argc, argv);
+               proc_exit(0);
+       }
+       if (strcmp(argv[1], "-forklog") == 0)
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(true);
+
+               /* Do not want to attach to shared memory */
+
+               SysLoggerMain(argc, argv);
+               proc_exit(0);
+       }
+
+       return 1;                                       /* shouldn't get here */
 }
 
-#endif
+#endif   /* EXEC_BACKEND */
 
 
 /*
@@ -2787,8 +3297,6 @@ ExitPostmaster(int status)
         *
         * MUST         -- vadim 05-10-1999
         */
-       /* Should I use true instead? */
-       ClosePostmasterPorts(false);
 
        proc_exit(status);
 }
@@ -2803,45 +3311,6 @@ sigusr1_handler(SIGNAL_ARGS)
 
        PG_SETMASK(&BlockSig);
 
-       if (CheckPostmasterSignal(PMSIGNAL_DO_CHECKPOINT))
-       {
-               if (CheckPointWarning != 0)
-               {
-                       /*
-                        * This only times checkpoints forced by running out of
-                        * segment files.  Other checkpoints could reduce the
-                        * frequency of forced checkpoints.
-                        */
-                       time_t          now = time(NULL);
-
-                       if (LastSignalledCheckpoint != 0)
-                       {
-                               int                     elapsed_secs = now - LastSignalledCheckpoint;
-
-                               if (elapsed_secs < CheckPointWarning)
-                                       ereport(LOG,
-                                                       (errmsg("checkpoints are occurring too frequently (%d seconds apart)",
-                                                                       elapsed_secs),
-                                       errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
-                       }
-                       LastSignalledCheckpoint = now;
-               }
-
-               /*
-                * Request to schedule a checkpoint
-                *
-                * Ignore request if checkpoint is already running or checkpointing
-                * is currently disabled
-                */
-               if (CheckPointPID == 0 && checkpointed &&
-                       StartupPID == 0 && Shutdown == NoShutdown &&
-                       !FatalError && random_seed != 0)
-               {
-                       CheckPointPID = CheckPointDataBase();
-                       /* note: if fork fails, CheckPointPID stays 0; nothing happens */
-               }
-       }
-
        if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE))
        {
                /*
@@ -2854,11 +3323,24 @@ sigusr1_handler(SIGNAL_ARGS)
        if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN))
        {
                /*
-                * Send SIGUSR2 to all children (triggers AsyncNotifyHandler). See
-                * storage/ipc/sinvaladt.c for the use of this.
+                * Send SIGUSR1 to all children (triggers
+                * CatchupInterruptHandler). See storage/ipc/sinval[adt].c for the
+                * use of this.
                 */
-               if (Shutdown == NoShutdown)
-                       SignalChildren(SIGUSR2);
+               if (Shutdown <= SmartShutdown)
+                       SignalChildren(SIGUSR1);
+       }
+
+       if (PgArchPID != 0 && Shutdown == NoShutdown)
+       {
+               if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER))
+               {
+                       /*
+                        * Send SIGUSR1 to archiver process, to wake it up and begin
+                        * archiving next transaction log file.
+                        */
+                       kill(PgArchPID, SIGUSR1);
+               }
        }
 
        PG_SETMASK(&UnBlockSig);
@@ -2871,9 +3353,10 @@ sigusr1_handler(SIGNAL_ARGS)
  * Dummy signal handler
  *
  * We use this for signals that we don't actually use in the postmaster,
- * but we do use in backends.  If we SIG_IGN such signals in the postmaster,
- * then a newly started backend might drop a signal that arrives before it's
- * able to reconfigure its signal processing.  (See notes in postgres.c.)
+ * but we do use in backends.  If we were to SIG_IGN such signals in the
+ * postmaster, then a newly started backend might drop a signal that arrives
+ * before it's able to reconfigure its signal processing.  (See notes in
+ * tcop/postgres.c.)
  */
 static void
 dummy_handler(SIGNAL_ARGS)
@@ -2951,103 +3434,74 @@ PostmasterRandom(void)
 }
 
 /*
- * Count up number of child processes.
+ * Count up number of child processes (regular backends only)
  */
 static int
 CountChildren(void)
 {
        Dlelem     *curr;
-       Backend    *bp;
        int                     cnt = 0;
 
        for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
-       {
-               bp = (Backend *) DLE_VAL(curr);
-               if (bp->pid != MyProcPid)
-                       cnt++;
-       }
-       /* Checkpoint and bgwriter will be in the list, discount them */
-       if (CheckPointPID != 0)
-               cnt--;
-       if (BgWriterPID != 0)
-               cnt--;
+               cnt++;
        return cnt;
 }
 
+
 /*
- * Fire off a subprocess for startup/shutdown/checkpoint/bgwriter.
+ * StartChildProcess -- start a non-backend child process for the postmaster
  *
- * Return value of SSDataBase is subprocess' PID, or 0 if failed to start subprocess
- * (0 is returned only for checkpoint/bgwriter cases).
+ * xlog determines what kind of child will be started. All child types
+ * initially go to BootstrapMain, which will handle common setup.
  *
- * note: in the EXEC_BACKEND case, we delay the fork until argument list has been
- *     established
+ * Return value of StartChildProcess is subprocess' PID, or 0 if failed
+ * to start subprocess.
  */
-NON_EXEC_STATIC void
-SSDataBaseInit(int xlop)
-{
-       const char *statmsg;
-
-       IsUnderPostmaster = true;               /* we are a postmaster subprocess
-                                                                        * now */
-
-#ifdef EXEC_BACKEND
-       /* In EXEC case we will not have inherited these settings */
-       IsPostmasterEnvironment = true;
-       whereToSendOutput = None;
-#endif
-
-       MyProcPid = getpid();           /* reset MyProcPid */
-
-       /* Lose the postmaster's on-exit routines and port connections */
-       on_exit_reset();
-
-       /*
-        * Identify myself via ps
-        */
-       switch (xlop)
-       {
-               case BS_XLOG_STARTUP:
-                       statmsg = "startup subprocess";
-                       break;
-               case BS_XLOG_CHECKPOINT:
-                       statmsg = "checkpoint subprocess";
-                       break;
-               case BS_XLOG_BGWRITER:
-                       statmsg = "bgwriter subprocess";
-                       break;
-               case BS_XLOG_SHUTDOWN:
-                       statmsg = "shutdown subprocess";
-                       break;
-               default:
-                       statmsg = "??? subprocess";
-                       break;
-       }
-       init_ps_display(statmsg, "", "");
-       set_ps_display("");
-}
-
-
 static pid_t
-SSDataBase(int xlop)
+StartChildProcess(int xlop)
 {
        pid_t           pid;
-       Backend    *bn;
-#ifndef EXEC_BACKEND
+       char       *av[10];
+       int                     ac = 0;
+       char            xlbuf[32];
+
 #ifdef LINUX_PROFILE
        struct itimerval prof_itimer;
 #endif
-#else
-       char            idbuf[32];
-       char            ddirbuf[MAXPGPATH];
+
+       /*
+        * Set up command-line arguments for subprocess
+        */
+       av[ac++] = "postgres";
+
+#ifdef EXEC_BACKEND
+       av[ac++] = "-forkboot";
+       av[ac++] = NULL;                        /* filled in by postmaster_forkexec */
 #endif
 
+       snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
+       av[ac++] = xlbuf;
+
+       av[ac++] = "-p";
+       av[ac++] = "template1";
+
+       av[ac] = NULL;
+       Assert(ac < lengthof(av));
+
+       /*
+        * Flush stdio channels (see comments in BackendStartup)
+        */
        fflush(stdout);
        fflush(stderr);
 
-#ifndef EXEC_BACKEND
+#ifdef EXEC_BACKEND
+
+       pid = postmaster_forkexec(ac, av);
+
+#else                                                  /* !EXEC_BACKEND */
+
 #ifdef LINUX_PROFILE
-       /* see comments in BackendRun */
+       /* see comments in BackendStartup */
        getitimer(ITIMER_PROF, &prof_itimer);
 #endif
 
@@ -3056,16 +3510,10 @@ SSDataBase(int xlop)
        beos_before_backend_startup();
 #endif
 
-       /* Non EXEC_BACKEND case; fork here */
-       if ((pid = fork()) == 0)        /* child */
-#endif
-       {
-               char       *av[10];
-               int                     ac = 0;
-               char            nbbuf[32];
-               char            xlbuf[32];
+       pid = fork();
 
-#ifndef EXEC_BACKEND
+       if (pid == 0)                           /* child */
+       {
 #ifdef LINUX_PROFILE
                setitimer(ITIMER_PROF, &prof_itimer, NULL);
 #endif
@@ -3075,89 +3523,44 @@ SSDataBase(int xlop)
                beos_backend_startup();
 #endif
 
-               /* Close the postmaster's sockets */
-               ClosePostmasterPorts(true);
-
-               SSDataBaseInit(xlop);
-#else
-               if (!write_backend_variables(NULL))
-                       return -1; /* log issued by write_backend_variables */
-#endif
-
-               /* Set up command-line arguments for subprocess */
-               av[ac++] = "postgres";
-
-#ifdef EXEC_BACKEND
-               av[ac++] = "-boot";
-#endif
-               snprintf(nbbuf, sizeof(nbbuf), "-B%d", NBuffers);
-               av[ac++] = nbbuf;
-
-               snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
-               av[ac++] = xlbuf;
+               IsUnderPostmaster = true;               /* we are a postmaster subprocess
+                                                                                * now */
 
-#ifdef EXEC_BACKEND
-               /* pass data dir before end of secure switches (-p) */
-               snprintf(ddirbuf, MAXPGPATH, "\"%s\"", DataDir);
-               av[ac++] = "-D";
-               av[ac++] = ddirbuf;
-
-               /* and the backend identifier + dbname */
-               snprintf(idbuf, sizeof(idbuf), "-p%lu,template1", tmpBackendFileNum);
-               av[ac++] = idbuf;
-#else
-               av[ac++] = "-p";
-               av[ac++] = "template1";
-#endif
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
 
-               av[ac] = NULL;
+               /* Lose the postmaster's on-exit routines and port connections */
+               on_exit_reset();
 
-               Assert(ac < lengthof(av));
+               /* Release postmaster's working memory context */
+               MemoryContextSwitchTo(TopMemoryContext);
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
 
-#ifdef EXEC_BACKEND
-               /* EXEC_BACKEND case; fork/exec here */
-#ifdef WIN32
-               pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
-               if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
-               {
-                       /* in child */
-                       elog(ERROR, "unable to execv in SSDataBase: %m");
-                       exit(0);
-               }
-#endif
-#else
                BootstrapMain(ac, av);
                ExitPostmaster(0);
-#endif
        }
+#endif   /* EXEC_BACKEND */
 
-       /* in parent */
        if (pid < 0)
        {
-#ifndef EXEC_BACKEND
+               /* in parent, fork failed */
+               int                     save_errno = errno;
+
 #ifdef __BEOS__
                /* Specific beos actions before backend startup */
                beos_backend_startup_failed();
 #endif
-#endif
+               errno = save_errno;
                switch (xlop)
                {
                        case BS_XLOG_STARTUP:
                                ereport(LOG,
                                                (errmsg("could not fork startup process: %m")));
                                break;
-                       case BS_XLOG_CHECKPOINT:
-                               ereport(LOG,
-                                         (errmsg("could not fork checkpoint process: %m")));
-                               break;
                        case BS_XLOG_BGWRITER:
                                ereport(LOG,
-                                         (errmsg("could not fork bgwriter process: %m")));
-                               break;
-                       case BS_XLOG_SHUTDOWN:
-                               ereport(LOG,
-                                               (errmsg("could not fork shutdown process: %m")));
+                               (errmsg("could not fork background writer process: %m")));
                                break;
                        default:
                                ereport(LOG,
@@ -3166,48 +3569,17 @@ SSDataBase(int xlop)
                }
 
                /*
-                * fork failure is fatal during startup/shutdown, but there's no
-                * need to choke if a routine checkpoint or starting a background
-                * writer fails.
+                * fork failure is fatal during startup, but there's no need to
+                * choke immediately if starting other child types fails.
                 */
-               if (xlop == BS_XLOG_CHECKPOINT)
-                       return 0;
-               if (xlop == BS_XLOG_BGWRITER)
-                       return 0;
-               ExitPostmaster(1);
+               if (xlop == BS_XLOG_STARTUP)
+                       ExitPostmaster(1);
+               return 0;
        }
 
        /*
-        * The startup and shutdown processes are not considered normal
-        * backends, but the checkpoint and bgwriter processes are.
-        * They must be added to the list of backends.
+        * in parent, successful fork
         */
-       if (xlop == BS_XLOG_CHECKPOINT || xlop == BS_XLOG_BGWRITER)
-       {
-               if (!(bn = (Backend *) malloc(sizeof(Backend))))
-               {
-                       ereport(LOG,
-                                       (errcode(ERRCODE_OUT_OF_MEMORY),
-                                        errmsg("out of memory")));
-                       ExitPostmaster(1);
-               }
-
-               bn->pid = pid;
-               bn->cancel_key = PostmasterRandom();
-#ifdef EXEC_BACKEND
-               ShmemBackendArrayAdd(bn);
-#endif
-               DLAddHead(BackendList, DLNewElem(bn));
-
-               /*
-                * Since this code is executed periodically, it's a fine place to
-                * do other actions that should happen every now and then on no
-                * particular schedule.  Such as...
-                */
-               TouchSocketFile();
-               TouchSocketLockFile();
-       }
-
        return pid;
 }
 
@@ -3232,7 +3604,7 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
 
        fprintf(fp, "%s", fullprogname);
        for (i = 1; i < argc; i++)
-               fprintf(fp, " '%s'", argv[i]);
+               fprintf(fp, " %s%s%s", SYSTEMQUOTE, argv[i], SYSTEMQUOTE);
        fputs("\n", fp);
 
        if (fclose(fp))
@@ -3244,203 +3616,310 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
        return true;
 }
 
-/*
- * This should be used only for reporting "interactive" errors (essentially,
- * bogus arguments on the command line).  Once the postmaster is launched,
- * use ereport.  In particular, don't use this for anything that occurs
- * after pmdaemonize.
- */
-static void
-postmaster_error(const char *fmt,...)
-{
-       va_list         ap;
-
-       fprintf(stderr, "%s: ", progname);
-       va_start(ap, fmt);
-       vfprintf(stderr, gettext(fmt), ap);
-       va_end(ap);
-       fprintf(stderr, "\n");
-}
-
 
 #ifdef EXEC_BACKEND
 
 /*
- * The following need to be available to the read/write_backend_variables
+ * The following need to be available to the save/restore_backend_variables
  * functions
  */
-#include "storage/spin.h"
-extern XLogRecPtr RedoRecPtr;
-extern XLogwrtResult LogwrtResult;
 extern slock_t *ShmemLock;
 extern slock_t *ShmemIndexLock;
 extern void *ShmemIndexAlloc;
-typedef struct LWLock LWLock;
 extern LWLock *LWLockArray;
-extern slock_t  *ProcStructLock;
+extern slock_t *ProcStructLock;
 extern int     pgStatSock;
+extern int pgStatPipe[2];
+
+#ifndef WIN32
+#define write_inheritable_socket(dest, src, childpid) (*(dest) = (src))
+#define read_inheritable_socket(dest, src) (*(dest) = *(src))
+#else
+static void write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child);
+static void write_inheritable_socket(InheritableSocket *dest, SOCKET src,
+                                                                        pid_t childPid);
+static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
+#endif
 
-#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
-#define read_var(var,fp)  fread((void*)&(var),sizeof(var),1,fp)
-#define get_tmp_backend_file_name(buf,id)      \
-               do {                                                            \
-                       Assert(DataDir);                                \
-                       sprintf((buf),                                  \
-                               "%s/%s/%s.backend_var.%lu",     \
-                               DataDir,                                        \
-                               PG_TEMP_FILES_DIR,                      \
-                               PG_TEMP_FILE_PREFIX,            \
-                               (id));                                          \
-               } while (0)
 
+/* Save critical backend variables into the BackendParameters struct */
+#ifndef WIN32
+static bool
+save_backend_variables(BackendParameters *param, Port *port)
+#else
 static bool
-write_backend_variables(Port *port)
+save_backend_variables(BackendParameters *param, Port *port,
+                                          HANDLE childProcess, pid_t childPid)
+#endif
 {
-       char    filename[MAXPGPATH];
-       FILE    *fp;
-       get_tmp_backend_file_name(filename,++tmpBackendFileNum);
+       memcpy(&param->port, port, sizeof(Port));
+       write_inheritable_socket(&param->portsocket, port->sock, childPid);
 
-       /* Open file */
-       fp = AllocateFile(filename, PG_BINARY_W);
-       if (!fp)
-       {
-               /* As per OpenTemporaryFile... */
-               char dirname[MAXPGPATH];
-               sprintf(dirname,"%s/%s",DataDir,PG_TEMP_FILES_DIR);
-               mkdir(dirname, S_IRWXU);
+       StrNCpy(param->DataDir, DataDir, MAXPGPATH);
 
-               fp = AllocateFile(filename, PG_BINARY_W);
-               if (!fp)
-               {
+       memcpy(&param->ListenSocket, &ListenSocket, sizeof(ListenSocket));
+
+       param->MyCancelKey = MyCancelKey;
+
+       param->UsedShmemSegID = UsedShmemSegID;
+       param->UsedShmemSegAddr = UsedShmemSegAddr;
+
+       param->ShmemLock = ShmemLock;
+       param->ShmemIndexLock = ShmemIndexLock;
+       param->ShmemVariableCache = ShmemVariableCache;
+       param->ShmemIndexAlloc = ShmemIndexAlloc;
+       param->ShmemBackendArray = ShmemBackendArray;
+
+       param->LWLockArray = LWLockArray;
+       param->ProcStructLock = ProcStructLock;
+       write_inheritable_socket(&param->pgStatSock, pgStatSock, childPid);
+       write_inheritable_socket(&param->pgStatPipe0, pgStatPipe[0], childPid);
+       write_inheritable_socket(&param->pgStatPipe1, pgStatPipe[1], childPid);
+
+       param->PostmasterPid = PostmasterPid;
+
+#ifdef WIN32
+       param->PostmasterHandle = PostmasterHandle;
+       write_duplicated_handle(&param->initial_signal_pipe,
+                                                       pgwin32_create_signal_listener(childPid),
+                                                       childProcess);
+#endif
+
+       memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
+
+       StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
+
+       StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
+
+       StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN);
+       StrNCpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), LOCALE_NAME_BUFLEN);
+
+       return true;
+}
+
+
+#ifdef WIN32
+/*
+ * Duplicate a handle for usage in a child process, and write the child
+ * process instance of the handle to the parameter file.
+ */
+static void
+write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess)
+{
+       HANDLE hChild = INVALID_HANDLE_VALUE;
+
+       if (!DuplicateHandle(GetCurrentProcess(),
+                                                src,
+                                                childProcess,
+                                                &hChild,
+                                                0,
+                                                TRUE,
+                                                DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
+               ereport(ERROR,
+                               (errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d",
+                                                                (int) GetLastError())));
+
+       *dest = hChild;
+}
+
+/*
+ * Duplicate a socket for usage in a child process, and write the resulting
+ * structure to the parameter file.
+ * This is required because a number of LSPs (Layered Service Providers) very
+ * common on Windows (antivirus, firewalls, download managers etc) break
+ * straight socket inheritance.
+ */
+static void
+write_inheritable_socket(InheritableSocket *dest, SOCKET src, pid_t childpid)
+{
+       dest->origsocket = src;
+       if (src != 0 && src != -1)
+       {
+               /* Actual socket */
+               if (WSADuplicateSocket(src, childpid, &dest->wsainfo) != 0)
                        ereport(ERROR,
-                               (errcode_for_file_access(),
-                               errmsg("could not write to file \"%s\": %m", filename)));
-                       return false;
-               }
+                                       (errmsg("could not duplicate socket %d for use in backend: error code %d",
+                                                       src, WSAGetLastError())));
        }
+}
+
+/*
+ * Read a duplicate socket structure back, and get the socket descriptor.
+ */
+static void
+read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
+{
+       SOCKET s;
 
-       /* Write vars */
-       if (port)
+       if (src->origsocket == -1  || src->origsocket == 0)
        {
-               write_var(port->sock,fp);
-               write_var(port->proto,fp);
-               write_var(port->laddr,fp);
-               write_var(port->raddr,fp);
-               write_var(port->canAcceptConnections,fp);
-               write_var(port->cryptSalt,fp);
-               write_var(port->md5Salt,fp);
+               /* Not a real socket! */
+               *dest = src->origsocket;
        }
-       write_var(MyCancelKey,fp);
+       else
+       {
+               /* Actual socket, so create from structure */
+               s = WSASocket(FROM_PROTOCOL_INFO,
+                                         FROM_PROTOCOL_INFO,
+                                         FROM_PROTOCOL_INFO,
+                                         &src->wsainfo,
+                                         0,
+                                         0);
+               if (s == INVALID_SOCKET)
+               {
+                       write_stderr("could not create inherited socket: error code %d\n",
+                                                WSAGetLastError());
+                       exit(1);
+               }
+               *dest = s;
 
-       write_var(RedoRecPtr,fp);
-       write_var(LogwrtResult,fp);
+               /*
+                * To make sure we don't get two references to the same socket,
+                * close the original one. (This would happen when inheritance
+                * actually works..
+                */
+               closesocket(src->origsocket);
+       }
+}
+#endif
 
-       write_var(UsedShmemSegID,fp);
-       write_var(UsedShmemSegAddr,fp);
+static void
+read_backend_variables(char *id, Port *port)
+{
+       BackendParameters param;
 
-       write_var(ShmemLock,fp);
-       write_var(ShmemIndexLock,fp);
-       write_var(ShmemVariableCache,fp);
-       write_var(ShmemIndexAlloc,fp);
-       write_var(ShmemBackendArray,fp);
+#ifndef WIN32
+       /* Non-win32 implementation reads from file */
+       FILE *fp;
 
-       write_var(LWLockArray,fp);
-       write_var(ProcStructLock,fp);
-       write_var(pgStatSock,fp);
+       /* Open file */
+       fp = AllocateFile(id, PG_BINARY_R);
+       if (!fp)
+       {
+               write_stderr("could not read from backend variables file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
+       }
 
-       write_var(PreAuthDelay,fp);
-       write_var(debug_flag,fp);
-       write_var(PostmasterPid,fp);
+       if (fread(&param, sizeof(param), 1, fp) != 1)
+       {
+               write_stderr("could not read from backend variables file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
+       }
 
        /* Release file */
-       if (FreeFile(fp))
+       FreeFile(fp);
+       if (unlink(id) != 0)
        {
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to file \"%s\": %m", filename)));
-               return false;
+               write_stderr("could not remove file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
        }
+#else
+       /* Win32 version uses mapped file */
+       HANDLE paramHandle;
+       BackendParameters *paramp;
 
-       return true;
-}
+       paramHandle = (HANDLE)atol(id);
+       paramp = MapViewOfFile(paramHandle, FILE_MAP_READ, 0, 0, 0);
+       if (!paramp)
+       {
+               write_stderr("could not map view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
 
-void
-read_backend_variables(unsigned long id, Port *port)
-{
-       char    filename[MAXPGPATH];
-       FILE    *fp;
-       get_tmp_backend_file_name(filename,id);
+       memcpy(&param, paramp, sizeof(BackendParameters));
 
-       /* Open file */
-       fp = AllocateFile(filename, PG_BINARY_R);
-       if (!fp)
+       if (!UnmapViewOfFile(paramp))
        {
-               ereport(ERROR,
-                       (errcode_for_file_access(),
-                       errmsg("could not read from backend_variables file \"%s\": %m", filename)));
-               return;
+               write_stderr("could not unmap view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
        }
 
-       /* Read vars */
-       if (port)
+       if (!CloseHandle(paramHandle))
        {
-               read_var(port->sock,fp);
-               read_var(port->proto,fp);
-               read_var(port->laddr,fp);
-               read_var(port->raddr,fp);
-               read_var(port->canAcceptConnections,fp);
-               read_var(port->cryptSalt,fp);
-               read_var(port->md5Salt,fp);
+               write_stderr("could not close handle to backend parameter variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
        }
-       read_var(MyCancelKey,fp);
+#endif
 
-       read_var(RedoRecPtr,fp);
-       read_var(LogwrtResult,fp);
+       restore_backend_variables(&param, port);
+}
 
-       read_var(UsedShmemSegID,fp);
-       read_var(UsedShmemSegAddr,fp);
+/* Restore critical backend variables from the BackendParameters struct */
+static void
+restore_backend_variables(BackendParameters *param, Port *port)
+{
+       memcpy(port, &param->port, sizeof(Port));
+       read_inheritable_socket(&port->sock, &param->portsocket);
 
-       read_var(ShmemLock,fp);
-       read_var(ShmemIndexLock,fp);
-       read_var(ShmemVariableCache,fp);
-       read_var(ShmemIndexAlloc,fp);
-       read_var(ShmemBackendArray,fp);
+       SetDataDir(param->DataDir);
 
-       read_var(LWLockArray,fp);
-       read_var(ProcStructLock,fp);
-       read_var(pgStatSock,fp);
+       memcpy(&ListenSocket, &param->ListenSocket, sizeof(ListenSocket));
 
-       read_var(PreAuthDelay,fp);
-       read_var(debug_flag,fp);
-       read_var(PostmasterPid,fp);
+       MyCancelKey = param->MyCancelKey;
 
-       /* Release file */
-       FreeFile(fp);
-       if (unlink(filename) != 0)
-               ereport(WARNING,
-                               (errcode_for_file_access(),
-                                errmsg("could not remove file \"%s\": %m", filename)));
+       UsedShmemSegID = param->UsedShmemSegID;
+       UsedShmemSegAddr = param->UsedShmemSegAddr;
+
+       ShmemLock = param->ShmemLock;
+       ShmemIndexLock = param->ShmemIndexLock;
+       ShmemVariableCache = param->ShmemVariableCache;
+       ShmemIndexAlloc = param->ShmemIndexAlloc;
+       ShmemBackendArray = param->ShmemBackendArray;
+
+       LWLockArray = param->LWLockArray;
+       ProcStructLock = param->ProcStructLock;
+       read_inheritable_socket(&pgStatSock, &param->pgStatSock);
+       read_inheritable_socket(&pgStatPipe[0], &param->pgStatPipe0);
+       read_inheritable_socket(&pgStatPipe[1], &param->pgStatPipe1);
+
+       PostmasterPid = param->PostmasterPid;
+
+#ifdef WIN32
+       PostmasterHandle = param->PostmasterHandle;
+       pgwin32_initial_signal_pipe = param->initial_signal_pipe;
+#endif
+
+       memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
+
+       StrNCpy(my_exec_path, param->my_exec_path, MAXPGPATH);
+
+       StrNCpy(ExtraOptions, param->ExtraOptions, MAXPGPATH);
+
+       setlocale(LC_COLLATE, param->lc_collate);
+       setlocale(LC_CTYPE, param->lc_ctype);
 }
 
 
-size_t ShmemBackendArraySize(void)
+size_t
+ShmemBackendArraySize(void)
 {
-       return (NUM_BACKENDARRAY_ELEMS*sizeof(Backend));
+       return (NUM_BACKENDARRAY_ELEMS * sizeof(Backend));
 }
 
-void ShmemBackendArrayAllocation(void)
+void
+ShmemBackendArrayAllocation(void)
 {
-       size_t size = ShmemBackendArraySize();
-       ShmemBackendArray = (Backend*)ShmemAlloc(size);
+       size_t          size = ShmemBackendArraySize();
+
+       ShmemBackendArray = (Backend *) ShmemAlloc(size);
+       /* Mark all slots as empty */
        memset(ShmemBackendArray, 0, size);
 }
 
-static void ShmemBackendArrayAdd(Backend *bn)
+static void
+ShmemBackendArrayAdd(Backend *bn)
 {
-       int i;
+       int                     i;
+
+       /* Find an empty slot */
        for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
        {
-               /* Find an empty slot */
                if (ShmemBackendArray[i].pid == 0)
                {
                        ShmemBackendArray[i] = *bn;
@@ -3449,12 +3928,14 @@ static void ShmemBackendArrayAdd(Backend *bn)
        }
 
        ereport(FATAL,
-                       (errmsg_internal("unable to add backend entry")));
+                       (errmsg_internal("no free slots in shmem backend array")));
 }
 
-static void ShmemBackendArrayRemove(pid_t pid)
+static void
+ShmemBackendArrayRemove(pid_t pid)
 {
-       int i;
+       int                     i;
+
        for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
        {
                if (ShmemBackendArray[i].pid == pid)
@@ -3466,88 +3947,28 @@ static void ShmemBackendArrayRemove(pid_t pid)
        }
 
        ereport(WARNING,
-                       (errmsg_internal("unable to find backend entry with pid %d",
-                                                        pid)));
+                       (errmsg_internal("could not find backend entry with pid %d",
+                                                        (int) pid)));
 }
 
-#endif
-
-#ifdef WIN32
-
-pid_t win32_forkexec(const char* path, char *argv[])
-{
-       STARTUPINFO si;
-       PROCESS_INFORMATION pi;
-       char *p;
-       int i;
-       char cmdLine[MAXPGPATH];
-       HANDLE childHandleCopy;
-       HANDLE waiterThread;
-
-       /* Format the cmd line */
-       snprintf(cmdLine,sizeof(cmdLine),"\"%s\"",path);
-       i = 0;
-       while (argv[++i] != NULL)
-       {
-               /* FIXME: [fork/exec] some strlen checks might be prudent here */
-               strcat(cmdLine," ");
-               strcat(cmdLine,argv[i]);
-       }
-
-       /*
-        * The following snippet can disappear when we consistently
-        * use forward slashes.
-        */
-       p = cmdLine;
-       while (*(p++) != '\0')
-               if (*p == '/') *p = '\\';
-
-       memset(&pi,0,sizeof(pi));
-       memset(&si,0,sizeof(si));
-       si.cb = sizeof(si);
-       if (!CreateProcess(NULL,cmdLine,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
-       {
-               elog(ERROR,"CreateProcess call failed (%i): %m",(int)GetLastError());
-               return -1;
-       }
-
-       if (!IsUnderPostmaster)
-               /* We are the Postmaster creating a child... */
-               win32_AddChild(pi.dwProcessId,pi.hProcess);
-
-       if (!DuplicateHandle(GetCurrentProcess(),
-                                                pi.hProcess,
-                                                GetCurrentProcess(),
-                                                &childHandleCopy,
-                                                0,
-                                                FALSE,
-                                                DUPLICATE_SAME_ACCESS))
-               ereport(FATAL,
-                               (errmsg_internal("failed to duplicate child handle: %i",(int)GetLastError())));
-       waiterThread = CreateThread(NULL, 64*1024, win32_sigchld_waiter, (LPVOID)childHandleCopy, 0, NULL);
-       if (!waiterThread)
-               ereport(FATAL,
-                               (errmsg_internal("failed to create sigchld waiter thread: %i",(int)GetLastError())));
-       CloseHandle(waiterThread);
+#endif   /* EXEC_BACKEND */
 
-       if (IsUnderPostmaster)
-               CloseHandle(pi.hProcess);
-       CloseHandle(pi.hThread);
 
-       return pi.dwProcessId;
-}
+#ifdef WIN32
 
 /*
- * Note: The following three functions must not be interrupted (eg. by signals).
- *  As the Postgres Win32 signalling architecture (currently) requires polling,
- *  or APC checking functions which aren't used here, this is not an issue.
+ * Note: The following three functions must not be interrupted (eg. by
+ * signals).  As the Postgres Win32 signalling architecture (currently)
+ * requires polling, or APC checking functions which aren't used here, this
+ * is not an issue.
  *
- *  We keep two separate arrays, instead of a single array of pid/HANDLE structs,
- *  to avoid having to re-create a handle array for WaitForMultipleObjects on
- *  each call to win32_waitpid.
+ * We keep two separate arrays, instead of a single array of pid/HANDLE
+ * structs, to avoid having to re-create a handle array for
+ * WaitForMultipleObjects on each call to win32_waitpid.
  */
 
-static void win32_AddChild(pid_t pid, HANDLE handle)
+static void
+win32_AddChild(pid_t pid, HANDLE handle)
 {
        Assert(win32_childPIDArray && win32_childHNDArray);
        if (win32_numChildren < NUM_BACKENDARRAY_ELEMS)
@@ -3558,13 +3979,15 @@ static void win32_AddChild(pid_t pid, HANDLE handle)
        }
        else
                ereport(FATAL,
-                               (errmsg_internal("unable to add child entry with pid %lu",
-                                                                pid)));
+                               (errmsg_internal("no room for child entry with pid %lu",
+                                                                (unsigned long) pid)));
 }
 
-static void win32_RemoveChild(pid_t pid)
+static void
+win32_RemoveChild(pid_t pid)
 {
-       int i;
+       int                     i;
+
        Assert(win32_childPIDArray && win32_childHNDArray);
 
        for (i = 0; i < win32_numChildren; i++)
@@ -3582,70 +4005,88 @@ static void win32_RemoveChild(pid_t pid)
        }
 
        ereport(WARNING,
-                       (errmsg_internal("unable to find child entry with pid %lu",
-                                                        pid)));
+                       (errmsg_internal("could not find child entry with pid %lu",
+                                                        (unsigned long) pid)));
 }
 
-static pid_t win32_waitpid(int *exitstatus)
+static pid_t
+win32_waitpid(int *exitstatus)
 {
+       /*
+        * Note: Do NOT use WaitForMultipleObjectsEx, as we don't want to run
+        * queued APCs here.
+        */
+       int                     index;
+       DWORD           exitCode;
+       DWORD           ret;
+       unsigned long offset;
+
        Assert(win32_childPIDArray && win32_childHNDArray);
-       elog(DEBUG3,"waiting on %lu children",win32_numChildren);
+       elog(DEBUG3, "waiting on %lu children", win32_numChildren);
 
-       if (win32_numChildren > 0)
+       for (offset = 0; offset < win32_numChildren; offset += MAXIMUM_WAIT_OBJECTS)
        {
-               /*
-                * Note: Do NOT use WaitForMultipleObjectsEx, as we don't
-                * want to run queued APCs here.
-                */
-               int index;
-               DWORD exitCode;
-               DWORD ret = WaitForMultipleObjects(win32_numChildren,win32_childHNDArray,FALSE,0);
+               unsigned long num = Min(MAXIMUM_WAIT_OBJECTS, win32_numChildren - offset);
 
+               ret = WaitForMultipleObjects(num, &win32_childHNDArray[offset], FALSE, 0);
                switch (ret)
                {
                        case WAIT_FAILED:
-                               ereport(ERROR,
-                                               (errmsg_internal("failed to wait on %lu children: %i",
-                                                                                win32_numChildren,(int)GetLastError())));
-                               /* Fall through to WAIT_TIMEOUTs return */
+                               ereport(LOG,
+                                               (errmsg_internal("failed to wait on %lu of %lu children: error code %d",
+                                                num, win32_numChildren, (int) GetLastError())));
+                               return -1;
 
                        case WAIT_TIMEOUT:
-                               /* No children have finished */
-                               return -1;
+                               /* No children (in this chunk) have finished */
+                               break;
 
                        default:
-                               /* Get the exit code, and return the PID of, the respective process */
-                               index = ret-WAIT_OBJECT_0;
+
+                               /*
+                                * Get the exit code, and return the PID of, the
+                                * respective process
+                                */
+                               index = offset + ret - WAIT_OBJECT_0;
                                Assert(index >= 0 && index < win32_numChildren);
-                               if (!GetExitCodeProcess(win32_childHNDArray[index],&exitCode))
+                               if (!GetExitCodeProcess(win32_childHNDArray[index], &exitCode))
+                               {
                                        /*
-                                        * If we get this far, this should never happen, but, then again...
-                                        * No choice other than to assume a catastrophic failure.
+                                        * If we get this far, this should never happen, but,
+                                        * then again... No choice other than to assume a
+                                        * catastrophic failure.
                                         */
                                        ereport(FATAL,
                                                        (errmsg_internal("failed to get exit code for child %lu",
-                                                                                        win32_childPIDArray[index])));
-                               *exitstatus = (int)exitCode;
+                                                                                        (unsigned long) win32_childPIDArray[index])));
+                               }
+                               *exitstatus = (int) exitCode;
                                return win32_childPIDArray[index];
                }
        }
 
-       /* No children */
+       /* No children have finished */
        return -1;
 }
 
-/* Note! Code belows executes on separate threads, one for
-   each child process created */
-static DWORD WINAPI win32_sigchld_waiter(LPVOID param) {
-       HANDLE procHandle = (HANDLE)param;
+/*
+ * Note! Code below executes on separate threads, one for
+ * each child process created
+ */
+static DWORD WINAPI
+win32_sigchld_waiter(LPVOID param)
+{
+       HANDLE          procHandle = (HANDLE) param;
+
+       DWORD           r = WaitForSingleObject(procHandle, INFINITE);
 
-       DWORD r = WaitForSingleObject(procHandle, INFINITE);
        if (r == WAIT_OBJECT_0)
                pg_queue_signal(SIGCHLD);
        else
-               fprintf(stderr,"ERROR: Failed to wait on child process handle: %i\n",(int)GetLastError());
+               write_stderr("could not wait on child process handle: error code %d\n",
+                                        (int) GetLastError());
        CloseHandle(procHandle);
        return 0;
 }
 
-#endif
+#endif   /* WIN32 */