Refactor postmaster child process launching
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 18 Mar 2024 09:35:08 +0000 (11:35 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 18 Mar 2024 09:35:30 +0000 (11:35 +0200)
Introduce new postmaster_child_launch() function that deals with the
differences in EXEC_BACKEND mode.

Refactor the mechanism of passing information from the parent to child
process. Instead of using different command-line arguments when
launching the child process in EXEC_BACKEND mode, pass a
variable-length blob of startup data along with all the global
variables. The contents of that blob depend on the kind of child
process being launched. In !EXEC_BACKEND mode, we use the same blob,
but it's simply inherited from the parent to child process.

Reviewed-by: Tristan Partin, Andres Freund
Discussion: https://www.postgresql.org/message-id/7a59b073-5b5b-151e-7ed3-8b01ff7ce9ef@iki.fi

28 files changed:
src/backend/postmaster/autovacuum.c
src/backend/postmaster/auxprocess.c
src/backend/postmaster/bgworker.c
src/backend/postmaster/bgwriter.c
src/backend/postmaster/checkpointer.c
src/backend/postmaster/launch_backend.c
src/backend/postmaster/pgarch.c
src/backend/postmaster/postmaster.c
src/backend/postmaster/startup.c
src/backend/postmaster/syslogger.c
src/backend/postmaster/walsummarizer.c
src/backend/postmaster/walwriter.c
src/backend/replication/logical/slotsync.c
src/backend/replication/walreceiver.c
src/backend/utils/init/globals.c
src/include/postmaster/autovacuum.h
src/include/postmaster/auxprocess.h
src/include/postmaster/bgworker_internals.h
src/include/postmaster/bgwriter.h
src/include/postmaster/pgarch.h
src/include/postmaster/postmaster.h
src/include/postmaster/startup.h
src/include/postmaster/syslogger.h
src/include/postmaster/walsummarizer.h
src/include/postmaster/walwriter.h
src/include/replication/slotsync.h
src/include/replication/walreceiver.h
src/tools/pgindent/typedefs.list

index 046ab46eccadf6bed165ea082fb2d99a40cb76a9..71e8a6f258476a03cfffdcb16640899c916adc7c 100644 (file)
@@ -85,7 +85,6 @@
 #include "nodes/makefuncs.h"
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
-#include "postmaster/fork_process.h"
 #include "postmaster/interrupt.h"
 #include "postmaster/postmaster.h"
 #include "storage/bufmgr.h"
@@ -311,13 +310,6 @@ static WorkerInfo MyWorkerInfo = NULL;
 /* PID of launcher, valid only in worker while shutting down */
 int                    AutovacuumLauncherPid = 0;
 
-#ifdef EXEC_BACKEND
-static pid_t avlauncher_forkexec(void);
-static pid_t avworker_forkexec(void);
-#endif
-NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
-NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
-
 static Oid     do_start_worker(void);
 static void HandleAutoVacLauncherInterrupts(void);
 static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
@@ -361,76 +353,23 @@ static void avl_sigusr2_handler(SIGNAL_ARGS);
  *                                       AUTOVACUUM LAUNCHER CODE
  ********************************************************************/
 
-#ifdef EXEC_BACKEND
 /*
- * forkexec routine for the autovacuum launcher process.
- *
- * Format up the arglist, then fork and exec.
+ * Main entry point for the autovacuum launcher process.
  */
-static pid_t
-avlauncher_forkexec(void)
+void
+AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
 {
-       char       *av[10];
-       int                     ac = 0;
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forkavlauncher";
-       av[ac++] = NULL;                        /* filled in by postmaster_forkexec */
-       av[ac] = NULL;
-
-       Assert(ac < lengthof(av));
-
-       return postmaster_forkexec(ac, av);
-}
-#endif
+       sigjmp_buf      local_sigjmp_buf;
 
-/*
- * Main entry point for autovacuum launcher process, to be called from the
- * postmaster.
- */
-int
-StartAutoVacLauncher(void)
-{
-       pid_t           AutoVacPID;
+       Assert(startup_data_len == 0);
 
-#ifdef EXEC_BACKEND
-       switch ((AutoVacPID = avlauncher_forkexec()))
-#else
-       switch ((AutoVacPID = fork_process()))
-#endif
+       /* Release postmaster's working memory context */
+       if (PostmasterContext)
        {
-               case -1:
-                       ereport(LOG,
-                                       (errmsg("could not fork autovacuum launcher process: %m")));
-                       return 0;
-
-#ifndef EXEC_BACKEND
-               case 0:
-                       /* in postmaster child ... */
-                       InitPostmasterChild();
-
-                       /* Close the postmaster's sockets */
-                       ClosePostmasterPorts(false);
-
-                       AutoVacLauncherMain(0, NULL);
-                       break;
-#endif
-               default:
-                       return (int) AutoVacPID;
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
        }
 
-       /* shouldn't get here */
-       return 0;
-}
-
-/*
- * Main loop for the autovacuum launcher process.
- */
-NON_EXEC_STATIC void
-AutoVacLauncherMain(int argc, char *argv[])
-{
-       sigjmp_buf      local_sigjmp_buf;
-
        MyBackendType = B_AUTOVAC_LAUNCHER;
        init_ps_display(NULL);
 
@@ -1412,78 +1351,24 @@ avl_sigusr2_handler(SIGNAL_ARGS)
  *                                       AUTOVACUUM WORKER CODE
  ********************************************************************/
 
-#ifdef EXEC_BACKEND
 /*
- * forkexec routines for the autovacuum worker.
- *
- * Format up the arglist, then fork and exec.
+ * Main entry point for autovacuum worker processes.
  */
-static pid_t
-avworker_forkexec(void)
+void
+AutoVacWorkerMain(char *startup_data, size_t startup_data_len)
 {
-       char       *av[10];
-       int                     ac = 0;
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forkavworker";
-       av[ac++] = NULL;                        /* filled in by postmaster_forkexec */
-       av[ac] = NULL;
-
-       Assert(ac < lengthof(av));
-
-       return postmaster_forkexec(ac, av);
-}
-#endif
+       sigjmp_buf      local_sigjmp_buf;
+       Oid                     dbid;
 
-/*
- * Main entry point for autovacuum worker process.
- *
- * This code is heavily based on pgarch.c, q.v.
- */
-int
-StartAutoVacWorker(void)
-{
-       pid_t           worker_pid;
+       Assert(startup_data_len == 0);
 
-#ifdef EXEC_BACKEND
-       switch ((worker_pid = avworker_forkexec()))
-#else
-       switch ((worker_pid = fork_process()))
-#endif
+       /* Release postmaster's working memory context */
+       if (PostmasterContext)
        {
-               case -1:
-                       ereport(LOG,
-                                       (errmsg("could not fork autovacuum worker process: %m")));
-                       return 0;
-
-#ifndef EXEC_BACKEND
-               case 0:
-                       /* in postmaster child ... */
-                       InitPostmasterChild();
-
-                       /* Close the postmaster's sockets */
-                       ClosePostmasterPorts(false);
-
-                       AutoVacWorkerMain(0, NULL);
-                       break;
-#endif
-               default:
-                       return (int) worker_pid;
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
        }
 
-       /* shouldn't get here */
-       return 0;
-}
-
-/*
- * AutoVacWorkerMain
- */
-NON_EXEC_STATIC void
-AutoVacWorkerMain(int argc, char *argv[])
-{
-       sigjmp_buf      local_sigjmp_buf;
-       Oid                     dbid;
-
        MyBackendType = B_AUTOVAC_WORKER;
        init_ps_display(NULL);
 
index 2c86abdb719a56319f6d9ddbb97b91c7c81b881e..78f4263eeb1291266701ce8be02a59abe002b68d 100644 (file)
@@ -27,6 +27,7 @@
 #include "storage/ipc.h"
 #include "storage/proc.h"
 #include "storage/procsignal.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 
 
@@ -34,19 +35,22 @@ static void ShutdownAuxiliaryProcess(int code, Datum arg);
 
 
 /*
- *      AuxiliaryProcessMain
+ *      AuxiliaryProcessMainCommon
  *
- *      The main entry point for auxiliary processes, such as the bgwriter,
- *      walwriter, walreceiver, bootstrapper and the shared memory checker code.
- *
- *      This code is here just because of historical reasons.
+ *      Common initialization code for auxiliary processes, such as the bgwriter,
+ *      walwriter, walreceiver, and the startup process.
  */
 void
-AuxiliaryProcessMain(BackendType auxtype)
+AuxiliaryProcessMainCommon(void)
 {
        Assert(IsUnderPostmaster);
 
-       MyBackendType = auxtype;
+       /* Release postmaster's working memory context */
+       if (PostmasterContext)
+       {
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
+       }
 
        init_ps_display(NULL);
 
@@ -84,41 +88,6 @@ AuxiliaryProcessMain(BackendType auxtype)
        before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 
        SetProcessingMode(NormalProcessing);
-
-       switch (MyBackendType)
-       {
-               case B_STARTUP:
-                       StartupProcessMain();
-                       proc_exit(1);
-
-               case B_ARCHIVER:
-                       PgArchiverMain();
-                       proc_exit(1);
-
-               case B_BG_WRITER:
-                       BackgroundWriterMain();
-                       proc_exit(1);
-
-               case B_CHECKPOINTER:
-                       CheckpointerMain();
-                       proc_exit(1);
-
-               case B_WAL_WRITER:
-                       WalWriterMain();
-                       proc_exit(1);
-
-               case B_WAL_RECEIVER:
-                       WalReceiverMain();
-                       proc_exit(1);
-
-               case B_WAL_SUMMARIZER:
-                       WalSummarizerMain();
-                       proc_exit(1);
-
-               default:
-                       elog(PANIC, "unrecognized process type: %d", (int) MyBackendType);
-                       proc_exit(1);
-       }
 }
 
 /*
index b73e91f0c867d0cf27f85f9ae8b9cdb9f8d5f3e4..cf64a4beb2016ac0dbb9bbcc0d01faea5a0d71bd 100644 (file)
@@ -720,15 +720,29 @@ bgworker_die(SIGNAL_ARGS)
  * Main entry point for background worker processes.
  */
 void
-BackgroundWorkerMain(void)
+BackgroundWorkerMain(char *startup_data, size_t startup_data_len)
 {
        sigjmp_buf      local_sigjmp_buf;
-       BackgroundWorker *worker = MyBgworkerEntry;
+       BackgroundWorker *worker;
        bgworker_main_type entrypt;
 
-       if (worker == NULL)
+       if (startup_data == NULL)
                elog(FATAL, "unable to find bgworker entry");
+       Assert(startup_data_len == sizeof(BackgroundWorker));
+       worker = MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
+       memcpy(worker, startup_data, sizeof(BackgroundWorker));
 
+       /*
+        * Now that we're done reading the startup data, release postmaster's
+        * working memory context.
+        */
+       if (PostmasterContext)
+       {
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
+       }
+
+       MyBgworkerEntry = worker;
        MyBackendType = B_BG_WORKER;
        init_ps_display(worker->bgw_name);
 
index da2d95b9261afafc46611477cc2e736f50062602..0f75548759a361aa6cf790eb9943a70cad8b13fe 100644 (file)
@@ -35,6 +35,7 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/interrupt.h"
 #include "storage/buf_internals.h"
@@ -83,13 +84,18 @@ static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr;
  * basic execution environment, but not enabled signals yet.
  */
 void
-BackgroundWriterMain(void)
+BackgroundWriterMain(char *startup_data, size_t startup_data_len)
 {
        sigjmp_buf      local_sigjmp_buf;
        MemoryContext bgwriter_context;
        bool            prev_hibernate;
        WritebackContext wb_context;
 
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_BG_WRITER;
+       AuxiliaryProcessMainCommon();
+
        /*
         * Properly accept or ignore signals that might be sent to us.
         */
index 46197d56f861cd35ea49ccaa0a2850d7f2047ec6..8ef600ae72aa3529628618fa17f4ab0275669ea2 100644 (file)
@@ -42,6 +42,7 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/interrupt.h"
 #include "replication/syncrep.h"
@@ -169,11 +170,16 @@ static void ReqCheckpointHandler(SIGNAL_ARGS);
  * basic execution environment, but not enabled signals yet.
  */
 void
-CheckpointerMain(void)
+CheckpointerMain(char *startup_data, size_t startup_data_len)
 {
        sigjmp_buf      local_sigjmp_buf;
        MemoryContext checkpointer_context;
 
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_CHECKPOINTER;
+       AuxiliaryProcessMainCommon();
+
        CheckpointerShmem->checkpointer_pid = MyProcPid;
 
        /*
index 80c96e708d7d83f4afda7b74997913b642439afc..d159096a584a7b2f16d43c7971061822d9ab7b28 100644 (file)
@@ -49,7 +49,9 @@
 #include "postmaster/postmaster.h"
 #include "postmaster/startup.h"
 #include "postmaster/syslogger.h"
+#include "postmaster/walsummarizer.h"
 #include "postmaster/walwriter.h"
+#include "replication/slotsync.h"
 #include "replication/walreceiver.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
@@ -89,13 +91,6 @@ typedef int InheritableSocket;
  */
 typedef struct
 {
-       bool            has_client_sock;
-       ClientSocket client_sock;
-       InheritableSocket inh_sock;
-
-       bool            has_bgworker;
-       BackgroundWorker bgworker;
-
        char            DataDir[MAXPGPATH];
        int32           MyCancelKey;
        int                     MyPMChildSlot;
@@ -138,22 +133,144 @@ typedef struct
 #endif
        char            my_exec_path[MAXPGPATH];
        char            pkglib_path[MAXPGPATH];
+
+       /*
+        * These are only used by backend processes, but are here because passing
+        * a socket needs some special handling on Windows. 'client_sock' is an
+        * explicit argument to postmaster_child_launch, but is stored in
+        * MyClientSocket in the child process.
+        */
+       ClientSocket client_sock;
+       InheritableSocket inh_sock;
+
+       /*
+        * Extra startup data, content depends on the child process.
+        */
+       size_t          startup_data_len;
+       char            startup_data[FLEXIBLE_ARRAY_MEMBER];
 } BackendParameters;
 
 #define SizeOfBackendParameters(startup_data_len) (offsetof(BackendParameters, startup_data) + startup_data_len)
 
-void           read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker);
-static void restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker);
+static void read_backend_variables(char *id, char **startup_data, size_t *startup_data_len);
+static void restore_backend_variables(BackendParameters *param);
 
-#ifndef WIN32
-static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker);
-#else
-static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
-                                                                  HANDLE childProcess, pid_t childPid);
+static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
+#ifdef WIN32
+                                                                  HANDLE childProcess, pid_t childPid,
 #endif
+                                                                  char *startup_data, size_t startup_data_len);
+
+static pid_t internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock);
+
+#endif                                                 /* EXEC_BACKEND */
+
+/*
+ * Information needed to launch different kinds of child processes.
+ */
+typedef struct
+{
+       const char *name;
+       void            (*main_fn) (char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+       bool            shmem_attach;
+} child_process_kind;
+
+child_process_kind child_process_kinds[] = {
+       [B_INVALID] = {"invalid", NULL, false},
+
+       [B_BACKEND] = {"backend", BackendMain, true},
+       [B_AUTOVAC_LAUNCHER] = {"autovacuum launcher", AutoVacLauncherMain, true},
+       [B_AUTOVAC_WORKER] = {"autovacuum worker", AutoVacWorkerMain, true},
+       [B_BG_WORKER] = {"bgworker", BackgroundWorkerMain, true},
+
+       /*
+        * WAL senders start their life as regular backend processes, and change
+        * their type after authenticating the client for replication.  We list it
+        * here forPostmasterChildName() but cannot launch them directly.
+        */
+       [B_WAL_SENDER] = {"wal sender", NULL, true},
+       [B_SLOTSYNC_WORKER] = {"slot sync worker", ReplSlotSyncWorkerMain, true},
+
+       [B_STANDALONE_BACKEND] = {"standalone backend", NULL, false},
+
+       [B_ARCHIVER] = {"archiver", PgArchiverMain, true},
+       [B_BG_WRITER] = {"bgwriter", BackgroundWriterMain, true},
+       [B_CHECKPOINTER] = {"checkpointer", CheckpointerMain, true},
+       [B_STARTUP] = {"startup", StartupProcessMain, true},
+       [B_WAL_RECEIVER] = {"wal_receiver", WalReceiverMain, true},
+       [B_WAL_SUMMARIZER] = {"wal_summarizer", WalSummarizerMain, true},
+       [B_WAL_WRITER] = {"wal_writer", WalWriterMain, true},
+
+       [B_LOGGER] = {"syslogger", SysLoggerMain, false},
+};
+
+const char *
+PostmasterChildName(BackendType child_type)
+{
+       Assert(child_type >= 0 && child_type < lengthof(child_process_kinds));
+       return child_process_kinds[child_type].name;
+}
+
+/*
+ * Start a new postmaster child process.
+ *
+ * The child process will be restored to roughly the same state whether
+ * EXEC_BACKEND is used or not: it will be attached to shared memory, and fds
+ * and other resources that we've inherited from postmaster that are not
+ * needed in a child process have been closed.
+ *
+ * 'startup_data' is an optional contiguous chunk of data that is passed to
+ * the child process.
+ */
+pid_t
+postmaster_child_launch(BackendType child_type,
+                                               char *startup_data, size_t startup_data_len,
+                                               ClientSocket *client_sock)
+{
+       pid_t           pid;
+
+       Assert(child_type >= 0 && child_type < lengthof(child_process_kinds));
+       Assert(IsPostmasterEnvironment && !IsUnderPostmaster);
+
+#ifdef EXEC_BACKEND
+       pid = internal_forkexec(child_process_kinds[child_type].name,
+                                                       startup_data, startup_data_len, client_sock);
+       /* the child process will arrive in SubPostmasterMain */
+#else                                                  /* !EXEC_BACKEND */
+       pid = fork_process();
+       if (pid == 0)                           /* child */
+       {
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(child_type == B_LOGGER);
+
+               /* Detangle from postmaster */
+               InitPostmasterChild();
 
-pid_t          internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker);
+               /*
+                * Enter the Main function with TopMemoryContext.  The startup data is
+                * allocated in PostmasterContext, so we cannot release it here yet.
+                * The Main function will do it after it's done handling the startup
+                * data.
+                */
+               MemoryContextSwitchTo(TopMemoryContext);
 
+               if (client_sock)
+               {
+                       MyClientSocket = palloc(sizeof(ClientSocket));
+                       memcpy(MyClientSocket, client_sock, sizeof(ClientSocket));
+               }
+
+               /*
+                * Run the appropriate Main function
+                */
+               child_process_kinds[child_type].main_fn(startup_data, startup_data_len);
+               pg_unreachable();               /* main_fn never returns */
+       }
+#endif                                                 /* EXEC_BACKEND */
+       return pid;
+}
+
+#ifdef EXEC_BACKEND
 #ifndef WIN32
 
 /*
@@ -162,25 +279,32 @@ pid_t             internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, Back
  * - writes out backend variables to the parameter file
  * - fork():s, and then exec():s the child process
  */
