]> 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 2081eb3650e39681f18099243cf06d9029ae504e..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.403 2004/06/11 03:54:43 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.445 2005/02/22 04:36:36 momjian Exp $
  *
  * NOTES
  *
  *             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.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -67,7 +73,6 @@
 #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 "miscadmin.h"
 #include "nodes/nodes.h"
 #include "postmaster/postmaster.h"
+#include "postmaster/pgarch.h"
+#include "postmaster/syslogger.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 #include "storage/bufmgr.h"
 #include "access/xlog.h"
 #include "tcop/tcopprot.h"
+#include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "bootstrap/bootstrap.h"
 #include "pgstat.h"
 
+#ifdef EXEC_BACKEND
+#include "storage/spin.h"
+#endif
+
 
 /*
  * List of active backends (or child processes anyway; we don't actually
@@ -155,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];
 
 /*
@@ -191,7 +204,10 @@ char          *preload_libraries_string = NULL;
 
 /* PIDs of special child processes; 0 when not running */
 static pid_t StartupPID = 0,
-                       BgWriterPID = 0;
+                       BgWriterPID = 0,
+                       PgArchPID = 0,
+                       PgStatPID = 0,
+                       SysLoggerPID = 0;
 
 /* Startup/shutdown state */
 #define                        NoShutdown              0
@@ -212,8 +228,6 @@ bool                ClientAuthInProgress = false;           /* T during new-client
  */
 static unsigned int random_seed = 0;
 
-static int     debug_flag = 0;
-
 extern char *optarg;
 extern int     optind,
                        opterr;
@@ -225,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);
@@ -239,8 +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 HandleChildCrash(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);
@@ -259,15 +274,10 @@ static void SignalChildren(int signal);
 static int     CountChildren(void);
 static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
 static pid_t StartChildProcess(int xlop);
-static void
-postmaster_error(const char *fmt,...)
-/* This lets gcc check the format string for consistency. */
-__attribute__((format(printf, 1, 2)));
 
 #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);
@@ -277,19 +287,74 @@ static pid_t *win32_childPIDArray;
 static HANDLE *win32_childHNDArray;
 static unsigned long win32_numChildren = 0;
 
-HANDLE PostmasterHandle;
+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()              StartChildProcess(BS_XLOG_STARTUP)
 #define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
@@ -303,10 +368,11 @@ PostmasterMain(int argc, char *argv[])
 {
        int                     opt;
        int                     status;
-       char       *potential_DataDir = NULL;
+       char       *userDoption = NULL;
        int                     i;
 
-       progname = get_progname(argv[0]);
+       /* This will call exit() if strdup() fails. */
+       progname = get_progname(argv[0]);       
 
        MyProcPid = PostmasterPid = getpid();
 
@@ -330,6 +396,11 @@ 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
@@ -367,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)
@@ -379,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':
@@ -392,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;
@@ -445,10 +505,12 @@ PostmasterMain(int argc, char *argv[])
                        case 'o':
 
                                /*
-                                * Other options to pass to the backend on the command line
+                                * Other options to pass to the backend on the command
+                                * line
                                 */
-                               strcat(ExtraOptions, " ");
-                               strcat(ExtraOptions, optarg);
+                               snprintf(ExtraOptions + strlen(ExtraOptions),
+                                                sizeof(ExtraOptions) - strlen(ExtraOptions),
+                                                " %s", optarg);
                                break;
                        case 'p':
                                SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV);
@@ -502,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);
                }
        }
@@ -514,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.
@@ -546,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);
        }
 
@@ -561,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);
        }
 
@@ -595,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
 
        /*
@@ -629,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(s) before
-        * the Unix socket.
+        * :-(). For the same reason, it's best to grab the TCP socket(s)
+        * before the Unix socket.
         */
        CreateDataDirLockFile(DataDir, true);
 
