]> 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 89a22815098955fc0fcc5d5050bac3d087ff26bd..d84bf2775768ee2628cbc09ee84bfbff89959964 100644 (file)
@@ -7,7 +7,7 @@
  *       message to setup a backend process.
  *
  *       The postmaster also manages system-wide operations such as
- *       startup and shutdown. The postmaster itself doesn't do those
+ *       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.
  *       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.399 2004/05/28 15:14:03 tgl 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/socket.h>
-#include <errno.h>
 #include <fcntl.h>
 #include <sys/param.h>
 #include <netinet/in.h>
@@ -87,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 "pgtime.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"
 
-
-#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
 {
@@ -148,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
@@ -172,7 +168,7 @@ int                 ReservedBackends;
 static const char *progname = NULL;
 
 /* The socket(s) we're listening to. */
-#define MAXLISTEN      10
+#define MAXLISTEN      64
 static int     ListenSocket[MAXLISTEN];
 
 /*
@@ -196,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;
@@ -209,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
@@ -232,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;
@@ -248,10 +239,11 @@ extern int        optreset;
 /*
  * postmaster.c - function prototypes
  */
-static void checkDataDir(const char *checkdir);
+static void checkDataDir(void);
+
 #ifdef USE_RENDEZVOUS
 static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
-                                         void *context);
+                 void *context);
 #endif
 static void pmdaemonize(void);
 static Port *ConnCreate(int serverFd);
@@ -262,7 +254,8 @@ 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 int     BackendRun(Port *port);
@@ -280,16 +273,11 @@ 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);
-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
-static 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 pid_t win32_waitpid(int *exitstatus);
@@ -298,23 +286,78 @@ static DWORD WINAPI win32_sigchld_waiter(LPVOID param);
 static pid_t *win32_childPIDArray;
 static HANDLE *win32_childHNDArray;
 static unsigned long win32_numChildren = 0;
+
+HANDLE         PostmasterHandle;
 #endif
 
 static pid_t backend_forkexec(Port *port);
 static pid_t internal_forkexec(int argc, char *argv[], Port *port);
 
-static void read_backend_variables(char *filename, Port *port);
-static bool write_backend_variables(char *filename, Port *port);
+/* Type for a socket that can be inherited to a client process */
+#ifdef WIN32
+typedef struct
+{
+       SOCKET origsocket; /* Original socket value, or -1 if not a socket */
+       WSAPROTOCOL_INFO wsainfo;
+} InheritableSocket;
+#else
+typedef int InheritableSocket;
+#endif
+
+typedef struct LWLock LWLock;  /* ugly kluge */
+
+/*
+ * 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;
+
+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);
 
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
-#define StartupDataBase()              SSDataBase(BS_XLOG_STARTUP)
-#define CheckPointDataBase()   SSDataBase(BS_XLOG_CHECKPOINT)
-#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
-#define ShutdownDataBase()             SSDataBase(BS_XLOG_SHUTDOWN)
+#define StartupDataBase()              StartChildProcess(BS_XLOG_STARTUP)
+#define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
 
 
 /*
@@ -325,13 +368,13 @@ 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;
 
@@ -353,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
         */
@@ -392,8 +438,6 @@ PostmasterMain(int argc, char *argv[])
         */
        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)
@@ -404,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':
@@ -417,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;
@@ -471,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);
@@ -529,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);
                }
        }
@@ -541,27 +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);
-
-       ProcessConfigFile(PGC_POSTMASTER);
-
-       /* If timezone is not set, determine what the OS uses */
-       pg_timezone_initialize();
+       if (!SelectConfigFiles(userDoption, progname))
+               ExitPostmaster(2);
 
-#ifdef EXEC_BACKEND
-       write_nondefault_variables(PGC_POSTMASTER);
-#endif
+       /* Verify that DataDir looks reasonable */
+       checkDataDir();
 
        /*
         * Check for invalid combinations of GUC settings.
@@ -573,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);
        }
 
@@ -588,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);
        }
 
@@ -622,8 +651,8 @@ PostmasterMain(int argc, char *argv[])
        if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
                                                postgres_exec_path) < 0)
                ereport(FATAL,
-                               (errmsg("%s: could not locate matching postgres executable",
-                                               progname)));
+                        (errmsg("%s: could not locate matching postgres executable",
+                                        progname)));
 #endif
 
        /*
@@ -656,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);
 
@@ -676,23 +705,26 @@ 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';
+                       /* 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,
@@ -707,12 +739,10 @@ PostmasterMain(int argc, char *argv[])
                                ereport(WARNING,
                                         (errmsg("could not create listen socket for \"%s\"",
                                                         curhost)));
-                       *endptr = c;
-                       if (c != '\0')
-                               curhost = endptr + 1;
-                       else
-                               break;
                }
+
+               list_free(elemlist);
+               pfree(rawstring);
        }
 
 #ifdef USE_RENDEZVOUS
@@ -768,14 +798,31 @@ PostmasterMain(int argc, char *argv[])
 #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
 
        /*
@@ -786,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 */
@@ -814,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) pg_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...
@@ -870,35 +929,26 @@ PostmasterMain(int argc, char *argv[])
  * Validate the proposed data directory
  */
 static void
