]> 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 96503e0a81854fea0901497ce44ecb885893c689..d84bf2775768ee2628cbc09ee84bfbff89959964 100644 (file)
  *       clients.
  *
  *
- * Portions Copyright (c) 1996-2004, 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.433 2004/10/14 20:23:45 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.445 2005/02/22 04:36:36 momjian Exp $
  *
  * NOTES
  *
@@ -92,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 "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
@@ -163,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];
 
 /*
@@ -223,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;
@@ -275,7 +278,6 @@ static pid_t StartChildProcess(int xlop);
 #ifdef EXEC_BACKEND
 
 #ifdef WIN32
-static pid_t win32_forkexec(const char *path, char *argv[]);
 static void win32_AddChild(pid_t pid, HANDLE handle);
 static void win32_RemoveChild(pid_t pid);
 static pid_t win32_waitpid(int *exitstatus);
@@ -291,11 +293,67 @@ HANDLE            PostmasterHandle;
 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 */
 
 #define StartupDataBase()              StartChildProcess(BS_XLOG_STARTUP)
@@ -313,7 +371,8 @@ PostmasterMain(int argc, char *argv[])
        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();
 
@@ -337,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
@@ -400,17 +464,8 @@ PostmasterMain(int argc, char *argv[])
                                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;
@@ -766,7 +821,7 @@ PostmasterMain(int argc, char *argv[])
                                                TRUE,
                                                DUPLICATE_SAME_ACCESS) == 0)
                ereport(FATAL,
-                       (errmsg_internal("could not duplicate postmaster handle: %d",
+                       (errmsg_internal("could not duplicate postmaster handle: error code %d",
                                                         (int) GetLastError())));
 #endif
 
@@ -848,12 +903,10 @@ PostmasterMain(int argc, char *argv[])
        pgstat_init();
 
        /*
-        * 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...
@@ -1012,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"));
@@ -1530,10 +1583,8 @@ processCancelRequest(Port *port, void *pkt)
        int                     backendPID;
        long            cancelAuthCode;
        Backend    *bp;
-
 #ifndef EXEC_BACKEND
        Dlelem     *curr;
-
 #else
        int                     i;
 #endif
@@ -1744,6 +1795,8 @@ SIGHUP_handler(SIGNAL_ARGS)
                if (SysLoggerPID != 0)
                        kill(SysLoggerPID, SIGHUP);
                /* PgStatPID does not currently need SIGHUP */
+
+               /* Reload authentication config files too */
                load_hba();
                load_ident();
 
@@ -1940,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")));
@@ -1953,6 +2006,14 @@ reaper(SIGNAL_ARGS)
                         */
                        FatalError = false;
 
+                       /*
+                        * 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.
@@ -2006,7 +2067,7 @@ reaper(SIGNAL_ARGS)
                         * Any unexpected exit of the bgwriter is treated as a crash.
                         */
                        HandleChildCrash(pid, exitstatus,
-                                                        gettext("background writer process"));
+                                                        _("background writer process"));
                        continue;
                }
 