@@ -649,23 +705,26 @@ PostmasterMain(int argc, char *argv[])
 
        if (ListenAddresses)
        {
-               char       *curhost,
-                                  *endptr;
-               char            c;
+               char       *rawstring;
+               List       *elemlist;
+               ListCell   *l;
 
-               curhost = ListenAddresses;
-               for (;;)
+               /* Need a modifiable copy of ListenAddresses */
+               rawstring = pstrdup(ListenAddresses);
+
+               /* 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,
@@ -680,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
@@ -739,6 +796,7 @@ PostmasterMain(int argc, char *argv[])
        BackendList = DLNewList();
 
 #ifdef WIN32
+
        /*
         * Initialize the child pid/HANDLE arrays for signal handling.
         */
@@ -763,8 +821,8 @@ PostmasterMain(int argc, char *argv[])
                                                TRUE,
                                                DUPLICATE_SAME_ACCESS) == 0)
                ereport(FATAL,
-                               (errmsg_internal("could not duplicate postmaster handle: %d",
-                                                                (int) GetLastError())));
+                       (errmsg_internal("could not duplicate postmaster handle: error code %d",
+                                                        (int) GetLastError())));
 #endif
 
        /*
@@ -775,12 +833,35 @@ 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, postmaster/bgwriter.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);
@@ -802,38 +883,36 @@ PostmasterMain(int argc, char *argv[])
        pqsignal(SIGXFSZ, SIG_IGN); /* ignored */
 #endif
 
+       /*
+        * If enabled, start up syslogger collection subprocess
+        */
+       SysLoggerPID = SysLogger_Start();
+
        /*
         * 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.
+        * 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.
         */
        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...
         */
        StartupPID = StartupDataBase();
 
-#ifdef EXEC_BACKEND
-       write_nondefault_variables(PGC_POSTMASTER);
-#endif
-
        status = ServerLoop();
 
        /*
@@ -850,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)));
        }
 
        /*
@@ -888,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);
@@ -926,8 +995,7 @@ reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
 {
 
 }
-
-#endif /* USE_RENDEZVOUS */
+#endif   /* USE_RENDEZVOUS */
 
 
 /*
@@ -952,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)
@@ -966,7 +1034,7 @@ pmdaemonize(void)
        setitimer(ITIMER_PROF, &prof_itimer, NULL);
 #endif
 
-       MyProcPid = PostmasterPid = getpid();   /* reset PID vars 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.
@@ -974,20 +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);
-#else  /* WIN32 */
+#else                                                  /* WIN32 */
        /* not supported */
        elog(FATAL, "SilentMode not supported under WIN32");
-#endif /* WIN32 */
+#endif   /* WIN32 */
 }
 
 
@@ -997,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"));
@@ -1063,7 +1131,8 @@ ServerLoop(void)
                 * 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.
+                * tasks handled below get done even when no requests are
+                * arriving.
                 */
                memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
 
@@ -1082,12 +1151,13 @@ ServerLoop(void)
 
                if (selres < 0)
                {
-                       if (errno == EINTR || errno == EWOULDBLOCK)
-                               continue;
-                       ereport(LOG,
-                                       (errcode_for_socket_access(),
-                                        errmsg("select() failed in postmaster: %m")));
-                       return STATUS_ERROR;
+                       if (errno != EINTR && errno != EWOULDBLOCK)
+                       {
+                               ereport(LOG,
+                                               (errcode_for_socket_access(),
+                                                errmsg("select() failed in postmaster: %m")));
+                               return STATUS_ERROR;
+                       }
                }
 
                /*
@@ -1097,7 +1167,8 @@ ServerLoop(void)
                if (selres > 0)
                {
                        /*
-                        * Select a random seed at the time of first receiving a request.
+                        * Select a random seed at the time of first receiving a
+                        * request.
                         */
                        while (random_seed == 0)
                        {
@@ -1105,8 +1176,9 @@ ServerLoop(void)
 
                                /*
                                 * We are not sure how much precision is in tv_usec, so we
-                                * swap the nibbles of 'later' and XOR them with 'earlier'. On
-                                * the off chance that the result is 0, we loop until it isn't.
+                                * 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) |
@@ -1125,8 +1197,8 @@ ServerLoop(void)
                                                BackendStartup(port);
 
                                                /*
-                                                * We no longer need the open socket or port structure
-                                                * in this process
+                                                * We no longer need the open socket or port
+                                                * structure in this process
                                                 */
                                                StreamClose(port->sock);
                                                ConnFree(port);
@@ -1135,9 +1207,13 @@ ServerLoop(void)
                        }
                }
 