-pid_t
-internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
+static pid_t
+internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
 {
        static unsigned long tmpBackendFileNum = 0;
        pid_t           pid;
        char            tmpfilename[MAXPGPATH];
-       BackendParameters param;
+       size_t          paramsz;
+       BackendParameters *param;
        FILE       *fp;
+       char       *argv[4];
+       char            forkav[MAXPGPATH];
 
        /*
-        * Make sure padding bytes are initialized, to prevent Valgrind from
-        * complaining about writing uninitialized bytes to the file.  This isn't
-        * performance critical, and the win32 implementation initializes the
-        * padding bytes to zeros, so do it even when not using Valgrind.
+        * Use palloc0 to make sure padding bytes are initialized, to prevent
+        * Valgrind from complaining about writing uninitialized bytes to the
+        * file.  This isn't performance critical, and the win32 implementation
+        * initializes the padding bytes to zeros, so do it even when not using
+        * Valgrind.
         */
-       memset(&param, 0, sizeof(BackendParameters));
-
-       if (!save_backend_variables(&param, client_sock, worker))
+       paramsz = SizeOfBackendParameters(startup_data_len);
+       param = palloc0(paramsz);
+       if (!save_backend_variables(param, client_sock, startup_data, startup_data_len))
+       {
+               pfree(param);
                return -1;                              /* log made by save_backend_variables */
+       }
 
        /* Calculate name for temp file */
        snprintf(tmpfilename, MAXPGPATH, "%s/%s.backend_var.%d.%lu",
@@ -204,18 +328,21 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
                                        (errcode_for_file_access(),
                                         errmsg("could not create file \"%s\": %m",
                                                        tmpfilename)));
+                       pfree(param);
                        return -1;
                }
        }
 