-checkDataDir(const char *checkdir)
+checkDataDir(void)
 {
        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);
-       }
+       Assert(DataDir);
 
-       if (stat(checkdir, &stat_buf) == -1)
+       if (stat(DataDir, &stat_buf) != 0)
        {
                if (errno == ENOENT)
                        ereport(FATAL,
                                        (errcode_for_file_access(),
                                         errmsg("data directory \"%s\" does not exist",
-                                                       checkdir)));
+                                                       DataDir)));
                else
                        ereport(FATAL,
                                        (errcode_for_file_access(),
                         errmsg("could not read permissions of directory \"%s\": %m",
-                                       checkdir)));
+                                       DataDir)));
        }
 
        /*
@@ -908,28 +958,27 @@ checkDataDir(const char *checkdir)
         * 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 !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",
-                                               checkdir),
+                                               DataDir),
                                 errdetail("Permissions should be u=rwx (0700).")));
 #endif
 
        /* Look for PG_VERSION before looking for pg_control */
-       ValidatePgVersion(checkdir);
+       ValidatePgVersion(DataDir);
 
-       snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
+       snprintf(path, sizeof(path), "%s/global/pg_control", DataDir);
 
        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));
+               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);
@@ -946,8 +995,7 @@ reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
 {
 
 }
-
-#endif /* USE_RENDEZVOUS */
+#endif   /* USE_RENDEZVOUS */
 
 
 /*
@@ -956,10 +1004,7 @@ reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
 static void
 pmdaemonize(void)
 {
-#ifdef WIN32
-       /* not supported */
-       elog(FATAL, "SilentMode not supported under WIN32");
-#else
+#ifndef WIN32
        int                     i;
        pid_t           pid;
 
@@ -975,8 +1020,8 @@ pmdaemonize(void)
        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)
@@ -989,7 +1034,7 @@ pmdaemonize(void)
        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.
@@ -997,17 +1042,20 @@ pmdaemonize(void)
 #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 */
 }
 
 
@@ -1017,35 +1065,35 @@ pmdaemonize(void)
 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"));
+       printf(_("  -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(_("  -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"));
@@ -1053,19 +1101,21 @@ usage(const char *progname)
 
 
 /*
- * Main loop of postmaster
+ * 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);
 
@@ -1074,77 +1124,24 @@ ServerLoop(void)
                Port       *port;
                fd_set          rmask;
                struct timeval timeout;
-
-               /*
-                * 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).
-                */
-               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);
-
-                       if (CheckPointTimeout + checkpointed > now)
-                       {
-                               /*
-                                * Not time for checkpoint yet, so set select timeout
-                                */
-                               timeout.tv_sec = CheckPointTimeout + checkpointed - now;
-                       }
-                       else
-                       {
-                               /* Time to make the checkpoint... */
-                               CheckPointPID = CheckPointDataBase();
-
-                               /*
-                                * if fork failed, schedule another try at 0.1 normal
-                                * delay
-                                */
-                               if (CheckPointPID == 0)
-                               {
-                                       timeout.tv_sec = CheckPointTimeout / 10;
-                                       checkpointed = now + timeout.tv_sec - CheckPointTimeout;
-                               }
-                       }
-               }
-
-               /*
-                * 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 (BgWriterPID == 0 && BgWriterPercent > 0 &&
-                       StartupPID == 0 && Shutdown == NoShutdown &&
-                       !FatalError && random_seed != 0)
-                       BgWriterPID = StartBackgroundWriter();
+               int                     selres;
+               int                     i;
 
                /*
                 * 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;
+
                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;
-               }
+               selres = select(nSockets, &rmask, NULL, NULL, &timeout);
 
                /*
                 * Block all signals until we wait again.  (This makes it safe for
@@ -1152,58 +1149,110 @@ ServerLoop(void)
                 */
                PG_SETMASK(&BlockSig);
 