+               /* 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
-                * state that prevents it, start one.  It doesn't matter if this
+                * 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)
@@ -1148,13 +1224,20 @@ ServerLoop(void)
                                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.
+                * 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)
@@ -1509,14 +1592,6 @@ processCancelRequest(Port *port, void *pkt)
        backendPID = (int) ntohl(canc->backendPID);
        cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
 
-       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
@@ -1644,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(void)
+ClosePostmasterPorts(bool am_syslogger)
 {
        int                     i;
 
@@ -1659,6 +1737,20 @@ ClosePostmasterPorts(void)
                        ListenSocket[i] = -1;
                }
        }
+
+       /* 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
+       }
 }
 
 
@@ -1698,6 +1790,13 @@ SIGHUP_handler(SIGNAL_ARGS)
                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();
 
@@ -1730,6 +1829,7 @@ pmdie(SIGNAL_ARGS)
        switch (postgres_signal_arg)
        {
                case SIGTERM:
+
                        /*
                         * Smart Shutdown:
                         *
@@ -1755,9 +1855,16 @@ pmdie(SIGNAL_ARGS)
                        /* 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:
+
                        /*
                         * Fast Shutdown:
                         *
@@ -1785,8 +1892,8 @@ pmdie(SIGNAL_ARGS)
                        /*
                         * No children left. Begin shutdown of data base system.
                         *
-                        * Note: if we previously got SIGTERM then we may send SIGUSR2
-                        * to the bgwriter a second time here.  This should be harmless.
+                        * 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)
                                break;                  /* let reaper() handle this */
@@ -1796,9 +1903,16 @@ pmdie(SIGNAL_ARGS)
                        /* 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:
+
                        /*
                         * Immediate Shutdown:
                         *
@@ -1811,6 +1925,10 @@ pmdie(SIGNAL_ARGS)
                                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);
@@ -1858,27 +1976,14 @@ 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 startup process.
@@ -1888,7 +1993,7 @@ reaper(SIGNAL_ARGS)
                        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")));
@@ -1896,12 +2001,21 @@ reaper(SIGNAL_ARGS)
                        }
 
                        /*
-                        * Startup succeeded - we are done with system startup or recovery.
+                        * Startup succeeded - we are done with system startup or
+                        * recovery.
                         */
                        FatalError = false;
 
                        /*
-                        * Crank up the background writer.  It doesn't matter if this
+                        * 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.
                         */
                        Assert(BgWriterPID == 0);
@@ -1909,9 +2023,18 @@ reaper(SIGNAL_ARGS)
 
                        /*
                         * Go to shutdown mode if a shutdown request was pending.
+                        * Otherwise, try to start the archiver and stats collector
+                        * too.
                         */
                        if (Shutdown > NoShutdown && BgWriterPID != 0)
                                kill(BgWriterPID, SIGUSR2);
+                       else if (Shutdown == NoShutdown)
+                       {
+                               if (XLogArchivingActive() && PgArchPID == 0)
+                                       PgArchPID = pgarch_start();
+                               if (PgStatPID == 0)
+                                       PgStatPID = pgstat_start();
+                       }
 
                        continue;
                }
@@ -1921,38 +2044,90 @@ reaper(SIGNAL_ARGS)
                 */
                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
+                                * Normal postmaster exit is here: we've seen normal exit
+                                * of the bgwriter after it's been told to shut down. We
+                                * expect that it wrote a shutdown checkpoint.  (If for
+                                * some reason it didn't, recovery will occur on next
                                 * postmaster start.)
+                                *
+                                * Note: we do not wait around for exit of the archiver or
+                                * stats processes.  They've been sent SIGQUIT by this
+                                * point, and in any case contain logic to commit
+                                * hara-kiri if they notice the postmaster is gone.
                                 */
                                ExitPostmaster(0);
                        }