-       if (fwrite(&param, sizeof(param), 1, fp) != 1)
+       if (fwrite(param, paramsz, 1, fp) != 1)
        {
                ereport(LOG,
                                (errcode_for_file_access(),
                                 errmsg("could not write to file \"%s\": %m", tmpfilename)));
                FreeFile(fp);
+               pfree(param);
                return -1;
        }
+       pfree(param);
 
        /* Release file */
        if (FreeFile(fp))
@@ -226,14 +353,13 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
                return -1;
        }
 
-       /* Make sure caller set up argv properly */
-       Assert(argc >= 3);
-       Assert(argv[argc] == NULL);
-       Assert(strncmp(argv[1], "--fork", 6) == 0);
-       Assert(argv[2] == NULL);
-
-       /* Insert temp file name after --fork argument */
+       /* set up argv properly */
+       argv[0] = "postgres";
+       snprintf(forkav, MAXPGPATH, "--forkchild=%s", child_kind);
+       argv[1] = forkav;
+       /* Insert temp file name after --forkchild argument */
        argv[2] = tmpfilename;
+       argv[3] = NULL;
 
        /* Fire off execv in child */
        if ((pid = fork_process()) == 0)
@@ -262,25 +388,21 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
  * - resumes execution of the new process once the backend parameter
  *      file is complete.
  */
-pid_t
-internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
+static pid_t
+internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
 {
        int                     retry_count = 0;
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
-       int                     i;
-       int                     j;
        char            cmdLine[MAXPGPATH * 2];
        HANDLE          paramHandle;
        BackendParameters *param;
        SECURITY_ATTRIBUTES sa;
+       size_t          paramsz;
        char            paramHandleStr[32];
+       int                     l;
 
-       /* Make sure caller set up argv properly */
-       Assert(argc >= 3);
-       Assert(argv[argc] == NULL);
-       Assert(strncmp(argv[1], "--fork", 6) == 0);
-       Assert(argv[2] == NULL);
+       paramsz = SizeOfBackendParameters(startup_data_len);
 
        /* Resume here if we need to retry */
 retry:
@@ -293,7 +415,7 @@ retry:
                                                                        &sa,
                                                                        PAGE_READWRITE,
                                                                        0,
-                                                                       sizeof(BackendParameters),
+                                                                       paramsz,
                                                                        NULL);
        if (paramHandle == INVALID_HANDLE_VALUE)
        {
@@ -302,8 +424,7 @@ retry:
                                                GetLastError())));
                return -1;
        }
-
-       param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
+       param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, paramsz);
        if (!param)
        {
                ereport(LOG,
@@ -313,25 +434,15 @@ retry:
                return -1;
        }
 
-       /* Insert temp file name after --fork argument */
+       /* Format the cmd line */
 #ifdef _WIN64
        sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
 #else
        sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
 #endif
-       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')
+       l = snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\" --forkchild=\"%s\" %s",
+                                postgres_exec_path, child_kind, paramHandleStr);
+       if (l >= sizeof(cmdLine))
        {
                ereport(LOG,
                                (errmsg("subprocess command line too long")));
@@ -359,7 +470,7 @@ retry:
                return -1;
        }
 
-       if (!save_backend_variables(param, client_sock, worker, pi.hProcess, pi.dwProcessId))
+       if (!save_backend_variables(param, client_sock, pi.hProcess, pi.dwProcessId, startup_data, startup_data_len))
        {
                /*
                 * log made by save_backend_variables, but we have to clean up the
@@ -445,6 +556,119 @@ retry:
 }
 #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 "--forkchild=<name>",
+ * where <name> 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.
+ */
+void
+SubPostmasterMain(int argc, char *argv[])
+{
+       char       *startup_data;
+       size_t          startup_data_len;
+       char       *child_kind;
+       BackendType child_type;
+       bool            found = false;
+
+       /* In EXEC_BACKEND case we will not have inherited these settings */
+       IsPostmasterEnvironment = true;
+       whereToSendOutput = DestNone;
+
+       /* Setup essential subsystems (to ensure elog() behaves sanely) */
+       InitializeGUCOptions();
+
+       /* Check we got appropriate args */
+       if (argc != 3)
+               elog(FATAL, "invalid subpostmaster invocation");
+
+       /* Find the entry in child_process_kinds */
+       if (strncmp(argv[1], "--forkchild=", 12) != 0)
+               elog(FATAL, "invalid subpostmaster invocation (--forkchild argument missing)");
+       child_kind = argv[1] + 12;
+       found = false;
+       for (int idx = 0; idx < lengthof(child_process_kinds); idx++)
+       {
+               if (strcmp(child_process_kinds[idx].name, child_kind) == 0)
+               {
+                       child_type = (BackendType) idx;
+                       found = true;
+                       break;
+               }
+       }
+       if (!found)
+               elog(ERROR, "unknown child kind %s", child_kind);
+
+       /* Read in the variables file */
+       read_backend_variables(argv[2], &startup_data, &startup_data_len);
+
+       /* Close the postmaster's sockets (as soon as we know them) */
+       ClosePostmasterPorts(child_type == B_LOGGER);
+
+       /* Setup as postmaster child */
+       InitPostmasterChild();
+
+       /*
+        * 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.  On the other hand, if we choose not
+        * to re-attach, we may have other cleanup to do.
+        *
+        * If testing EXEC_BACKEND on Linux, you should run this as root before
+        * starting the postmaster:
+        *
+        * sysctl -w kernel.randomize_va_space=0
+        *
+        * This prevents using randomized stack and code addresses that cause the
+        * child process's memory map to be different from the parent's, making it
+        * sometimes impossible to attach to shared memory at the desired address.
+        * Return the setting to its old value (usually '1' or '2') when finished.
+        */
+       if (child_process_kinds[child_type].shmem_attach)
+               PGSharedMemoryReAttach();
+       else
+               PGSharedMemoryNoReAttach();
+
+       /* Read in remaining GUC variables */
+       read_nondefault_variables();
+
+       /*
+        * Check that the data directory looks valid, which will also check the
+        * privileges on the data directory and update our umask and file/group
+        * variables for creating files later.  Note: this should really be done
+        * before we create any files or directories.
+        */
+       checkDataDir();
+
+       /*
+        * (re-)read control file, as it contains config. The postmaster will
+        * already have read this, but this process doesn't know about that.
+        */
+       LocalProcessControlFile(false);
+
+       /*
+        * Reload any libraries that were preloaded by the postmaster.  Since we
+        * exec'd this process, those libraries didn't come along with us; but we
+        * should load them into all child processes to be consistent with the
+        * non-EXEC_BACKEND behavior.
+        */
+       process_shared_preload_libraries();
+
+       /* Restore basic shared memory pointers */
+       if (UsedShmemSegAddr != NULL)
+               InitShmemAccess(UsedShmemSegAddr);
+
+       /*
+        * Run the appropriate Main function
+        */
+       child_process_kinds[child_type].main_fn(startup_data, startup_data_len);
+       pg_unreachable();                       /* main_fn never returns */
+}
+
 /*
  * The following need to be available to the save/restore_backend_variables
  * functions.  They are marked NON_EXEC_STATIC in their home modules.
@@ -469,38 +693,21 @@ static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
 
 
 /* Save critical backend variables into the BackendParameters struct */
-#ifndef WIN32
-static bool
-save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker)
-#else
 static bool
-save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
-                                          HANDLE childProcess, pid_t childPid)
+save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
+#ifdef WIN32
+                                          HANDLE childProcess, pid_t childPid,
 #endif
+                                          char *startup_data, size_t startup_data_len)
 {
        if (client_sock)
-       {
                memcpy(&param->client_sock, client_sock, sizeof(ClientSocket));
-               if (!write_inheritable_socket(&param->inh_sock, client_sock->sock, childPid))
-                       return false;
-               param->has_client_sock = true;
-       }
        else
-       {
                memset(&param->client_sock, 0, sizeof(ClientSocket));
-               param->has_client_sock = false;
-       }
-
-       if (worker)
-       {
-               memcpy(&param->bgworker, worker, sizeof(BackgroundWorker));
-               param->has_bgworker = true;
-       }
-       else
-       {
-               memset(&param->bgworker, 0, sizeof(BackgroundWorker));
-               param->has_bgworker = false;
-       }
+       if (!write_inheritable_socket(&param->inh_sock,
+                                                                 client_sock ? client_sock->sock : PGINVALID_SOCKET,
+                                                                 childPid))
+               return false;
 
        strlcpy(param->DataDir, DataDir, MAXPGPATH);
 
@@ -557,6 +764,9 @@ save_backend_variables(BackendParameters *param, ClientSocket *client_sock, Back
 
        strlcpy(param->pkglib_path, pkglib_path, MAXPGPATH);
 
+       param->startup_data_len = startup_data_len;
+       memcpy(param->startup_data, startup_data, startup_data_len);
+
        return true;
 }
 
@@ -653,8 +863,8 @@ read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
 }
 #endif
 
-void
-read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker)
+static void
+read_backend_variables(char *id, char **startup_data, size_t *startup_data_len)
 {
        BackendParameters param;
 
@@ -676,6 +886,21 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
                exit(1);
        }
 
+       /* read startup data */
+       *startup_data_len = param.startup_data_len;
+       if (param.startup_data_len > 0)
+       {
+               *startup_data = palloc(*startup_data_len);
+               if (fread(*startup_data, *startup_data_len, 1, fp) != 1)
+               {
+                       write_stderr("could not read startup data from backend variables file \"%s\": %m\n",
+                                                id);
+                       exit(1);
+               }
+       }
+       else
+               *startup_data = NULL;
+
        /* Release file */
        FreeFile(fp);
        if (unlink(id) != 0)
@@ -703,6 +928,16 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
 
        memcpy(&param, paramp, sizeof(BackendParameters));
 