-               /*
-                * Select a random seed at the time of first receiving a request.
-                */
-               while (random_seed == 0)
+               if (selres < 0)
                {
-                       gettimeofday(&later, &tz);
-
-                       /*
-                        * 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 (errno != EINTR && errno != EWOULDBLOCK)
+                       {
+                               ereport(LOG,
+                                               (errcode_for_socket_access(),
+                                                errmsg("select() failed in postmaster: %m")));
+                               return STATUS_ERROR;
+                       }
                }
 
                /*
                 * New connection pending on any of our sockets? If so, fork a
                 * child process to deal with it.
                 */
-               for (i = 0; i < MAXLISTEN; i++)
+               if (selres > 0)
                {
-                       if (ListenSocket[i] == -1)
-                               break;
-                       if (FD_ISSET(ListenSocket[i], &rmask))
+                       /*
+                        * Select a random seed at the time of first receiving a
+                        * request.
+                        */
+                       while (random_seed == 0)
                        {
-                               port = ConnCreate(ListenSocket[i]);
-                               if (port)
-                               {
-                                       BackendStartup(port);
+                               gettimeofday(&later, &tz);
 
-                                       /*
-                                        * We no longer need the open socket or port structure
-                                        * in this process
-                                        */
-                                       StreamClose(port->sock);
-                                       ConnFree(port);
+                               /*
+                                * 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.
+                                */
+                               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))
+                               {
+                                       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 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 && StartupPID == 0 && !FatalError)
+               {
+                       BgWriterPID = StartBackgroundWriter();
+                       /* If shutdown is pending, set it going */
+                       if (Shutdown > NoShutdown && BgWriterPID != 0)
+                               kill(BgWriterPID, SIGUSR2);
+               }
+
+               /* If we have lost the archiver, try to start a new one */
+               if (XLogArchivingActive() && PgArchPID == 0 &&
+                       StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                       PgArchPID = pgarch_start();
+
                /* If we have lost the stats collector, try to start a new one */
-               if (!pgstat_is_running)
-                       pgstat_start();
+               if (PgStatPID == 0 &&
+                       StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                       PgStatPID = pgstat_start();
+
+               /*
+                * Touch the socket and lock file at least every ten minutes, to
+                * ensure that they are not removed by overzealous /tmp-cleaning
+                * tasks.
+                */
+               now = time(NULL);
+               if (now - last_touch_time >= 10 * 60)
+               {
+                       TouchSocketFile();
+                       TouchSocketLockFile();
+                       last_touch_time = now;
+               }
        }
 }
 
 
 /*
- * 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)
@@ -1543,25 +1592,10 @@ processCancelRequest(Port *port, void *pkt)
        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.  In the EXEC_BACKEND case, we
         * can no longer access the postmaster's own backend list, and must
-        * rely on the backup array in shared memory.
+        * rely on the duplicate array in shared memory.
         */
 #ifndef EXEC_BACKEND
        for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
@@ -1685,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;
 
@@ -1701,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
+       }
 }
 
 
@@ -1741,6 +1788,15 @@ SIGHUP_handler(SIGNAL_ARGS)
                         (errmsg("received SIGHUP, reloading configuration files")));
                ProcessConfigFile(PGC_SIGHUP);
                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();
 
@@ -1748,13 +1804,6 @@ SIGHUP_handler(SIGNAL_ARGS)
                /* Update the starting-point file for future children */
                write_nondefault_variables(PGC_SIGHUP);
 #endif
-
-               /*
-                * 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);
        }
 
        PG_SETMASK(&UnBlockSig);
@@ -1784,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;
@@ -1792,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:
@@ -1821,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;
@@ -1842,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:
@@ -1861,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);
@@ -1916,116 +1976,188 @@ reaper(SIGNAL_ARGS)
        while ((pid = win32_waitpid(&exitstatus)) > 0)
        {
                /*
-                * We need to do this here, and not in CleanupProc, 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...
+                * 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 /* WIN32 */
-#endif /* HAVE_WAITPID */
-
-               /*
-                * 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 - we are done with system startup or recovery.
+                        * Startup succeeded - we are done with system startup or
+                        * recovery.
                         */
                        FatalError = false;
 
                        /*
-                        * Arrange for first checkpoint to occur after standard delay.
+                        * 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();
+
+                       /*
+                        * 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;
                }
 
                /*
-                * Else do standard child cleanup.
+                * Was it the bgwriter?
                 */
-               CleanupProc(pid, exitstatus);
+               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);
+                       }
 
-       }                                                       /* loop over pending child-death reports */
+                       /*
+                        * Any unexpected exit of the bgwriter is treated as a crash.
+                        */
+                       HandleChildCrash(pid, exitstatus,
+                                                        _("background writer process"));
+                       continue;
+               }
 