@@ -2019,7 +2080,7 @@ reaper(SIGNAL_ARGS)
                {
                        PgArchPID = 0;
                        if (exitstatus != 0)
-                               LogChildExit(LOG, gettext("archiver process"),
+                               LogChildExit(LOG, _("archiver process"),
                                                         pid, exitstatus);
                        if (XLogArchivingActive() &&
                                StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
@@ -2036,7 +2097,7 @@ reaper(SIGNAL_ARGS)
                {
                        PgStatPID = 0;
                        if (exitstatus != 0)
-                               LogChildExit(LOG, gettext("statistics collector process"),
+                               LogChildExit(LOG, _("statistics collector process"),
                                                         pid, exitstatus);
                        if (StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
                                PgStatPID = pgstat_start();
@@ -2050,7 +2111,7 @@ reaper(SIGNAL_ARGS)
                        /* for safety's sake, launch new logger *first* */
                        SysLoggerPID = SysLogger_Start();
                        if (exitstatus != 0)
-                               LogChildExit(LOG, gettext("system logger process"),
+                               LogChildExit(LOG, _("system logger process"),
                                                         pid, exitstatus);
                        continue;
                }
@@ -2117,7 +2178,7 @@ CleanupBackend(int pid,
 {
        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
@@ -2127,7 +2188,7 @@ CleanupBackend(int pid,
         */
        if (exitstatus != 0)
        {
-               HandleChildCrash(pid, exitstatus, gettext("server process"));
+               HandleChildCrash(pid, exitstatus, _("server process"));
                return;
        }
 
@@ -2451,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 */
@@ -2510,7 +2571,6 @@ BackendRun(Port *port)
        char      **av;
        int                     maxac;
        int                     ac;
-       char            debugbuf[32];
        char            protobuf[32];
        int                     i;
 
@@ -2610,7 +2670,7 @@ 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.
@@ -2706,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
@@ -2819,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 */
 
-       if (!write_backend_variables(tmpfilename, port))
-               return -1;                              /* log made by write_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;
+       }
+
+       /* 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);
@@ -2837,27 +2944,200 @@ 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 */
 }
 
+#else /* WIN32 */
+
+/*
+ * internal_forkexec win32 implementation
+ *
+ * - starts backend using CreateProcess(), in suspended state
+ * - writes out backend variables to the parameter file
+ *  - during this, duplicates handles and sockets required for
+ *    inheritance into the new process
+ * - resumes execution of the new process once the backend parameter
+ *   file is complete.
+ */
+static pid_t
+internal_forkexec(int argc, char *argv[], Port *port)
+{
+       STARTUPINFO si;
+       PROCESS_INFORMATION pi;
+       int                     i;
+       int                     j;
+       char            cmdLine[MAXPGPATH * 2];
+       HANDLE          childHandleCopy;
+       HANDLE          waiterThread;
+       HANDLE      paramHandle;
+       BackendParameters *param;
+       SECURITY_ATTRIBUTES sa;
+       char        paramHandleStr[32];
+
+       /* Make sure caller set up argv properly */
+       Assert(argc >= 3);
+       Assert(argv[argc] == NULL);
+       Assert(strncmp(argv[1], "-fork", 5) == 0);
+       Assert(argv[2] == NULL);
+
+       /* Set up shared memory for parameter passing */
+       ZeroMemory(&sa,sizeof(sa));
+       sa.nLength = sizeof(sa);
+       sa.bInheritHandle = TRUE;
+       paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
+                                                                       &sa,
+                                                                       PAGE_READWRITE,
+                                                                       0,
+                                                                       sizeof(BackendParameters),
+                                                                       NULL);
+       if (paramHandle == INVALID_HANDLE_VALUE)
+       {
+               elog(LOG, "could not create backend parameter file mapping: error code %d",
+                        (int) GetLastError());
+               return -1;
+       }
+
+       param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
+       if (!param)
+       {
+               elog(LOG, "could not map backend parameter memory: error code %d",
+                        (int) GetLastError());
+               CloseHandle(paramHandle);
+               return -1;
+       }
+
+       /* 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
@@ -2882,20 +3162,42 @@ SubPostmasterMain(int argc, char *argv[])
        /* In EXEC_BACKEND case we will not have inherited these settings */
        IsPostmasterEnvironment = true;
        whereToSendOutput = None;
-       pqinitmask();
-       PG_SETMASK(&BlockSig);
 
-       /* Setup essential subsystems */
+       /* 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");
 
-       /* Read in file-based context */
-       memset(&port, 0, sizeof(Port));
-       read_backend_variables(argv[2], &port);
+       /*
+        * 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 */
@@ -2903,7 +3205,7 @@ SubPostmasterMain(int argc, char *argv[])
        {
                /* BackendRun will close sockets */
 
-               /* Attach process to shared segments */
+               /* Attach process to shared data structures */
                CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
 
 #ifdef USE_SSL
@@ -2924,7 +3226,7 @@ SubPostmasterMain(int argc, char *argv[])
                /* Close the postmaster's sockets */
                ClosePostmasterPorts(false);
 
-               /* Attach process to shared segments */
+               /* Attach process to shared data structures */
                CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
 
                BootstrapMain(argc - 2, argv + 2);
@@ -2975,6 +3277,7 @@ SubPostmasterMain(int argc, char *argv[])
 
        return 1;                                       /* shouldn't get here */
 }
+
 #endif   /* EXEC_BACKEND */
 
 
@@ -3301,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))
@@ -3317,191 +3620,279 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
 #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
 
-       write_var(MyCancelKey, fp);
+       memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
 
-       write_var(UsedShmemSegID, fp);
-       write_var(UsedShmemSegAddr, fp);
+       StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
 
-       write_var(ShmemLock, fp);
-       write_var(ShmemIndexLock, fp);
-       write_var(ShmemVariableCache, fp);
-       write_var(ShmemIndexAlloc, fp);
-       write_var(ShmemBackendArray, fp);
+       StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
 
-       write_var(LWLockArray, fp);
-       write_var(ProcStructLock, fp);
-       write_var(pgStatSock, 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(debug_flag, fp);
-       write_var(PostmasterPid, fp);
-#ifdef WIN32
-       write_var(PostmasterHandle, fp);
-#endif
+       return true;
+}
 
-       write_var(syslogPipe[0], fp);
-       write_var(syslogPipe[1], fp);
 
-       StrNCpy(str_buf, my_exec_path, MAXPGPATH);
-       write_array_var(str_buf, fp);
+#ifdef WIN32
+/*
+ * Duplicate a handle for usage in a child process, and write the child
+ * process instance of the handle to the parameter file.
+ */
+static void
+write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess)
+{
+       HANDLE hChild = INVALID_HANDLE_VALUE;
+
+       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())));
 
-       write_array_var(ExtraOptions, fp);
+       *dest = hChild;
+}
 
-       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);
+/*
+ * 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())));
+       }
+}
 
-       /* Release file */
-       if (FreeFile(fp))
+/*
+ * Read a duplicate socket structure back, and get the socket descriptor.
+ */
+static void
+read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
+{
+       SOCKET s;
+
+       if (src->origsocket == -1  || src->origsocket == 0)
        {
-               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);
+       }
+
+       /* Release file */
+       FreeFile(fp);
+       if (unlink(id) != 0)
+       {
+               write_stderr("could not remove file \"%s\": %s\n",
+                                        id, strerror(errno));
+               exit(1);
+       }
+#else
+       /* Win32 version uses mapped file */
+       HANDLE paramHandle;
+       BackendParameters *paramp;
+
+       paramHandle = (HANDLE)atol(id);
+       paramp = MapViewOfFile(paramHandle, FILE_MAP_READ, 0, 0, 0);
+       if (!paramp)
+       {
+               write_stderr("could not map view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+
+       memcpy(&param, paramp, sizeof(BackendParameters));
+
+       if (!UnmapViewOfFile(paramp))
+       {
+               write_stderr("could not unmap view of backend variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+
+       if (!CloseHandle(paramHandle))
+       {
+               write_stderr("could not close handle to backend parameter variables: error code %d\n",
+                                        (int) GetLastError());
+               exit(1);
+       }
+#endif
+
+       restore_backend_variables(&param, port);
+}
 
-       read_array_var(str_buf, fp);
-       SetDataDir(str_buf);
+/* Restore critical backend variables from the BackendParameters struct */
+static void
+restore_backend_variables(BackendParameters *param, Port *port)
+{
+       memcpy(port, &param->port, sizeof(Port));
+       read_inheritable_socket(&port->sock, &param->portsocket);
+
+       SetDataDir(param->DataDir);
 
-       read_array_var(ListenSocket, fp);
+       memcpy(&ListenSocket, &param->ListenSocket, sizeof(ListenSocket));
 
-       read_var(MyCancelKey, fp);
+       MyCancelKey = param->MyCancelKey;
 
-       read_var(UsedShmemSegID, fp);
-       read_var(UsedShmemSegAddr, fp);
+       UsedShmemSegID = param->UsedShmemSegID;
+       UsedShmemSegAddr = param->UsedShmemSegAddr;
 
-       read_var(ShmemLock, fp);
-       read_var(ShmemIndexLock, fp);
-       read_var(ShmemVariableCache, fp);
-       read_var(ShmemIndexAlloc, fp);
-       read_var(ShmemBackendArray, fp);
+       ShmemLock = param->ShmemLock;
+       ShmemIndexLock = param->ShmemIndexLock;
+       ShmemVariableCache = param->ShmemVariableCache;
+       ShmemIndexAlloc = param->ShmemIndexAlloc;
+       ShmemBackendArray = param->ShmemBackendArray;
 
-       read_var(LWLockArray, fp);
-       read_var(ProcStructLock, fp);
-       read_var(pgStatSock, fp);
+       LWLockArray = param->LWLockArray;
+       ProcStructLock = param->ProcStructLock;
+       read_inheritable_socket(&pgStatSock, &param->pgStatSock);
+       read_inheritable_socket(&pgStatPipe[0], &param->pgStatPipe0);
+       read_inheritable_socket(&pgStatPipe[1], &param->pgStatPipe1);
+
+       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_var(syslogPipe[0], fp);
-       read_var(syslogPipe[1], fp);
-
-       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);
 }
 
 
@@ -3559,79 +3950,12 @@ ShmemBackendArrayRemove(pid_t pid)
                        (errmsg_internal("could not find backend entry with pid %d",
                                                         (int) pid)));
 }
+
 #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)
@@ -3702,14 +4026,14 @@ win32_waitpid(int *exitstatus)
 
        for (offset = 0; offset < win32_numChildren; offset += MAXIMUM_WAIT_OBJECTS)
        {
-               unsigned long num = min(MAXIMUM_WAIT_OBJECTS, win32_numChildren - offset);
+               unsigned long num = Min(MAXIMUM_WAIT_OBJECTS, win32_numChildren - offset);
 
                ret = WaitForMultipleObjects(num, &win32_childHNDArray[offset], FALSE, 0);
                switch (ret)
                {
                        case WAIT_FAILED:
                                ereport(LOG,
-                                               (errmsg_internal("failed to wait on %lu of %lu children: %d",
+                                               (errmsg_internal("failed to wait on %lu of %lu children: error code %d",
                                                 num, win32_numChildren, (int) GetLastError())));
                                return -1;
 
@@ -3734,7 +4058,7 @@ 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];
@@ -3759,7 +4083,7 @@ win32_sigchld_waiter(LPVOID param)
        if (r == WAIT_OBJECT_0)
                pg_queue_signal(SIGCHLD);
        else
-               write_stderr("could not wait on child process handle: %d\n",
+               write_stderr("could not wait on child process handle: error code %d\n",
                                         (int) GetLastError());
        CloseHandle(procHandle);
        return 0;