+       /* read startup data */
+       *startup_data_len = param.startup_data_len;
+       if (param.startup_data_len > 0)
+       {
+               *startup_data = palloc(paramp->startup_data_len);
+               memcpy(*startup_data, paramp->startup_data, param.startup_data_len);
+       }
+       else
+               *startup_data = NULL;
+
        if (!UnmapViewOfFile(paramp))
        {
                write_stderr("could not unmap view of backend variables: error code %lu\n",
@@ -718,30 +953,19 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
        }
 #endif
 
-       restore_backend_variables(&param, client_sock, worker);
+       restore_backend_variables(&param);
 }
 
 /* Restore critical backend variables from the BackendParameters struct */
 static void
-restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker)
+restore_backend_variables(BackendParameters *param)
 {
-       if (param->has_client_sock)
-       {
-               *client_sock = (ClientSocket *) MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
-               memcpy(*client_sock, &param->client_sock, sizeof(ClientSocket));
-               read_inheritable_socket(&(*client_sock)->sock, &param->inh_sock);
-       }
-       else
-               *client_sock = NULL;
-
-       if (param->has_bgworker)
+       if (param->client_sock.sock != PGINVALID_SOCKET)
        {
-               *worker = (BackgroundWorker *)
-                       MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
-               memcpy(*worker, &param->bgworker, sizeof(BackgroundWorker));
+               MyClientSocket = MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
+               memcpy(MyClientSocket, &param->client_sock, sizeof(ClientSocket));
+               read_inheritable_socket(&MyClientSocket->sock, &param->inh_sock);
        }
-       else
-               *worker = NULL;
 
        SetDataDir(param->DataDir);
 
index f97035ca03cdc273f2a034042af3159da808ec63..c266904b579df976b05f14c2282ffd07071f55f6 100644 (file)
@@ -36,6 +36,7 @@
 #include "lib/binaryheap.h"
 #include "libpq/pqsignal.h"
 #include "pgstat.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/interrupt.h"
 #include "postmaster/pgarch.h"
 #include "storage/fd.h"
@@ -209,8 +210,13 @@ PgArchCanRestart(void)
 
 /* Main entry point for archiver process */
 void
-PgArchiverMain(void)
+PgArchiverMain(char *startup_data, size_t startup_data_len)
 {
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_ARCHIVER;
+       AuxiliaryProcessMainCommon();
+
        /*
         * Ignore all signals usually bound to some action in the postmaster,
         * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
index 6610bd5f866e921d12a89fca5303f3015591cd19..9a82c3dafaf684c3572e9c85ae5962496f11d28b 100644 (file)
@@ -2,9 +2,9 @@
  *
  * postmaster.c
  *       This program acts as a clearing house for requests to the
- *       POSTGRES system.  Frontend programs send a startup message
- *       to the Postmaster and the postmaster uses the info in the
- *       message to setup a backend process.
+ *       POSTGRES system.  Frontend programs connect to the Postmaster,
+ *       and postmaster forks a new backend process to handle the
+ *       connection.
  *
  *       The postmaster also manages system-wide operations such as
  *       startup and shutdown. The postmaster itself doesn't do those
 #include "postmaster/autovacuum.h"
 #include "postmaster/auxprocess.h"
 #include "postmaster/bgworker_internals.h"
-#include "postmaster/fork_process.h"
 #include "postmaster/pgarch.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
@@ -427,7 +426,6 @@ typedef enum CAC_state
 } CAC_state;
 
 static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
-static void BackendRun(void) pg_attribute_noreturn();
 static void ExitPostmaster(int status) pg_attribute_noreturn();
 static int     ServerLoop(void);
 static int     BackendStartup(ClientSocket *client_sock);
@@ -485,13 +483,6 @@ typedef struct
 } win32_deadchild_waitinfo;
 #endif                                                 /* WIN32 */
 
-static pid_t backend_forkexec(ClientSocket *client_sock, CAC_state cac);
-
-
-/* in launch_backend.c */
-extern pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker);
-extern void read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker);
-
 static void ShmemBackendArrayAdd(Backend *bn);
 static void ShmemBackendArrayRemove(Backend *bn);
 #endif                                                 /* EXEC_BACKEND */
@@ -1748,7 +1739,7 @@ ServerLoop(void)
                        (AutoVacuumingActive() || start_autovac_launcher) &&
                        pmState == PM_RUN)
                {
-                       AutoVacPID = StartAutoVacLauncher();
+                       AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
                        if (AutoVacPID != 0)
                                start_autovac_launcher = false; /* signal processed */
                }
@@ -2902,7 +2893,7 @@ process_pm_child_exit(void)
                         * situation, some of them may be alive already.
                         */
                        if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
-                               AutoVacPID = StartAutoVacLauncher();
+                               AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
                        if (PgArchStartupAllowed() && PgArchPID == 0)
                                PgArchPID = StartChildProcess(B_ARCHIVER);
                        MaybeStartSlotSyncWorker();
@@ -3964,6 +3955,12 @@ TerminateChildren(int signal)
                signal_child(SlotSyncWorkerPID, signal);
 }
 
+/* Information passed from postmaster to backend process */
+typedef struct BackendStartupData
+{
+       CAC_state       canAcceptConnections;
+} BackendStartupData;
+
 /*
  * BackendStartup -- start backend process
  *
@@ -3976,7 +3973,7 @@ BackendStartup(ClientSocket *client_sock)
 {
        Backend    *bn;                         /* for backend cleanup */
        pid_t           pid;
-       CAC_state       cac;
+       BackendStartupData startup_data;
 
        /*
         * Create backend data structure.  Better before the fork() so we can
@@ -4005,11 +4002,10 @@ BackendStartup(ClientSocket *client_sock)
                return STATUS_ERROR;
        }
 
-       bn->cancel_key = MyCancelKey;
-
        /* Pass down canAcceptConnections state */
-       cac = canAcceptConnections(BACKEND_TYPE_NORMAL);
-       bn->dead_end = (cac != CAC_OK);
+       startup_data.canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
+       bn->dead_end = (startup_data.canAcceptConnections != CAC_OK);
+       bn->cancel_key = MyCancelKey;
 
        /*
         * Unless it's a dead_end child, assign it a child slot number
@@ -4022,26 +4018,9 @@ BackendStartup(ClientSocket *client_sock)
        /* Hasn't asked to be notified about any bgworkers yet */
        bn->bgworker_notify = false;
 
-#ifdef EXEC_BACKEND
-       pid = backend_forkexec(client_sock, cac);
-#else                                                  /* !EXEC_BACKEND */
-       pid = fork_process();
-       if (pid == 0)                           /* child */
-       {
-               /* Detangle from postmaster */
-               InitPostmasterChild();
-
-               /* Close the postmaster's sockets */
-               ClosePostmasterPorts(false);
-
-               /* Perform additional initialization and collect startup packet */
-               BackendInitialize(client_sock, cac);
-
-               /* And run the backend */
-               BackendRun();
-       }
-#endif                                                 /* EXEC_BACKEND */
-
+       pid = postmaster_child_launch(B_BACKEND,
+                                                                 (char *) &startup_data, sizeof(startup_data),
+                                                                 client_sock);
        if (pid < 0)
        {
                /* in parent, fork failed */
@@ -4351,269 +4330,57 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
        set_ps_display("initializing");
 }
 
-
-/*
- * BackendRun -- set up the backend's argument list and invoke PostgresMain()
- *
- * returns:
- *             Doesn't return at all.
- */
-static void
-BackendRun(void)
-{
-       /*
-        * Create a per-backend PGPROC struct in shared memory.  We must do this
-        * before we can use LWLocks or access any shared memory.
-        */
-       InitProcess();
-
-       /*
-        * Make sure we aren't in PostmasterContext anymore.  (We can't delete it
-        * just yet, though, because InitPostgres will need the HBA data.)
-        */
-       MemoryContextSwitchTo(TopMemoryContext);
-
-       PostgresMain(MyProcPort->database_name, MyProcPort->user_name);
-}
-
-
-#ifdef EXEC_BACKEND
-
-/*
- * postmaster_forkexec -- fork and exec a postmaster subprocess
- *
- * The caller must have set up the argv array already, except for argv[2]
- * which will be filled with the name of the temp variable file.
- *
- * Returns the child process PID, or -1 on fork failure (a suitable error
- * message has been logged on failure).
- *
- * All uses of this routine will dispatch to SubPostmasterMain in the
- * child process.
- */
-pid_t
-postmaster_forkexec(int argc, char *argv[])
-{
-       return internal_forkexec(argc, argv, NULL, NULL);
-}
-
-/*
- * backend_forkexec -- fork/exec off a backend process
- *
- * Some operating systems (WIN32) don't have fork() so we have to simulate
- * it by storing parameters that need to be passed to the child and
- * then create a new child process.
- *
- * returns the pid of the fork/exec'd process, or -1 on failure
- */
-static pid_t
-backend_forkexec(ClientSocket *client_sock, CAC_state cac)
-{
-       char       *av[5];
-       int                     ac = 0;
-       char            cacbuf[10];
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forkbackend";
-       av[ac++] = NULL;                        /* filled in by internal_forkexec */
-
-       snprintf(cacbuf, sizeof(cacbuf), "%d", (int) cac);
-       av[ac++] = cacbuf;
-
-       av[ac] = NULL;
-       Assert(ac < lengthof(av));
-
-       return internal_forkexec(ac, av, client_sock, NULL);
-}
-
-/*
- * 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.
- */
 void
-SubPostmasterMain(int argc, char *argv[])
+BackendMain(char *startup_data, size_t startup_data_len)
 {
-       ClientSocket *client_sock;
-       BackgroundWorker *worker;
-
-       /* In EXEC_BACKEND case we will not have inherited these settings */
-       IsPostmasterEnvironment = true;
-       whereToSendOutput = DestNone;
-
-       /* Setup essential subsystems (to ensure elog() behaves sanely) */
-       InitializeGUCOptions();
-
-       /* Check we got appropriate args */
-       if (argc < 3)
-               elog(FATAL, "invalid subpostmaster invocation");
-
-       /* Read in the variables file */
-       read_backend_variables(argv[2], &client_sock, &worker);
+       BackendStartupData *bsdata = (BackendStartupData *) startup_data;
 
-       /* Close the postmaster's sockets (as soon as we know them) */
-       ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0);
+       Assert(startup_data_len == sizeof(BackendStartupData));
+       Assert(MyClientSocket != NULL);
 