-       if (FatalError)
-       {
                /*
-                * Wait for all children exit, then reset shmem and
-                * StartupDataBase.
+                * 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 (DLGetHead(BackendList) || StartupPID > 0 || ShutdownPID > 0)
-                       goto reaper_done;
-               ereport(LOG,
-                       (errmsg("all server processes terminated; reinitializing")));
-
-               shmem_exit(0);
-               reset_shared(PostPortNumber);
-
-               StartupPID = StartupDataBase();
+               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;
+               }
 
-               goto reaper_done;
+               /*
+                * 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.)
+                */
+               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 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 || BgWriterPID != 0)
+                       goto reaper_done;
+               ereport(LOG,
+                       (errmsg("all server processes terminated; reinitializing")));
+
+               shmem_exit(0);
+               reset_shared(PostPortNumber);
+
+               StartupPID = StartupDataBase();
+
+               goto reaper_done;
        }
 
        if (Shutdown > NoShutdown)
        {
-               if (DLGetHead(BackendList))
+               if (DLGetHead(BackendList) || StartupPID != 0)
                        goto reaper_done;
-               if (StartupPID > 0 || ShutdownPID > 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:
@@ -2036,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
@@ -2056,61 +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);
-                       }
-               }
-               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,
@@ -2130,36 +2276,44 @@ CleanupProc(int 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)
-               BgWriterPID = 0;
-       else
+
+       /* Force a power-cycle of the pgarch process too */
+       /* (Shouldn't be necessary, but just for luck) */
+       if (PgArchPID != 0 && !FatalError)
        {
-               /*
-                * Tell the collector about backend termination
-                */
-               pgstat_beterm(pid);
+               ereport(DEBUG2,
+                               (errmsg_internal("sending %s to process %d",
+                                                                "SIGQUIT",
+                                                                (int) PgArchPID)));
+               kill(PgArchPID, SIGQUIT);
+       }
+
+       /* Force a power-cycle of the pgstat processes too */
+       /* (Shouldn't be necessary, but just for luck) */
+       if (PgStatPID != 0 && !FatalError)
+       {
+               ereport(DEBUG2,
+                               (errmsg_internal("sending %s to process %d",
+                                                                "SIGQUIT",
+                                                                (int) PgStatPID)));
+               kill(PgStatPID, SIGQUIT);
        }
 
+       /* We do NOT restart the syslogger */
+
        FatalError = true;
 }
 
@@ -2199,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);
        }
 }
 
@@ -2280,7 +2424,7 @@ BackendStartup(Port *port)
 
        pid = backend_forkexec(port);
 
-#else /* !EXEC_BACKEND */
+#else                                                  /* !EXEC_BACKEND */
 
 #ifdef LINUX_PROFILE
 
@@ -2315,8 +2459,7 @@ BackendStartup(Port *port)
 
                proc_exit(BackendRun(port));
        }
-
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
        if (pid < 0)
        {
@@ -2346,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;
 }
@@ -2369,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 */
@@ -2422,15 +2565,12 @@ 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            debugbuf[32];
        char            protobuf[32];
        int                     i;
 
@@ -2438,9 +2578,9 @@ BackendRun(Port *port)
 
        /*
         * Let's clean up ourselves as the postmaster child, and close the
-        * postmaster's other sockets
+        * postmaster's listen sockets
         */
-       ClosePostmasterPorts(true);
+       ClosePostmasterPorts(false);
 
        /* We don't want the postmaster's proc_exit() handlers */
        on_exit_reset();
@@ -2530,12 +2670,12 @@ BackendRun(Port *port)
        port->remote_port = strdup(remote_port);
 
        /*
-        * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.c
+        * 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?
+        * FIXME: [fork/exec] Ugh.      Is there a way around this overhead?
         */
 #ifdef EXEC_BACKEND
        Assert(PostmasterContext == NULL);
@@ -2601,9 +2741,7 @@ BackendRun(Port *port)
         * start a new random sequence in the random() library function.
         */
        random_seed = 0;
-       gettimeofday(&now, &tz);
-       srandom((unsigned int) now.tv_usec);
-
+       srandom((unsigned int) (MyProcPid ^ port->session_start.tv_usec));
 
        /* ----------------
         * Now, build the argv vector that will be given to PostgresMain.
@@ -2628,15 +2766,6 @@ 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.  (It's OK to mangle
@@ -2682,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])));
@@ -2741,14 +2870,70 @@ backend_forkexec(Port *port)
        return internal_forkexec(ac, av, port);
 }
 
+#ifndef WIN32
+
+/*
+ * 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;
+
+       if (!save_backend_variables(&param, port))
+               return -1;                              /* log made by save_backend_variables */
+
+       /* 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);
+
+       /* Open file */
+       fp = AllocateFile(tmpfilename, PG_BINARY_W);
+       if (!fp)
+       {
+               /* As per OpenTemporaryFile... */
+               char            dirname[MAXPGPATH];
+
+               snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
+               mkdir(dirname, S_IRWXU);
+
+               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;
+       }
 