+
                        /*
                         * Any unexpected exit of the bgwriter is treated as a crash.
                         */
-                       LogChildExit(DEBUG2, gettext("background writer process"),
-                                                pid, exitstatus);
-                       HandleChildCrash(pid, exitstatus);
+                       HandleChildCrash(pid, exitstatus,
+                                                        _("background writer process"));
+                       continue;
+               }
+
+               /*
+                * Was it the archiver?  If so, just try to start a new one; no
+                * need to force reset of the rest of the system.  (If fail, we'll
+                * try again in future cycles of the main loop.)
+                */
+               if (PgArchPID != 0 && pid == PgArchPID)
+               {
+                       PgArchPID = 0;
+                       if (exitstatus != 0)
+                               LogChildExit(LOG, _("archiver process"),
+                                                        pid, exitstatus);
+                       if (XLogArchivingActive() &&
+                               StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+                               PgArchPID = pgarch_start();
+                       continue;
+               }
+
+               /*
+                * 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.
                 */
-               CleanupProc(pid, exitstatus);
+               CleanupBackend(pid, exitstatus);
        }                                                       /* loop over pending child-death reports */
 
        if (FatalError)
        {
                /*
-                * Wait for all children exit, then reset shmem and
-                * StartupDataBase.
+                * Wait for all important children to exit, then reset shmem and
+                * StartupDataBase.  (We can ignore the archiver and stats
+                * processes here since they are not connected to shmem.)
                 */
                if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
                        goto reaper_done;
@@ -1977,6 +2152,12 @@ reaper(SIGNAL_ARGS)
                /* 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:
@@ -1987,17 +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;
 
-       LogChildExit(DEBUG2, gettext("server 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
@@ -2007,7 +2188,7 @@ CleanupProc(int pid,
         */
        if (exitstatus != 0)
        {
-               HandleChildCrash(pid, exitstatus);
+               HandleChildCrash(pid, exitstatus, _("server process"));
                return;
        }
 
@@ -2037,8 +2218,7 @@ CleanupProc(int pid,
  * process, and to signal all other remaining children to quickdie.
  */
 static void
-HandleChildCrash(int pid,
-                                int exitstatus) /* child's exit status. */
+HandleChildCrash(int pid, int exitstatus, const char *procname)
 {
        Dlelem     *curr,
                           *next;
@@ -2046,17 +2226,14 @@ HandleChildCrash(int pid,
 
        /*
         * 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)
+        * exit status is to be expected in SIGQUIT response; don't clutter
+        * log)
         */
        if (!FatalError)
        {
-               LogChildExit(LOG,
-                                        (pid == BgWriterPID) ?
-                                        gettext("background writer process") :
-                                        gettext("server process"),
-                                        pid, exitstatus);
+               LogChildExit(LOG, procname, pid, exitstatus);
                ereport(LOG,
-                               (errmsg("terminating any other active server processes")));
+                         (errmsg("terminating any other active server processes")));
        }
 
        /* Process regular backends */
@@ -2113,6 +2290,30 @@ HandleChildCrash(int pid,
                kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
        }
 
+       /* Force a power-cycle of the pgarch process too */
+       /* (Shouldn't be necessary, but just for luck) */
+       if (PgArchPID != 0 && !FatalError)
+       {
+               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;
 }
 
@@ -2152,7 +2353,7 @@ 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)
@@ -2223,7 +2424,7 @@ BackendStartup(Port *port)
 
        pid = backend_forkexec(port);
 
-#else /* !EXEC_BACKEND */
+#else                                                  /* !EXEC_BACKEND */
 
 #ifdef LINUX_PROFILE
 
@@ -2258,8 +2459,7 @@ BackendStartup(Port *port)
 
                proc_exit(BackendRun(port));
        }
-
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
        if (pid < 0)
        {
@@ -2312,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 */
@@ -2365,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;
 
@@ -2383,7 +2580,7 @@ BackendRun(Port *port)
         * Let's clean up ourselves as the postmaster child, and close the
         * postmaster's listen sockets
         */
-       ClosePostmasterPorts();
+       ClosePostmasterPorts(false);
 
        /* We don't want the postmaster's proc_exit() handlers */
        on_exit_reset();
@@ -2473,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);
@@ -2544,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.
@@ -2571,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
@@ -2625,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])));
@@ -2684,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);
@@ -2702,73 +2944,279 @@ 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;
+
+       /* Format the cmd line */
+       cmdLine[sizeof(cmdLine) - 1] = '\0';
+       cmdLine[sizeof(cmdLine) - 2] = '\0';
+       snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path);
+       i = 0;
+       while (argv[++i] != NULL)
+       {
+               j = strlen(cmdLine);
+               snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
+       }
+       if (cmdLine[sizeof(cmdLine) - 2] != '\0')
+       {
+               elog(LOG, "subprocess command line too long");
+               return -1;
+       }
+
+       memset(&pi, 0, sizeof(pi));
+       memset(&si, 0, sizeof(si));
+       si.cb = sizeof(si);
+       /*
+        * Create the subprocess in a suspended state. This will be resumed
+        * later, once we have written out the parameter file.
+        */
+       if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED,
+                                          NULL, NULL, &si, &pi))
+       {
+               elog(LOG, "CreateProcess call failed: %m (error code %d)",
+                        (int) GetLastError());
+               return -1;
+       }
+
+       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));
@@ -2776,18 +3224,28 @@ SubPostmasterMain(int argc, char *argv[])
        if (strcmp(argv[1], "-forkboot") == 0)
        {
                /* Close the postmaster's sockets */
-               ClosePostmasterPorts();
+               ClosePostmasterPorts(false);
 
-               /* Attach process to shared segments */
+               /* 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();
+               ClosePostmasterPorts(false);
 
                /* Do not want to attach to shared memory */
 
@@ -2797,8 +3255,8 @@ SubPostmasterMain(int argc, char *argv[])
        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 */
@@ -2806,11 +3264,21 @@ SubPostmasterMain(int argc, char *argv[])
                PgstatCollectorMain(argc, argv);
                proc_exit(0);
        }