-       /* Setup as postmaster child */
-       InitPostmasterChild();
+#ifdef EXEC_BACKEND
 
        /*
-        * 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.  On the other hand, if we choose not
-        * to re-attach, we may have other cleanup to do.
-        *
-        * If testing EXEC_BACKEND on Linux, you should run this as root before
-        * starting the postmaster:
+        * Need to reinitialize the SSL library in the backend, since the context
+        * structures contain function pointers and cannot be passed through the
+        * parameter file.
         *
-        * sysctl -w kernel.randomize_va_space=0
+        * If for some reason reload fails (maybe the user installed broken key
+        * files), soldier on without SSL; that's better than all connections
+        * becoming impossible.
         *
-        * This prevents using randomized stack and code addresses that cause the
-        * child process's memory map to be different from the parent's, making it
-        * sometimes impossible to attach to shared memory at the desired address.
-        * Return the setting to its old value (usually '1' or '2') when finished.
+        * XXX should we do this in all child processes?  For the moment it's
+        * enough to do it in backend children.
         */
-       if (strcmp(argv[1], "--forkbackend") == 0 ||
-               strcmp(argv[1], "--forkavlauncher") == 0 ||
-               strcmp(argv[1], "--forkssworker") == 0 ||
-               strcmp(argv[1], "--forkavworker") == 0 ||
-               strcmp(argv[1], "--forkaux") == 0 ||
-               strcmp(argv[1], "--forkbgworker") == 0)
-               PGSharedMemoryReAttach();
-       else
-               PGSharedMemoryNoReAttach();
+#ifdef USE_SSL
+       if (EnableSSL)
+       {
+               if (secure_initialize(false) == 0)
+                       LoadedSSL = true;
+               else
+                       ereport(LOG,
+                                       (errmsg("SSL configuration could not be loaded in child process")));
+       }
+#endif
+#endif
 
-       /* Read in remaining GUC variables */
-       read_nondefault_variables();
+       /* Perform additional initialization and collect startup packet */
+       BackendInitialize(MyClientSocket, bsdata->canAcceptConnections);
 
        /*
-        * Check that the data directory looks valid, which will also check the
-        * privileges on the data directory and update our umask and file/group
-        * variables for creating files later.  Note: this should really be done
-        * before we create any files or directories.
-        */
-       checkDataDir();
-
-       /*
-        * (re-)read control file, as it contains config. The postmaster will
-        * already have read this, but this process doesn't know about that.
+        * Create a per-backend PGPROC struct in shared memory.  We must do this
+        * before we can use LWLocks or access any shared memory.
         */
-       LocalProcessControlFile(false);
+       InitProcess();
 
        /*
-        * Reload any libraries that were preloaded by the postmaster.  Since we
-        * exec'd this process, those libraries didn't come along with us; but we
-        * should load them into all child processes to be consistent with the
-        * non-EXEC_BACKEND behavior.
+        * Make sure we aren't in PostmasterContext anymore.  (We can't delete it
+        * just yet, though, because InitPostgres will need the HBA data.)
         */
-       process_shared_preload_libraries();
-
-       /* Run backend or appropriate child */
-       if (strcmp(argv[1], "--forkbackend") == 0)
-       {
-               CAC_state       cac;
-
-               Assert(argc == 4);
-               cac = (CAC_state) atoi(argv[3]);
-
-               /*
-                * 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 for some reason reload fails (maybe the user installed broken
-                * key files), soldier on without SSL; that's better than all
-                * connections becoming impossible.
-                *
-                * XXX should we do this in all child processes?  For the moment it's
-                * enough to do it in backend children.
-                */
-#ifdef USE_SSL
-               if (EnableSSL)
-               {
-                       if (secure_initialize(false) == 0)
-                               LoadedSSL = true;
-                       else
-                               ereport(LOG,
-                                               (errmsg("SSL configuration could not be loaded in child process")));
-               }
-#endif
-
-               /*
-                * Perform additional initialization and collect startup packet.
-                *
-                * We want to do this before InitProcess() for a couple of reasons: 1.
-                * so that we aren't eating up a PGPROC slot while waiting on the
-                * client. 2. so that if InitProcess() fails due to being out of
-                * PGPROC slots, we have already initialized libpq and are able to
-                * report the error to the client.
-                */
-               BackendInitialize(client_sock, cac);
-
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               /* And run the backend */
-               BackendRun();                   /* does not return */
-
-       }
-       if (strcmp(argv[1], "--forkaux") == 0)
-       {
-               BackendType auxtype;
-
-               Assert(argc == 4);
-
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               auxtype = atoi(argv[3]);
-               AuxiliaryProcessMain(auxtype);  /* does not return */
-       }
-       if (strcmp(argv[1], "--forkavlauncher") == 0)
-       {
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               AutoVacLauncherMain(argc - 2, argv + 2);        /* does not return */
-       }
-       if (strcmp(argv[1], "--forkavworker") == 0)
-       {
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               AutoVacWorkerMain(argc - 2, argv + 2);  /* does not return */
-       }
-       if (strcmp(argv[1], "--forkssworker") == 0)
-       {
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               ReplSlotSyncWorkerMain(argc - 2, argv + 2); /* does not return */
-       }
-       if (strcmp(argv[1], "--forkbgworker") == 0)
-       {
-               /* Restore basic shared memory pointers */
-               InitShmemAccess(UsedShmemSegAddr);
-
-               MyBgworkerEntry = worker;
-               BackgroundWorkerMain();
-       }
-       if (strcmp(argv[1], "--forklog") == 0)
-       {
-               /* Do not want to attach to shared memory */
-
-               SysLoggerMain(argc, argv);      /* does not return */
-       }
+       MemoryContextSwitchTo(TopMemoryContext);
 
-       abort();                                        /* shouldn't get here */
+       PostgresMain(MyProcPort->database_name, MyProcPort->user_name);
 }
-#endif                                                 /* EXEC_BACKEND */
 
 
 /*
@@ -4912,87 +4679,12 @@ StartChildProcess(BackendType type)
 {
        pid_t           pid;
 
-#ifdef EXEC_BACKEND
-       {
-               char       *av[10];
-               int                     ac = 0;
-               char            typebuf[32];
-
-               /*
-                * Set up command-line arguments for subprocess
-                */
-               av[ac++] = "postgres";
-               av[ac++] = "--forkaux";
-               av[ac++] = NULL;                /* filled in by postmaster_forkexec */
-
-               snprintf(typebuf, sizeof(typebuf), "%d", type);
-               av[ac++] = typebuf;
-
-               av[ac] = NULL;
-               Assert(ac < lengthof(av));
-
-               pid = postmaster_forkexec(ac, av);
-       }
-#else                                                  /* !EXEC_BACKEND */
-       pid = fork_process();
-
-       if (pid == 0)                           /* child */
-       {
-               InitPostmasterChild();
-
-               /* Close the postmaster's sockets */
-               ClosePostmasterPorts(false);
-
-               /* Release postmaster's working memory context */
-               MemoryContextSwitchTo(TopMemoryContext);
-               MemoryContextDelete(PostmasterContext);
-               PostmasterContext = NULL;
-
-               AuxiliaryProcessMain(type); /* does not return */
-       }
-#endif                                                 /* EXEC_BACKEND */
-
+       pid = postmaster_child_launch(type, NULL, 0, NULL);
        if (pid < 0)
        {
                /* in parent, fork failed */
-               int                     save_errno = errno;
-
-               errno = save_errno;
-               switch (type)
-               {
-                       case B_STARTUP:
-                               ereport(LOG,
-                                               (errmsg("could not fork startup process: %m")));
-                               break;
-                       case B_ARCHIVER:
-                               ereport(LOG,
-                                               (errmsg("could not fork archiver process: %m")));
-                               break;
-                       case B_BG_WRITER:
-                               ereport(LOG,
-                                               (errmsg("could not fork background writer process: %m")));
-                               break;
-                       case B_CHECKPOINTER:
-                               ereport(LOG,
-                                               (errmsg("could not fork checkpointer process: %m")));
-                               break;
-                       case B_WAL_WRITER:
-                               ereport(LOG,
-                                               (errmsg("could not fork WAL writer process: %m")));
-                               break;
-                       case B_WAL_RECEIVER:
-                               ereport(LOG,
-                                               (errmsg("could not fork WAL receiver process: %m")));
-                               break;
-                       case B_WAL_SUMMARIZER:
-                               ereport(LOG,
-                                               (errmsg("could not fork WAL summarizer process: %m")));
-                               break;
-                       default:
-                               ereport(LOG,
-                                               (errmsg("could not fork process: %m")));
-                               break;
-               }
+               ereport(LOG,
+                               (errmsg("could not fork \"%s\" process: %m", PostmasterChildName(type))));
 
                /*
                 * fork failure is fatal during startup, but there's no need to choke
@@ -5056,7 +4748,7 @@ StartAutovacuumWorker(void)
                        bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
                        bn->bgworker_notify = false;
 
-                       bn->pid = StartAutoVacWorker();
+                       bn->pid = StartChildProcess(B_AUTOVAC_WORKER);
                        if (bn->pid > 0)
                        {
                                bn->bkend_type = BACKEND_TYPE_AUTOVAC;
@@ -5070,7 +4762,7 @@ StartAutovacuumWorker(void)
 
                        /*
                         * fork failed, fall through to report -- actual error message was
-                        * logged by StartAutoVacWorker
+                        * logged by StartChildProcess
                         */
                        (void) ReleasePostmasterChildSlot(bn->child_slot);
                        pfree(bn);
@@ -5153,7 +4845,7 @@ MaybeStartSlotSyncWorker(void)
        if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
                Shutdown <= SmartShutdown && sync_replication_slots &&
                ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
-               SlotSyncWorkerPID = StartSlotSyncWorker();
+               SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER);
 }
 
 /*
@@ -5293,24 +4985,6 @@ BackgroundWorkerUnblockSignals(void)
        sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
 }
 
-#ifdef EXEC_BACKEND
-static pid_t
-bgworker_forkexec(BackgroundWorker *worker)
-{
-       char       *av[10];
-       int                     ac = 0;
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forkbgworker";
-       av[ac++] = NULL;                        /* filled in by internal_forkexec */
-       av[ac] = NULL;
-
-       Assert(ac < lengthof(av));
-
-       return internal_forkexec(ac, av, NULL, worker);
-}
-#endif
-
 /*
  * Start a new bgworker.
  * Starting time conditions must have been checked already.
@@ -5347,65 +5021,32 @@ do_start_bgworker(RegisteredBgWorker *rw)
                        (errmsg_internal("starting background worker process \"%s\"",
                                                         rw->rw_worker.bgw_name)));
 
-#ifdef EXEC_BACKEND
-       switch ((worker_pid = bgworker_forkexec(&rw->rw_worker)))
-#else
-       switch ((worker_pid = fork_process()))
-#endif
+       worker_pid = postmaster_child_launch(B_BG_WORKER, (char *) &rw->rw_worker, sizeof(BackgroundWorker), NULL);
+       if (worker_pid == -1)
        {
-               case -1:
-                       /* in postmaster, fork failed ... */
-                       ereport(LOG,
-                                       (errmsg("could not fork background worker process: %m")));
-                       /* undo what assign_backendlist_entry did */
-                       ReleasePostmasterChildSlot(rw->rw_child_slot);
-                       rw->rw_child_slot = 0;
-                       pfree(rw->rw_backend);
-                       rw->rw_backend = NULL;
-                       /* mark entry as crashed, so we'll try again later */
-                       rw->rw_crashed_at = GetCurrentTimestamp();
-                       break;
-
-#ifndef EXEC_BACKEND
-               case 0:
-                       /* in postmaster child ... */
-                       InitPostmasterChild();
-
-                       /* Close the postmaster's sockets */
-                       ClosePostmasterPorts(false);
-
-                       /*
-                        * Before blowing away PostmasterContext, save this bgworker's
-                        * data where it can find it.
-                        */
-                       MyBgworkerEntry = (BackgroundWorker *)
-                               MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
-                       memcpy(MyBgworkerEntry, &rw->rw_worker, sizeof(BackgroundWorker));
-
-                       /* Release postmaster's working memory context */
-                       MemoryContextSwitchTo(TopMemoryContext);
-                       MemoryContextDelete(PostmasterContext);
-                       PostmasterContext = NULL;
-
-                       BackgroundWorkerMain();
+               /* in postmaster, fork failed ... */
+               ereport(LOG,
+                               (errmsg("could not fork background worker process: %m")));
+               /* undo what assign_backendlist_entry did */
+               ReleasePostmasterChildSlot(rw->rw_child_slot);
+               rw->rw_child_slot = 0;
+               pfree(rw->rw_backend);
+               rw->rw_backend = NULL;
+               /* mark entry as crashed, so we'll try again later */
+               rw->rw_crashed_at = GetCurrentTimestamp();
+               return false;
+       }
 