-       if (!write_backend_variables(tmpfilename, port))
-               return -1;                              /* log made by write_backend_variables */
+       /* 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);
@@ -2759,89 +2944,305 @@ internal_forkexec(int argc, char *argv[], Port *port)
        /* Insert temp file name after -fork argument */
        argv[2] = tmpfilename;
 
-#ifdef WIN32
-       pid = win32_forkexec(postgres_exec_path, argv);
-#else
        /* Fire off execv in child */
        if ((pid = fork()) == 0)
        {
                if (execv(postgres_exec_path, argv) < 0)
                {
                        ereport(LOG,
-                                       (errmsg("could not exec backend process \"%s\": %m",
+                                       (errmsg("could not execute server process \"%s\": %m",
                                                        postgres_exec_path)));
                        /* We're already in the child process here, can't return */
                        exit(1);
                }
        }
-#endif
 
-       return pid;                                     /* Parent returns pid, or -1 on fork failure */
+       return pid;                                     /* Parent returns pid, or -1 on fork
+                                                                * failure */
 }
 
+#else /* 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.
+ * internal_forkexec win32 implementation
  *
- * 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.
+ * - 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.
  */
-int
-SubPostmasterMain(int argc, char *argv[])
+static pid_t
+internal_forkexec(int argc, char *argv[], Port *port)
 {
-       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;
-       pqinitmask();
-       PG_SETMASK(&BlockSig);
-
-       /* Setup essential subsystems */
-       MemoryContextInit();
-       InitializeGUCOptions();
+       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];
 
-       /* Check we got appropriate args */
-       if (argc < 3)
-               elog(FATAL, "invalid subpostmaster invocation");
+       /* 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);
 
-       /* Read in file-based context */
-       memset(&port, 0, sizeof(Port));
-       read_backend_variables(argv[2], &port);
-       read_nondefault_variables();
+       /* 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;
+       }
 
-       /* Run backend or appropriate child */
-       if (strcmp(argv[1], "-forkbackend") == 0)
+       param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
+       if (!param)
        {
-               /* BackendRun will close sockets */
+               elog(LOG, "could not map backend parameter memory: error code %d",
+                        (int) GetLastError());
+               CloseHandle(paramHandle);
+               return -1;
+       }
 
-               /* Attach process to shared segments */
-               CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+       /* Insert temp file name after -fork argument */
+       sprintf(paramHandleStr, "%lu", (DWORD)paramHandle);
+       argv[2] = paramHandleStr;
 
-               Assert(argc == 3);              /* shouldn't be any more args */
-               proc_exit(BackendRun(&port));
+       /* 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 (strcmp(argv[1], "-forkboot") == 0)
+       if (cmdLine[sizeof(cmdLine) - 2] != '\0')
        {
-               /* Close the postmaster's sockets */
-               ClosePostmasterPorts(true);
-
-               /* Attach process to shared segments */
-               CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+               elog(LOG, "subprocess command line too long");
+               return -1;
+       }
 
-               BootstrapMain(argc - 2, argv + 2);
-               ExitPostmaster(0);
+       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;
        }
-       if (strcmp(argv[1], "-forkbuf") == 0)
+
+       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 */
+       }
+
+       /* 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());
+
+       /*
+        * 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;
+       }
+
+       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
+       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
+               /*
+                *      Need to reinitialize the SSL library in the backend,
+                *      since the context structures contain function pointers
+                *      and cannot be passed through the parameter file.
+                */
+               if (EnableSSL)
+                       secure_initialize();
+#endif
+
+               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);
@@ -2849,25 +3250,35 @@ SubPostmasterMain(int argc, char *argv[])
                /* Do not want to attach to shared memory */
 
                PgstatBufferMain(argc, argv);
-               ExitPostmaster(0);
+               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 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);
-               ExitPostmaster(0);
+               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 /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
 
 /*
@@ -2886,8 +3297,6 @@ ExitPostmaster(int status)
         *
         * MUST         -- vadim 05-10-1999
         */
-       /* Should I use true instead? */
-       ClosePostmasterPorts(false);
 
        proc_exit(status);
 }
@@ -2902,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))
        {
                /*
@@ -2957,10 +3327,22 @@ sigusr1_handler(SIGNAL_ARGS)
                 * CatchupInterruptHandler). See storage/ipc/sinval[adt].c for the
                 * use of this.
                 */
-               if (Shutdown == NoShutdown)
+               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);
 
        errno = save_errno;