+       if (strcmp(argv[1], "-forklog") == 0)
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(true);
+
+               /* Do not want to attach to shared memory */
+
+               SysLoggerMain(argc, argv);
+               proc_exit(0);
+       }
 
        return 1;                                       /* shouldn't get here */
 }
 
-#endif /* EXEC_BACKEND */
+#endif   /* EXEC_BACKEND */
 
 
 /*
@@ -2863,6 +3331,18 @@ sigusr1_handler(SIGNAL_ARGS)
                        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;
@@ -2954,7 +3434,7 @@ PostmasterRandom(void)
 }
 
 /*
- * Count up number of child processes.
+ * Count up number of child processes (regular backends only)
  */
 static int
 CountChildren(void)
@@ -2963,9 +3443,7 @@ CountChildren(void)
        int                     cnt = 0;
 
        for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
-       {
                cnt++;
-       }
        return cnt;
 }
 
@@ -2973,7 +3451,7 @@ CountChildren(void)
 /*
  * 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 StartChildProcess is subprocess' PID, or 0 if failed
@@ -2986,6 +3464,7 @@ StartChildProcess(int xlop)
        char       *av[10];
        int                     ac = 0;
        char            xlbuf[32];
+
 #ifdef LINUX_PROFILE
        struct itimerval prof_itimer;
 #endif
@@ -3019,7 +3498,7 @@ StartChildProcess(int xlop)
 
        pid = postmaster_forkexec(ac, av);
 
-#else /* !EXEC_BACKEND */
+#else                                                  /* !EXEC_BACKEND */
 
 #ifdef LINUX_PROFILE
        /* see comments in BackendStartup */