-                       exit(1);                        /* should not get here */
-                       break;
-#endif
-               default:
-                       /* in postmaster, fork successful ... */
-                       rw->rw_pid = worker_pid;
-                       rw->rw_backend->pid = rw->rw_pid;
-                       ReportBackgroundWorkerPID(rw);
-                       /* add new worker to lists of backends */
-                       dlist_push_head(&BackendList, &rw->rw_backend->elem);
+       /* in postmaster, fork successful ... */
+       rw->rw_pid = worker_pid;
+       rw->rw_backend->pid = rw->rw_pid;
+       ReportBackgroundWorkerPID(rw);
+       /* add new worker to lists of backends */
+       dlist_push_head(&BackendList, &rw->rw_backend->elem);
 #ifdef EXEC_BACKEND
-                       ShmemBackendArrayAdd(rw->rw_backend);
+       ShmemBackendArrayAdd(rw->rw_backend);
 #endif
-                       return true;
-       }
-
-       return false;
+       return true;
 }
 
 /*
index 8b51e45bad0011d71d5f66d28b0958559235b754..ef6f98ebcd794e32965c60f3e737ea62e6872fb6 100644 (file)
@@ -24,6 +24,7 @@
 #include "access/xlogutils.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/pmsignal.h"
@@ -212,8 +213,13 @@ StartupProcExit(int code, Datum arg)
  * ----------------------------------
  */
 void