@@ -2971,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)
@@ -3051,47 +3434,37 @@ 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;
 }
 
 
 /*
- * SSDataBase -- start a non-backend child process for the postmaster
+ * StartChildProcess -- start a non-backend child process for the postmaster
  *
- * xlog determines what kind of child will be started.  All child types
+ * xlog determines what kind of child will be started. All child types
  * initially go to BootstrapMain, which will handle common setup.
  *
- * Return value of SSDataBase is subprocess' PID, or 0 if failed to start
- * subprocess (0 is returned only for checkpoint/bgwriter cases).
+ * Return value of StartChildProcess is subprocess' PID, or 0 if failed
+ * to start subprocess.
  */
 static pid_t
-SSDataBase(int xlop)
+StartChildProcess(int xlop)
 {
-       Backend    *bn;
        pid_t           pid;
        char       *av[10];
        int                     ac = 0;
        char            xlbuf[32];
+
 #ifdef LINUX_PROFILE
        struct itimerval prof_itimer;
 #endif
@@ -3125,7 +3498,7 @@ SSDataBase(int xlop)
 
        pid = postmaster_forkexec(ac, av);
 
-#else /* !EXEC_BACKEND */
+#else                                                  /* !EXEC_BACKEND */
 
 #ifdef LINUX_PROFILE
        /* see comments in BackendStartup */
@@ -3150,19 +3523,24 @@ SSDataBase(int xlop)
                beos_backend_startup();
 #endif
 
-               IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
+               IsUnderPostmaster = true;               /* we are a postmaster subprocess
+                                                                                * now */
 
                /* Close the postmaster's sockets */
-               ClosePostmasterPorts(true);
+               ClosePostmasterPorts(false);
 
                /* Lose the postmaster's on-exit routines and port connections */
                on_exit_reset();
 
+               /* Release postmaster's working memory context */
+               MemoryContextSwitchTo(TopMemoryContext);
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
+
                BootstrapMain(ac, av);
                ExitPostmaster(0);
        }
-
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
        if (pid < 0)
        {
@@ -3180,17 +3558,9 @@ SSDataBase(int xlop)
                                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,
@@ -3199,50 +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;
        }
 
        /*
         * in parent, successful fork
-        *
-        * 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.
         */
-       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;
 }
 
@@ -3267,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))
@@ -3279,193 +3616,283 @@ 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 slock_t *ShmemLock;
 extern slock_t *ShmemIndexLock;
 extern void *ShmemIndexAlloc;
-typedef struct LWLock LWLock;
 extern LWLock *LWLockArray;
 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)
 
+/* 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(char *filename, Port *port)
+save_backend_variables(BackendParameters *param, Port *port,
+                                          HANDLE childProcess, pid_t childPid)
+#endif
 {
-       static unsigned long tmpBackendFileNum = 0;
-       FILE       *fp;
-       char            str_buf[MAXPGPATH];
+       memcpy(&param->port, port, sizeof(Port));
+       write_inheritable_socket(&param->portsocket, port->sock, childPid);
 
-       /* Calculate name for temp file in caller's buffer */
-       Assert(DataDir);
-       snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%lu",
-                        DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
-                        ++tmpBackendFileNum);
+       StrNCpy(param->DataDir, DataDir, MAXPGPATH);
 
-       /* Open file */
-       fp = AllocateFile(filename, PG_BINARY_W);
-       if (!fp)
-       {
-               /* As per OpenTemporaryFile... */
-               char            dirname[MAXPGPATH];
+       memcpy(&param->ListenSocket, &ListenSocket, sizeof(ListenSocket));
 
-               snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
-               mkdir(dirname, S_IRWXU);
+       param->MyCancelKey = MyCancelKey;
 
-               fp = AllocateFile(filename, PG_BINARY_W);
-               if (!fp)
-               {
-                       ereport(LOG,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not create file \"%s\": %m",
-                                                       filename)));
-                       return false;
-               }
-       }
+       param->UsedShmemSegID = UsedShmemSegID;
+       param->UsedShmemSegAddr = UsedShmemSegAddr;
 
-       /* Write vars */
-       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);
+       param->ShmemLock = ShmemLock;
+       param->ShmemIndexLock = ShmemIndexLock;
+       param->ShmemVariableCache = ShmemVariableCache;
+       param->ShmemIndexAlloc = ShmemIndexAlloc;
+       param->ShmemBackendArray = ShmemBackendArray;
 
-       /*
-        * XXX FIXME later: writing these strings as MAXPGPATH bytes always is
-        * probably a waste of resources
-        */
+       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);
 
-       StrNCpy(str_buf, DataDir, MAXPGPATH);
-       fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+       param->PostmasterPid = PostmasterPid;
 
-       write_var(MyCancelKey, fp);
+#ifdef WIN32
+       param->PostmasterHandle = PostmasterHandle;
+       write_duplicated_handle(&param->initial_signal_pipe,
+                                                       pgwin32_create_signal_listener(childPid),
+                                                       childProcess);
+#endif
 