@@ -3044,19 +3523,24 @@ StartChildProcess(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();
+               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)
        {
@@ -3076,7 +3560,7 @@ StartChildProcess(int xlop)
                                break;
                        case BS_XLOG_BGWRITER:
                                ereport(LOG,
-                                               (errmsg("could not fork background writer process: %m")));
+                               (errmsg("could not fork background writer process: %m")));
                                break;
                        default:
                                ereport(LOG,
@@ -3085,8 +3569,8 @@ StartChildProcess(int xlop)
                }
 
                /*
-                * fork failure is fatal during startup, but there's no need
-                * to choke immediately if starting other child types 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_STARTUP)
                        ExitPostmaster(1);
@@ -3120,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))
@@ -3132,207 +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)
-#define write_array_var(var,fp) fwrite((void*)(var),sizeof(var),1,fp)
-#define read_array_var(var,fp)  fread((void*)(var),sizeof(var),1,fp)
 
+/* Save critical backend variables into the BackendParameters struct */
+#ifndef WIN32
 static bool
-write_backend_variables(char *filename, Port *port)
+save_backend_variables(BackendParameters *param, Port *port)
+#else
+static bool
+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.%d.%lu",
-                        DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
-                        MyProcPid, ++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);
-       write_array_var(str_buf, fp);
+       param->PostmasterPid = PostmasterPid;
 
-       write_array_var(ListenSocket, fp);
+#ifdef WIN32
+       param->PostmasterHandle = PostmasterHandle;
+       write_duplicated_handle(&param->initial_signal_pipe,
+                                                       pgwin32_create_signal_listener(childPid),
+                                                       childProcess);
+#endif
+
+       memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
+
+       StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
 
-       write_var(MyCancelKey, fp);
+       StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
 
-       write_var(UsedShmemSegID, fp);
-       write_var(UsedShmemSegAddr, fp);
+       StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN);
+       StrNCpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), LOCALE_NAME_BUFLEN);
 
-       write_var(ShmemLock, fp);
-       write_var(ShmemIndexLock, fp);
-       write_var(ShmemVariableCache, fp);
-       write_var(ShmemIndexAlloc, fp);
-       write_var(ShmemBackendArray, fp);
+       return true;
+}
 
-       write_var(LWLockArray, fp);
-       write_var(ProcStructLock, fp);
-       write_var(pgStatSock, fp);
 
-       write_var(debug_flag, fp);
-       write_var(PostmasterPid, fp);
 #ifdef WIN32