-StartupProcessMain(void)
+StartupProcessMain(char *startup_data, size_t startup_data_len)
 {
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_STARTUP;
+       AuxiliaryProcessMainCommon();
+
        /* Arrange to clean up at startup process exit */
        on_shmem_exit(StartupProcExit, 0);
 
index d9d042f5628a1f5a7a4eeee5a846af92099aa1b2..08efe74cc910c63811464df99637788db18276c7 100644 (file)
@@ -39,7 +39,6 @@
 #include "pgstat.h"
 #include "pgtime.h"
 #include "port/pg_bitutils.h"
-#include "postmaster/fork_process.h"
 #include "postmaster/interrupt.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
@@ -50,6 +49,7 @@
 #include "storage/pg_shmem.h"
 #include "tcop/tcopprot.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 
 /*
@@ -133,10 +133,7 @@ static volatile sig_atomic_t rotation_requested = false;
 #ifdef EXEC_BACKEND
 static int     syslogger_fdget(FILE *file);
 static FILE *syslogger_fdopen(int fd);
-static pid_t syslogger_forkexec(void);
-static void syslogger_parseArgs(int argc, char *argv[]);
 #endif
-NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
 static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
 static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
 static FILE *logfile_open(const char *filename, const char *mode,
@@ -155,13 +152,19 @@ static void set_next_rotation_time(void);
 static void sigUsr1Handler(SIGNAL_ARGS);
 static void update_metainfo_datafile(void);
 
+typedef struct
+{
+       int                     syslogFile;
+       int                     csvlogFile;
+       int                     jsonlogFile;
+} SysloggerStartupData;
 
 /*
  * Main entry point for syslogger process
  * argc/argv parameters are valid only in EXEC_BACKEND case.
  */
-NON_EXEC_STATIC void
-SysLoggerMain(int argc, char *argv[])
+void
+SysLoggerMain(char *startup_data, size_t startup_data_len)
 {
 #ifndef WIN32
        char            logbuffer[READ_BUF_SIZE];
@@ -173,11 +176,37 @@ SysLoggerMain(int argc, char *argv[])
        pg_time_t       now;
        WaitEventSet *wes;
 
-       now = MyStartTime;
-
+       /*
+        * Re-open the error output files that were opened by SysLogger_Start().
+        *
+        * We expect this will always succeed, which is too optimistic, but if it
+        * fails there's not a lot we can do to report the problem anyway.  As
+        * coded, we'll just crash on a null pointer dereference after failure...
+        */
 #ifdef EXEC_BACKEND
-       syslogger_parseArgs(argc, argv);
-#endif                                                 /* EXEC_BACKEND */
+       {
+               SysloggerStartupData *slsdata = (SysloggerStartupData *) startup_data;
+
+               Assert(startup_data_len == sizeof(*slsdata));
+               syslogFile = syslogger_fdopen(slsdata->syslogFile);
+               csvlogFile = syslogger_fdopen(slsdata->csvlogFile);
+               jsonlogFile = syslogger_fdopen(slsdata->jsonlogFile);
+       }
+#else
+       Assert(startup_data_len == 0);
+#endif
+
+       /*
+        * Now that we're done reading the startup data, release postmaster's
+        * working memory context.
+        */
+       if (PostmasterContext)
+       {
+               MemoryContextDelete(PostmasterContext);
+               PostmasterContext = NULL;
+       }
+
+       now = MyStartTime;
 
        MyBackendType = B_LOGGER;
        init_ps_display(NULL);
@@ -567,6 +596,9 @@ SysLogger_Start(void)
 {
        pid_t           sysloggerPid;
        char       *filename;
+#ifdef EXEC_BACKEND
+       SysloggerStartupData startup_data;
+#endif                                                 /* EXEC_BACKEND */
 
        if (!Logging_collector)
                return 0;
@@ -666,112 +698,95 @@ SysLogger_Start(void)
        }
 
 #ifdef EXEC_BACKEND
-       switch ((sysloggerPid = syslogger_forkexec()))
+       startup_data.syslogFile = syslogger_fdget(syslogFile);
+       startup_data.csvlogFile = syslogger_fdget(csvlogFile);
+       startup_data.jsonlogFile = syslogger_fdget(jsonlogFile);
+       sysloggerPid = postmaster_child_launch(B_LOGGER, (char *) &startup_data, sizeof(startup_data), NULL);
 #else
-       switch ((sysloggerPid = fork_process()))
-#endif
-       {
-               case -1:
-                       ereport(LOG,
-                                       (errmsg("could not fork system logger: %m")));
-                       return 0;
-
-#ifndef EXEC_BACKEND
-               case 0:
-                       /* in postmaster child ... */
-                       InitPostmasterChild();
-
-                       /* Close the postmaster's sockets */
-                       ClosePostmasterPorts(true);
-
-                       /* Drop our connection to postmaster's shared memory, as well */
-                       dsm_detach_all();
-                       PGSharedMemoryDetach();
+       sysloggerPid = postmaster_child_launch(B_LOGGER, NULL, 0, NULL);
+#endif                                                 /* EXEC_BACKEND */
 
-                       /* do the work */
-                       SysLoggerMain(0, NULL);
-                       break;
-#endif
+       if (sysloggerPid == -1)
+       {
+               ereport(LOG,
+                               (errmsg("could not fork system logger: %m")));
+               return 0;
+       }
 
-               default:
-                       /* success, in postmaster */
+       /* success, in postmaster */
 
-                       /* now we redirect stderr, if not done already */
-                       if (!redirection_done)
-                       {
+       /* now we redirect stderr, if not done already */
+       if (!redirection_done)
+       {
 #ifdef WIN32
-                               int                     fd;
+               int                     fd;
 #endif
 
-                               /*
-                                * Leave a breadcrumb trail when redirecting, in case the user
-                                * forgets that redirection is active and looks only at the
-                                * original stderr target file.
-                                */
-                               ereport(LOG,
-                                               (errmsg("redirecting log output to logging collector process"),
-                                                errhint("Future log output will appear in directory \"%s\".",
-                                                                Log_directory)));
+               /*
+                * Leave a breadcrumb trail when redirecting, in case the user forgets
+                * that redirection is active and looks only at the original stderr
+                * target file.
+                */
+               ereport(LOG,
+                               (errmsg("redirecting log output to logging collector process"),
+                                errhint("Future log output will appear in directory \"%s\".",
+                                                Log_directory)));
 
 #ifndef WIN32
-                               fflush(stdout);
-                               if (dup2(syslogPipe[1], STDOUT_FILENO) < 0)
-                                       ereport(FATAL,
-                                                       (errcode_for_file_access(),
-                                                        errmsg("could not redirect stdout: %m")));
-                               fflush(stderr);
-                               if (dup2(syslogPipe[1], STDERR_FILENO) < 0)
-                                       ereport(FATAL,
-                                                       (errcode_for_file_access(),
-                                                        errmsg("could not redirect stderr: %m")));
-                               /* Now we are done with the write end of the pipe. */
-                               close(syslogPipe[1]);
-                               syslogPipe[1] = -1;
+               fflush(stdout);
+               if (dup2(syslogPipe[1], STDOUT_FILENO) < 0)
+                       ereport(FATAL,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not redirect stdout: %m")));
+               fflush(stderr);
+               if (dup2(syslogPipe[1], STDERR_FILENO) < 0)
+                       ereport(FATAL,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not redirect stderr: %m")));
+               /* Now we are done with the write end of the pipe. */
+               close(syslogPipe[1]);
+               syslogPipe[1] = -1;
 #else
 
-                               /*
-                                * open the pipe in binary mode and make sure stderr is binary
-                                * after it's been dup'ed into, to avoid disturbing the pipe
-                                * chunking protocol.
-                                */
-                               fflush(stderr);
-                               fd = _open_osfhandle((intptr_t) syslogPipe[1],
-                                                                        _O_APPEND | _O_BINARY);
-                               if (dup2(fd, STDERR_FILENO) < 0)
-                                       ereport(FATAL,
-                                                       (errcode_for_file_access(),
-                                                        errmsg("could not redirect stderr: %m")));
-                               close(fd);
-                               _setmode(STDERR_FILENO, _O_BINARY);
+               /*
+                * open the pipe in binary mode and make sure stderr is binary after
+                * it's been dup'ed into, to avoid disturbing the pipe chunking
+                * protocol.
+                */
+               fflush(stderr);
+               fd = _open_osfhandle((intptr_t) syslogPipe[1],
+                                                        _O_APPEND | _O_BINARY);
+               if (dup2(fd, STDERR_FILENO) < 0)
+                       ereport(FATAL,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not redirect stderr: %m")));
+               close(fd);
+               _setmode(STDERR_FILENO, _O_BINARY);
 
-                               /*
-                                * Now we are done with the write end of the pipe.
-                                * CloseHandle() must not be called because the preceding
-                                * close() closes the underlying handle.
-                                */
-                               syslogPipe[1] = 0;
+               /*
+                * Now we are done with the write end of the pipe.  CloseHandle() must
+                * not be called because the preceding close() closes the underlying
+                * handle.
+                */
+               syslogPipe[1] = 0;
 #endif
-                               redirection_done = true;
-                       }
-
-                       /* postmaster will never write the file(s); close 'em */
-                       fclose(syslogFile);
-                       syslogFile = NULL;
-                       if (csvlogFile != NULL)
-                       {
-                               fclose(csvlogFile);
-                               csvlogFile = NULL;
-                       }
-                       if (jsonlogFile != NULL)
-                       {
-                               fclose(jsonlogFile);
-                               jsonlogFile = NULL;
-                       }
-                       return (int) sysloggerPid;
+               redirection_done = true;
        }
 
-       /* we should never reach here */
-       return 0;
+       /* postmaster will never write the file(s); close 'em */
+       fclose(syslogFile);
+       syslogFile = NULL;
+       if (csvlogFile != NULL)
+       {
+               fclose(csvlogFile);
+               csvlogFile = NULL;
+       }
+       if (jsonlogFile != NULL)
+       {
+               fclose(jsonlogFile);
+               jsonlogFile = NULL;
+       }
+       return (int) sysloggerPid;
 }
 
 
@@ -830,69 +845,6 @@ syslogger_fdopen(int fd)
 
        return file;
 }
-
-/*
- * syslogger_forkexec() -
- *
- * Format up the arglist for, then fork and exec, a syslogger process
- */
-static pid_t
-syslogger_forkexec(void)
-{
-       char       *av[10];
-       int                     ac = 0;
-       char            filenobuf[32];
-       char            csvfilenobuf[32];
-       char            jsonfilenobuf[32];
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forklog";
-       av[ac++] = NULL;                        /* filled in by postmaster_forkexec */
-
-       /* static variables (those not passed by write_backend_variables) */
-       snprintf(filenobuf, sizeof(filenobuf), "%d",
-                        syslogger_fdget(syslogFile));
-       av[ac++] = filenobuf;
-       snprintf(csvfilenobuf, sizeof(csvfilenobuf), "%d",
-                        syslogger_fdget(csvlogFile));
-       av[ac++] = csvfilenobuf;
-       snprintf(jsonfilenobuf, sizeof(jsonfilenobuf), "%d",
-                        syslogger_fdget(jsonlogFile));
-       av[ac++] = jsonfilenobuf;
-
-       av[ac] = NULL;
-       Assert(ac < lengthof(av));
-
-       return postmaster_forkexec(ac, av);
-}
-
-/*
- * syslogger_parseArgs() -
- *
- * Extract data from the arglist for exec'ed syslogger process
- */
-static void
-syslogger_parseArgs(int argc, char *argv[])
-{
-       int                     fd;
-
-       Assert(argc == 6);
-       argv += 3;
-
-       /*
-        * Re-open the error output files that were opened by SysLogger_Start().
-        *
-        * We expect this will always succeed, which is too optimistic, but if it
-        * fails there's not a lot we can do to report the problem anyway.  As
-        * coded, we'll just crash on a null pointer dereference after failure...
-        */
-       fd = atoi(*argv++);
-       syslogFile = syslogger_fdopen(fd);
-       fd = atoi(*argv++);
-       csvlogFile = syslogger_fdopen(fd);
-       fd = atoi(*argv++);
-       jsonlogFile = syslogger_fdopen(fd);
-}
 #endif                                                 /* EXEC_BACKEND */
 
 
index ec2874c18cbd66da106e40cff60fdc959f9a46ea..b412d0eb86627981a6a09c9c5c2eabfbfc6af869 100644 (file)
@@ -33,6 +33,7 @@
 #include "common/blkreftable.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/interrupt.h"
 #include "postmaster/walsummarizer.h"
 #include "replication/walreceiver.h"
@@ -206,7 +207,7 @@ WalSummarizerShmemInit(void)
  * Entry point for walsummarizer process.
  */
 void
-WalSummarizerMain(void)
+WalSummarizerMain(char *startup_data, size_t startup_data_len)
 {
        sigjmp_buf      local_sigjmp_buf;
        MemoryContext context;
@@ -228,6 +229,11 @@ WalSummarizerMain(void)
        XLogRecPtr      switch_lsn = InvalidXLogRecPtr;
        TimeLineID      switch_tli = 0;
 
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_WAL_SUMMARIZER;
+       AuxiliaryProcessMainCommon();
+
        ereport(DEBUG1,
                        (errmsg_internal("WAL summarizer started")));
 
index e079dc65c88c70fde14737a5cc1a198c87583f83..6e7918a78d47844b30d4ab52892d62fc84493c53 100644 (file)
@@ -48,6 +48,7 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/interrupt.h"
 #include "postmaster/walwriter.h"
 #include "storage/bufmgr.h"
@@ -85,13 +86,18 @@ int                 WalWriterFlushAfter = DEFAULT_WAL_WRITER_FLUSH_AFTER;
  * basic execution environment, but not enabled signals yet.
  */
 void
-WalWriterMain(void)
+WalWriterMain(char *startup_data, size_t startup_data_len)
 {
        sigjmp_buf      local_sigjmp_buf;
        MemoryContext walwriter_context;
        int                     left_till_hibernate;
        bool            hibernating;
 
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_WAL_WRITER;
+       AuxiliaryProcessMainCommon();
+
        /*
         * Properly accept or ignore signals the postmaster might send us
         *
index 5074c8409f7808e16cc63dc7080fa022217d0dea..7b180bdb5c8e5425e4f36fff63420f12384af17f 100644 (file)
@@ -139,11 +139,6 @@ typedef struct RemoteSlot
        ReplicationSlotInvalidationCause invalidated;
 } RemoteSlot;
 
-#ifdef EXEC_BACKEND
-static pid_t slotsyncworker_forkexec(void);
-#endif
-NON_EXEC_STATIC void ReplSlotSyncWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
-
 static void slotsync_failure_callback(int code, Datum arg);
 
 /*
@@ -1113,8 +1108,8 @@ wait_for_slot_activity(bool some_slot_updated)
  * It connects to the primary server, fetches logical failover slots
  * information periodically in order to create and sync the slots.
  */
-NON_EXEC_STATIC void
-ReplSlotSyncWorkerMain(int argc, char *argv[])
+void
+ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len)
 {
        WalReceiverConn *wrconn = NULL;
        char       *dbname;
@@ -1122,6 +1117,8 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
        sigjmp_buf      local_sigjmp_buf;
        StringInfoData app_name;
 
+       Assert(startup_data_len == 0);
+
        MyBackendType = B_SLOTSYNC_WORKER;
 
        init_ps_display(NULL);
@@ -1299,67 +1296,6 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
        Assert(false);
 }
 
-/*
- * Main entry point for slot sync worker process, to be called from the
- * postmaster.
- */
-int
-StartSlotSyncWorker(void)
-{
-       pid_t           pid;
-
-#ifdef EXEC_BACKEND
-       switch ((pid = slotsyncworker_forkexec()))
-       {
-#else
-       switch ((pid = fork_process()))
-       {
-               case 0:
-                       /* in postmaster child ... */
-                       InitPostmasterChild();
-
-                       /* Close the postmaster's sockets */
-                       ClosePostmasterPorts(false);
-
-                       ReplSlotSyncWorkerMain(0, NULL);
-                       break;
-#endif
-               case -1:
-                       ereport(LOG,
-                                       (errmsg("could not fork slot sync worker process: %m")));
-                       return 0;
-
-               default:
-                       return (int) pid;
-       }
-
-       /* shouldn't get here */
-       return 0;
-}
-
-#ifdef EXEC_BACKEND
-/*
- * The forkexec routine for the slot sync worker process.
- *
- * Format up the arglist, then fork and exec.
- */
-static pid_t
-slotsyncworker_forkexec(void)
-{
-       char       *av[10];
-       int                     ac = 0;
-
-       av[ac++] = "postgres";
-       av[ac++] = "--forkssworker";
-       av[ac++] = NULL;                        /* filled in by postmaster_forkexec */
-       av[ac] = NULL;
-
-       Assert(ac < lengthof(av));
-
-       return postmaster_forkexec(ac, av);
-}
-#endif
-
 /*
  * Shut down the slot sync worker.
  */
index 5a0652c9426a15464f9ec74cd1413fea9a695ebb..acda5f68d9a8ba177ffbd2c9a02b7f13ca1d5f94 100644 (file)
@@ -63,6 +63,7 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/auxprocess.h"
 #include "postmaster/interrupt.h"
 #include "replication/walreceiver.h"
 #include "replication/walsender.h"
@@ -179,7 +180,7 @@ ProcessWalRcvInterrupts(void)
 
 /* Main entry point for walreceiver process */
 void
-WalReceiverMain(void)
+WalReceiverMain(char *startup_data, size_t startup_data_len)
 {
        char            conninfo[MAXCONNINFO];
        char       *tmp_conninfo;
@@ -195,6 +196,11 @@ WalReceiverMain(void)
        char       *sender_host = NULL;
        int                     sender_port = 0;
 
+       Assert(startup_data_len == 0);
+
+       MyBackendType = B_WAL_RECEIVER;
+       AuxiliaryProcessMainCommon();
+
        /*
         * WalRcv should be set up already (if we are a backend, we inherit this
         * by fork() or EXEC_BACKEND mechanism from the postmaster).
index 5b536ac50d135e963f5156fd593bb6f2733aa740..3e38bb1311d6f0df9fe5abe21aea99199ed37198 100644 (file)
@@ -45,6 +45,7 @@ volatile uint32 CritSectionCount = 0;
 int                    MyProcPid;
 pg_time_t      MyStartTime;
 TimestampTz MyStartTimestamp;
+struct ClientSocket *MyClientSocket;
 struct Port *MyProcPort;
 int32          MyCancelKey;
 int                    MyPMChildSlot;
index 80cf4cdd969c76bdd3670d898dcbad9d50df313a..cae1e8b3294f2727ad9b6dd6928c2a13ddaebc73 100644 (file)
@@ -50,18 +50,14 @@ extern PGDLLIMPORT int Log_autovacuum_min_duration;
 /* Status inquiry functions */
 extern bool AutoVacuumingActive(void);
 
-/* Functions to start autovacuum process, called from postmaster */
+/* called from postmaster at server startup */
 extern void autovac_init(void);
-extern int     StartAutoVacLauncher(void);
-extern int     StartAutoVacWorker(void);
 
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
-#ifdef EXEC_BACKEND
-extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
-extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
-#endif
+extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
                                                                  Oid relationId, BlockNumber blkno);
index 3e443edde704f1a582b738c6c2a9ee919d76ba38..4e80b1cfec7f3ea41e71461718755cd8a63708a7 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef AUXPROCESS_H
 #define AUXPROCESS_H
 
-#include "miscadmin.h"
-
-extern void AuxiliaryProcessMain(BackendType auxtype) pg_attribute_noreturn();
+extern void AuxiliaryProcessMainCommon(void);
 
 #endif                                                 /* AUXPROCESS_H */
index 5e30525364b6966d4811e7877411778313ac6b6c..9106a0ef3f08ed5e7da065e4061a7b2e1c688bf2 100644 (file)
@@ -55,6 +55,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
 extern void ResetBackgroundWorkerCrashTimes(void);
 
 /* Entry point for background worker processes */
-extern void BackgroundWorkerMain(void) pg_attribute_noreturn();
+extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 #endif                                                 /* BGWORKER_INTERNALS_H */
index b52dc19ef0bcf2fca00e1b808acbcb6ee6ec9ee0..407f26e53025f97cae3a82179334243bd00a16ff 100644 (file)
@@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
 extern PGDLLIMPORT int CheckPointWarning;
 extern PGDLLIMPORT double CheckPointCompletionTarget;
 
-extern void BackgroundWriterMain(void) pg_attribute_noreturn();
-extern void CheckpointerMain(void) pg_attribute_noreturn();
+extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+extern void CheckpointerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 extern void RequestCheckpoint(int flags);
 extern void CheckpointWriteDelay(int flags, double progress);
index 6135a9718d6ee49a2af126beed8cd819cb230e36..a7a417226b01218979e90333166c46068c04234a 100644 (file)
@@ -29,7 +29,7 @@
 extern Size PgArchShmemSize(void);
 extern void PgArchShmemInit(void);
 extern bool PgArchCanRestart(void);
-extern void PgArchiverMain(void) pg_attribute_noreturn();
+extern void PgArchiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 extern void PgArchWakeup(void);
 extern void PgArchForceDirScan(void);
 
index 53f82bb5d4395b984add8e1fe6af4a019d92ffb7..333f81c2c529e1d76b6c778fa963a956de4845d5 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _POSTMASTER_H
 #define _POSTMASTER_H
 
+#include "miscadmin.h"
+
 /* GUC options */
 extern PGDLLIMPORT bool EnableSSL;
 extern PGDLLIMPORT int SuperuserReservedConnections;
@@ -58,11 +60,9 @@ extern int   MaxLivePostmasterChildren(void);
 
 extern bool PostmasterMarkPIDForWorkerNotify(int);
 
-#ifdef EXEC_BACKEND
-
-extern pid_t postmaster_forkexec(int argc, char *argv[]);
-extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
+#ifdef EXEC_BACKEND
 extern Size ShmemBackendArraySize(void);
 extern void ShmemBackendArrayAllocation(void);
 
@@ -71,6 +71,16 @@ extern void pgwin32_register_deadchild_callback(HANDLE procHandle, DWORD procId)
 #endif
 #endif
 
+/* defined in globals.c */
+extern struct ClientSocket *MyClientSocket;
+
+/* prototypes for functions in launch_backend.c */
+extern pid_t postmaster_child_launch(BackendType child_type, char *startup_data, size_t startup_data_len, struct ClientSocket *sock);
+const char *PostmasterChildName(BackendType child_type);
+#ifdef EXEC_BACKEND
+extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
+#endif
+
 /*
  * Note: MAX_BACKENDS is limited to 2^18-1 because that's the width reserved
  * for buffer references in buf_internals.h.  This limitation could be lifted
index cf7a43e38cc8d3b4f72257fbcde893f728e04b5a..dde7ebde88124474f68b002e2f74580804aeb6ca 100644 (file)
@@ -26,7 +26,7 @@
 extern PGDLLIMPORT int log_startup_progress_interval;
 
 extern void HandleStartupProcInterrupts(void);
-extern void StartupProcessMain(void) pg_attribute_noreturn();
+extern void StartupProcessMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 extern void PreRestoreCommand(void);
 extern void PostRestoreCommand(void);
 extern bool IsPromoteSignaled(void);
index b26a2f294734bf767e170c5b2dee96ad39f4a8aa..0f28ebcba55154576d3760b131097942575e67b0 100644 (file)
@@ -86,9 +86,7 @@ extern int    SysLogger_Start(void);
 
 extern void write_syslogger_file(const char *buffer, int count, int destination);
 
-#ifdef EXEC_BACKEND
-extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
-#endif
+extern void SysLoggerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 extern bool CheckLogrotateSignal(void);
 extern void RemoveLogrotateSignalFiles(void);
index ecb4ea37fba725744c4fad5a689597053d908334..ad346d0c119ef21ce50403ecbba5413af3c65439 100644 (file)
@@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
 
 extern Size WalSummarizerShmemSize(void);
 extern void WalSummarizerShmemInit(void);
-extern void WalSummarizerMain(void) pg_attribute_noreturn();
+extern void WalSummarizerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 extern void GetWalSummarizerState(TimeLineID *summarized_tli,
                                                                  XLogRecPtr *summarized_lsn,
index 60f23618cbd8a04c3bd01a624adff273555978cf..5884d69fed110d9dd10daa2539c1dc5bf679bb4f 100644 (file)
@@ -18,6 +18,6 @@
 extern PGDLLIMPORT int WalWriterDelay;
 extern PGDLLIMPORT int WalWriterFlushAfter;
 
-extern void WalWriterMain(void) pg_attribute_noreturn();
+extern void WalWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 
 #endif                                                 /* _WALWRITER_H */
index dca57c502046d3dedd8e1efdf135148678529a6b..61e154b31bf48a5c7feba5a5a56df9c55c82ef38 100644 (file)
@@ -26,9 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
 extern char *CheckAndGetDbnameFromConninfo(void);
 extern bool ValidateSlotSyncParams(int elevel);
 
-#ifdef EXEC_BACKEND
-extern void ReplSlotSyncWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
-#endif
+extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 extern int     StartSlotSyncWorker(void);
 
 extern void ShutDownSlotSync(void);
index b906bb5ce8355a4f1213d47385fc4951c170c020..12f71fa99b0caf9b4617925e4b1ee0adadfc0f50 100644 (file)
@@ -483,7 +483,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
 }
 
 /* prototypes for functions in walreceiver.c */
-extern void WalReceiverMain(void) pg_attribute_noreturn();
+extern void WalReceiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
 extern void ProcessWalRcvInterrupts(void);
 extern void WalRcvForceReply(void);
 
index 6ca93b1e478d5a3419509dd46676ca4f190e29d2..042d04c8de29cdb451780b1b87a3fbd341baacc5 100644 (file)
@@ -231,6 +231,7 @@ BY_HANDLE_FILE_INFORMATION
 Backend
 BackendId
 BackendParameters
+BackendStartupData
 BackendState
 BackendType
 BackgroundWorker
@@ -2136,6 +2137,7 @@ PortalStrategy
 PostParseColumnRefHook
 PostgresPollingStatusType
 PostingItem
+PostmasterChildType
 PreParseColumnRefHook
 PredClass
 PredIterInfo
@@ -3259,6 +3261,7 @@ check_network_data
 check_object_relabel_type
 check_password_hook_type
 check_ungrouped_columns_context
+child_process_kind
 chr
 cmpEntriesArg
 codes_t
@@ -4042,6 +4045,7 @@ BlockRefTableReader
 BlockRefTableSerializedEntry
 BlockRefTableWriter
 SummarizerReadLocalXLogPrivate
+SysloggerStartupData
 WalSummarizerData
 WalSummaryFile
 WalSummaryIO