-       write_var(UsedShmemSegID, fp);
-       write_var(UsedShmemSegAddr, fp);
+       memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
 
-       write_var(ShmemLock, fp);
-       write_var(ShmemIndexLock, fp);
-       write_var(ShmemVariableCache, fp);
-       write_var(ShmemIndexAlloc, fp);
-       write_var(ShmemBackendArray, fp);
+       StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
 
-       write_var(LWLockArray, fp);
-       write_var(ProcStructLock, fp);
-       write_var(pgStatSock, fp);
+       StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
 
-       write_var(debug_flag, fp);
-       write_var(PostmasterPid, fp);
+       StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN);
+       StrNCpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), LOCALE_NAME_BUFLEN);
 
-       fwrite((void *) my_exec_path, MAXPGPATH, 1, fp);
+       return true;
+}
 
-       fwrite((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
 
-       StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
-       fwrite((void *) str_buf, MAXPGPATH, 1, fp);
-       StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
-       fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+#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;
 
-       /* Release file */
-       if (FreeFile(fp))
-       {
+       if (!DuplicateHandle(GetCurrentProcess(),
+                                                src,
+                                                childProcess,
+                                                &hChild,
+                                                0,
+                                                TRUE,
+                                                DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
                ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to file \"%s\": %m", filename)));
-               return false;
+                               (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,
+                                       (errmsg("could not duplicate socket %d for use in backend: error code %d",
+                                                       src, WSAGetLastError())));
        }
+}
 
-       return true;
+/*
+ * Read a duplicate socket structure back, and get the socket descriptor.
+ */
+static void
+read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
+{
+       SOCKET s;
+
+       if (src->origsocket == -1  || src->origsocket == 0)
+       {
+               /* Not a real socket! */
+               *dest = src->origsocket;
+       }
+       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;
+
+               /*
+                * 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
 
 static void
-read_backend_variables(char *filename, Port *port)
+read_backend_variables(char *id, Port *port)
 {
-       FILE       *fp;
-       char            str_buf[MAXPGPATH];
+       BackendParameters param;
+
+#ifndef WIN32
+       /* Non-win32 implementation reads from file */
+       FILE *fp;
 
        /* Open file */
-       fp = AllocateFile(filename, PG_BINARY_R);
+       fp = AllocateFile(id, PG_BINARY_R);
        if (!fp)
-               ereport(FATAL,
-                               (errcode_for_file_access(),
-                                errmsg("could not read from backend variables file \"%s\": %m",
-                                               filename)));
+       {
+               write_stderr("could not read from backend variables file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
+       }
+
+       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 */
+       FreeFile(fp);
+       if (unlink(id) != 0)
+       {
+               write_stderr("could not remove file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
+       }
+#else
+       /* Win32 version uses mapped file */
+       HANDLE paramHandle;
+       BackendParameters *paramp;
+
+       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);
+       }
+
+       memcpy(&param, paramp, sizeof(BackendParameters));
+
+       if (!UnmapViewOfFile(paramp))
+       {
+               write_stderr("could not unmap view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+
+       if (!CloseHandle(paramHandle))
+       {
+               write_stderr("could not close handle to backend parameter variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+#endif
 
-       /* Read vars */
-       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);
+       restore_backend_variables(&param, port);
+}
 
-       fread((void *) str_buf, MAXPGPATH, 1, fp);
-       SetDataDir(str_buf);
+/* 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(MyCancelKey, fp);
+       SetDataDir(param->DataDir);
 
-       read_var(UsedShmemSegID, fp);
-       read_var(UsedShmemSegAddr, fp);
+       memcpy(&ListenSocket, &param->ListenSocket, sizeof(ListenSocket));
 
-       read_var(ShmemLock, fp);
-       read_var(ShmemIndexLock, fp);
-       read_var(ShmemVariableCache, fp);
-       read_var(ShmemIndexAlloc, fp);
-       read_var(ShmemBackendArray, fp);
+       MyCancelKey = param->MyCancelKey;
 
-       read_var(LWLockArray, fp);
-       read_var(ProcStructLock, fp);
-       read_var(pgStatSock, fp);
+       UsedShmemSegID = param->UsedShmemSegID;
+       UsedShmemSegAddr = param->UsedShmemSegAddr;
 
-       read_var(debug_flag, fp);
-       read_var(PostmasterPid, fp);
+       ShmemLock = param->ShmemLock;
+       ShmemIndexLock = param->ShmemIndexLock;
+       ShmemVariableCache = param->ShmemVariableCache;
+       ShmemIndexAlloc = param->ShmemIndexAlloc;
+       ShmemBackendArray = param->ShmemBackendArray;
 
-       fread((void *) my_exec_path, MAXPGPATH, 1, fp);
+       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);
 
-       fread((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+       PostmasterPid = param->PostmasterPid;
 
-       fread((void *) str_buf, MAXPGPATH, 1, fp);
-       setlocale(LC_COLLATE, str_buf);
-       fread((void *) str_buf, MAXPGPATH, 1, fp);
-       setlocale(LC_CTYPE, str_buf);
+#ifdef WIN32
+       PostmasterHandle = param->PostmasterHandle;
+       pgwin32_initial_signal_pipe = param->initial_signal_pipe;
+#endif
 
-       /* Release file */
-       FreeFile(fp);
-       if (unlink(filename) != 0)
-               ereport(WARNING,
-                               (errcode_for_file_access(),
-                                errmsg("could not remove file \"%s\": %m", filename)));
+       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);
 }
 
 
@@ -3481,6 +3908,7 @@ ShmemBackendArrayAllocation(void)
        size_t          size = ShmemBackendArraySize();
 
        ShmemBackendArray = (Backend *) ShmemAlloc(size);
+       /* Mark all slots as empty */
        memset(ShmemBackendArray, 0, size);
 }
 