-       write_var(PostmasterHandle, fp);
-#endif
+/*
+ * Duplicate a handle for usage in a child process, and write the child
+ * process instance of the handle to the parameter file.
+ */
+static void
+write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess)
+{
+       HANDLE hChild = INVALID_HANDLE_VALUE;
+
+       if (!DuplicateHandle(GetCurrentProcess(),
+                                                src,
+                                                childProcess,
+                                                &hChild,
+                                                0,
+                                                TRUE,
+                                                DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
+               ereport(ERROR,
+                               (errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d",
+                                                                (int) GetLastError())));
 
-       StrNCpy(str_buf, my_exec_path, MAXPGPATH);
-       write_array_var(str_buf, fp);
+       *dest = hChild;
+}
 
-       write_array_var(ExtraOptions, fp);
+/*
+ * 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())));
+       }
+}
 
-       StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
-       write_array_var(str_buf, fp);
-       StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
-       write_array_var(str_buf, fp);
+/*
+ * Read a duplicate socket structure back, and get the socket descriptor.
+ */
+static void
+read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
+{
+       SOCKET s;
 
-       /* Release file */
-       if (FreeFile(fp))
+       if (src->origsocket == -1  || src->origsocket == 0)
        {
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to file \"%s\": %m", filename)));
-               return false;
+               /* 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;
 
-       return true;
+               /*
+                * 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);
+       }
 
-       /* 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);
+       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);
+       }
 
-       read_array_var(str_buf, fp);
-       SetDataDir(str_buf);
+       /* 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;
 
-       read_array_var(ListenSocket, fp);
+       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);
+       }
 
-       read_var(MyCancelKey, fp);
+       memcpy(&param, paramp, sizeof(BackendParameters));
 
-       read_var(UsedShmemSegID, fp);
-       read_var(UsedShmemSegAddr, fp);
+       if (!UnmapViewOfFile(paramp))
+       {
+               write_stderr("could not unmap view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
 
-       read_var(ShmemLock, fp);
-       read_var(ShmemIndexLock, fp);
-       read_var(ShmemVariableCache, fp);
-       read_var(ShmemIndexAlloc, fp);
-       read_var(ShmemBackendArray, fp);
+       if (!CloseHandle(paramHandle))
+       {
+               write_stderr("could not close handle to backend parameter variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+#endif
+
+       restore_backend_variables(&param, port);
+}
+
+/* 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);
+
+       SetDataDir(param->DataDir);
+
+       memcpy(&ListenSocket, &param->ListenSocket, sizeof(ListenSocket));
+
+       MyCancelKey = param->MyCancelKey;
 
-       read_var(LWLockArray, fp);
-       read_var(ProcStructLock, fp);
-       read_var(pgStatSock, fp);
+       UsedShmemSegID = param->UsedShmemSegID;
+       UsedShmemSegAddr = param->UsedShmemSegAddr;
+
+       ShmemLock = param->ShmemLock;
+       ShmemIndexLock = param->ShmemIndexLock;
+       ShmemVariableCache = param->ShmemVariableCache;
+       ShmemIndexAlloc = param->ShmemIndexAlloc;
+       ShmemBackendArray = param->ShmemBackendArray;
+
+       LWLockArray = param->LWLockArray;
+       ProcStructLock = param->ProcStructLock;
+       read_inheritable_socket(&pgStatSock, &param->pgStatSock);
+       read_inheritable_socket(&pgStatPipe[0], &param->pgStatPipe0);
+       read_inheritable_socket(&pgStatPipe[1], &param->pgStatPipe1);
+
+       PostmasterPid = param->PostmasterPid;
 
-       read_var(debug_flag, fp);
-       read_var(PostmasterPid, fp);
 #ifdef WIN32
-       read_var(PostmasterHandle, fp);
+       PostmasterHandle = param->PostmasterHandle;
+       pgwin32_initial_signal_pipe = param->initial_signal_pipe;
 #endif
 
-       read_array_var(str_buf, fp);
-       StrNCpy(my_exec_path, str_buf, MAXPGPATH);
+       memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
 
-       read_array_var(ExtraOptions, fp);
+       StrNCpy(my_exec_path, param->my_exec_path, MAXPGPATH);
 
-       read_array_var(str_buf, fp);
-       setlocale(LC_COLLATE, str_buf);
-       read_array_var(str_buf, fp);
-       setlocale(LC_CTYPE, str_buf);
+       StrNCpy(ExtraOptions, param->ExtraOptions, MAXPGPATH);
 
-       /* Release file */
-       FreeFile(fp);
-       if (unlink(filename) != 0)
-               ereport(WARNING,
-                               (errcode_for_file_access(),
-                                errmsg("could not remove file \"%s\": %m", filename)));
+       setlocale(LC_COLLATE, param->lc_collate);
+       setlocale(LC_CTYPE, param->lc_ctype);
 }
 
 
@@ -3391,79 +3951,11 @@ ShmemBackendArrayRemove(pid_t pid)
                                                         (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) == 0)
-               ereport(FATAL,
-                               (errmsg_internal("could not duplicate child handle: %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: %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)
@@ -3520,32 +4012,34 @@ win32_RemoveChild(pid_t 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;
+               unsigned long num = Min(MAXIMUM_WAIT_OBJECTS, win32_numChildren - offset);
 
-               ret = WaitForMultipleObjects(win32_numChildren, win32_childHNDArray,
-                                                                        FALSE, 0);
+               ret = WaitForMultipleObjects(num, &win32_childHNDArray[offset], FALSE, 0);
                switch (ret)
                {
                        case WAIT_FAILED:
                                ereport(LOG,
-                                  (errmsg_internal("failed to wait on %lu children: %d",
-                                                         win32_numChildren, (int) GetLastError())));
+                                               (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:
 
@@ -3553,7 +4047,7 @@ 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))
                                {
@@ -3564,14 +4058,14 @@ 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;
 }
 
@@ -3589,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: %d\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 */