@@ -3489,9 +3917,9 @@ ShmemBackendArrayAdd(Backend *bn)
 {
        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;
@@ -3500,7 +3928,7 @@ ShmemBackendArrayAdd(Backend *bn)
        }
 
        ereport(FATAL,
-                       (errmsg_internal("unable to add backend entry")));
+                       (errmsg_internal("no free slots in shmem backend array")));
 }
 
 static void
@@ -3519,91 +3947,24 @@ ShmemBackendArrayRemove(pid_t pid)
        }
 
        ereport(WARNING,
-                       (errmsg_internal("unable to find backend entry with pid %d",
+                       (errmsg_internal("could not find backend entry with pid %d",
                                                         (int) pid)));
 }
 
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
 
 #ifdef WIN32
 
-static pid_t
-win32_forkexec(const char *path, char *argv[])
-{
-       STARTUPINFO si;
-       PROCESS_INFORMATION pi;
-       int                     i;
-       int                     j;
-       char            cmdLine[MAXPGPATH * 2];
-       HANDLE          childHandleCopy;
-       HANDLE          waiterThread;
-
-       /* Format the cmd line */
-       cmdLine[sizeof(cmdLine)-1] = '\0';
-       cmdLine[sizeof(cmdLine)-2] = '\0';
-       snprintf(cmdLine, sizeof(cmdLine)-1, "\"%s\"", 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);
-       if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
-       {
-               elog(LOG, "CreateProcess call failed (%d): %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: %d",
-                                                                (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: %d",
-                                                                (int) GetLastError())));
-       CloseHandle(waiterThread);
-
-       if (IsUnderPostmaster)
-               CloseHandle(pi.hProcess);
-       CloseHandle(pi.hThread);
-
-       return pi.dwProcessId;
-}
-
 /*
- * 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
@@ -3618,7 +3979,7 @@ win32_AddChild(pid_t pid, HANDLE handle)
        }
        else
                ereport(FATAL,
-                               (errmsg_internal("unable to add child entry with pid %lu",
+                               (errmsg_internal("no room for child entry with pid %lu",
                                                                 (unsigned long) pid)));
 }
 
@@ -3644,37 +4005,41 @@ win32_RemoveChild(pid_t pid)
        }
 
        ereport(WARNING,
-                       (errmsg_internal("unable to find child entry with pid %lu",
+                       (errmsg_internal("could not find child entry with pid %lu",
                                                         (unsigned long) pid)));
 }
 
 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);
 
-       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:
 
@@ -3682,10 +4047,10 @@ win32_waitpid(int *exitstatus)
                                 * Get the exit code, and return the PID of, the
                                 * respective process
                                 */
-                               index = ret - WAIT_OBJECT_0;
+                               index = offset + ret - WAIT_OBJECT_0;
                                Assert(index >= 0 && index < win32_numChildren);
                                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
@@ -3693,18 +4058,21 @@ win32_waitpid(int *exitstatus)
                                         */
                                        ereport(FATAL,
                                                        (errmsg_internal("failed to get exit code for child %lu",
-                                                                                  win32_childPIDArray[index])));
+                                                                                        (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 */
+/*
+ * Note! Code below executes on separate threads, one for
+ * each child process created
+ */
 static DWORD WINAPI
 win32_sigchld_waiter(LPVOID param)
 {
@@ -3715,10 +4083,10 @@ win32_sigchld_waiter(LPVOID param)
        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 /* WIN32 */
+#endif   /* WIN32 */