From aafc05de1bf5c0324cb5e690c6742118c1ac4af6 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Mon, 18 Mar 2024 11:35:08 +0200 Subject: [PATCH] Refactor postmaster child process launching 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 --- src/backend/postmaster/autovacuum.c | 163 +----- src/backend/postmaster/auxprocess.c | 53 +- src/backend/postmaster/bgworker.c | 20 +- src/backend/postmaster/bgwriter.c | 8 +- src/backend/postmaster/checkpointer.c | 8 +- src/backend/postmaster/launch_backend.c | 432 ++++++++++++---- src/backend/postmaster/pgarch.c | 8 +- src/backend/postmaster/postmaster.c | 525 ++++---------------- src/backend/postmaster/startup.c | 8 +- src/backend/postmaster/syslogger.c | 302 +++++------ src/backend/postmaster/walsummarizer.c | 8 +- src/backend/postmaster/walwriter.c | 8 +- src/backend/replication/logical/slotsync.c | 72 +-- src/backend/replication/walreceiver.c | 8 +- src/backend/utils/init/globals.c | 1 + src/include/postmaster/autovacuum.h | 10 +- src/include/postmaster/auxprocess.h | 4 +- src/include/postmaster/bgworker_internals.h | 2 +- src/include/postmaster/bgwriter.h | 4 +- src/include/postmaster/pgarch.h | 2 +- src/include/postmaster/postmaster.h | 18 +- src/include/postmaster/startup.h | 2 +- src/include/postmaster/syslogger.h | 4 +- src/include/postmaster/walsummarizer.h | 2 +- src/include/postmaster/walwriter.h | 2 +- src/include/replication/slotsync.h | 4 +- src/include/replication/walreceiver.h | 2 +- src/tools/pgindent/typedefs.list | 4 + 28 files changed, 676 insertions(+), 1008 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 046ab46ecc..71e8a6f258 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -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) -{ - 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 - -/* - * Main entry point for autovacuum launcher process, to be called from the - * postmaster. - */ -int -StartAutoVacLauncher(void) -{ - pid_t AutoVacPID; - -#ifdef EXEC_BACKEND - switch ((AutoVacPID = avlauncher_forkexec())) -#else - switch ((AutoVacPID = fork_process())) -#endif - { - 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; - } - - /* shouldn't get here */ - return 0; -} - -/* - * Main loop for the autovacuum launcher process. - */ -NON_EXEC_STATIC void -AutoVacLauncherMain(int argc, char *argv[]) +void +AutoVacLauncherMain(char *startup_data, size_t startup_data_len) { sigjmp_buf local_sigjmp_buf; + Assert(startup_data_len == 0); + + /* Release postmaster's working memory context */ + if (PostmasterContext) + { + MemoryContextDelete(PostmasterContext); + PostmasterContext = NULL; + } + 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) -{ - 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 - -/* - * Main entry point for autovacuum worker process. - * - * This code is heavily based on pgarch.c, q.v. - */ -int -StartAutoVacWorker(void) -{ - pid_t worker_pid; - -#ifdef EXEC_BACKEND - switch ((worker_pid = avworker_forkexec())) -#else - switch ((worker_pid = fork_process())) -#endif - { - 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; - } - - /* shouldn't get here */ - return 0; -} - -/* - * AutoVacWorkerMain - */ -NON_EXEC_STATIC void -AutoVacWorkerMain(int argc, char *argv[]) +void +AutoVacWorkerMain(char *startup_data, size_t startup_data_len) { sigjmp_buf local_sigjmp_buf; Oid dbid; + Assert(startup_data_len == 0); + + /* Release postmaster's working memory context */ + if (PostmasterContext) + { + MemoryContextDelete(PostmasterContext); + PostmasterContext = NULL; + } + MyBackendType = B_AUTOVAC_WORKER; init_ps_display(NULL); diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c index 2c86abdb71..78f4263eeb 100644 --- a/src/backend/postmaster/auxprocess.c +++ b/src/backend/postmaster/auxprocess.c @@ -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); - } } /* diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index b73e91f0c8..cf64a4beb2 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -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); diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index da2d95b926..0f75548759 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -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. */ diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 46197d56f8..8ef600ae72 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -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; /* diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 80c96e708d..d159096a58 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -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); -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); +#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(); + + /* + * 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(¶m, 0, sizeof(BackendParameters)); - - if (!save_backend_variables(¶m, 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(¶m, 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=", + * where 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(¶m->client_sock, client_sock, sizeof(ClientSocket)); - if (!write_inheritable_socket(¶m->inh_sock, client_sock->sock, childPid)) - return false; - param->has_client_sock = true; - } else - { memset(¶m->client_sock, 0, sizeof(ClientSocket)); - param->has_client_sock = false; - } - - if (worker) - { - memcpy(¶m->bgworker, worker, sizeof(BackgroundWorker)); - param->has_bgworker = true; - } - else - { - memset(¶m->bgworker, 0, sizeof(BackgroundWorker)); - param->has_bgworker = false; - } + if (!write_inheritable_socket(¶m->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(¶m, 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(¶m, client_sock, worker); + restore_backend_variables(¶m); } /* 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) + if (param->client_sock.sock != PGINVALID_SOCKET) { - *client_sock = (ClientSocket *) MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket)); - memcpy(*client_sock, ¶m->client_sock, sizeof(ClientSocket)); - read_inheritable_socket(&(*client_sock)->sock, ¶m->inh_sock); + MyClientSocket = MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket)); + memcpy(MyClientSocket, ¶m->client_sock, sizeof(ClientSocket)); + read_inheritable_socket(&MyClientSocket->sock, ¶m->inh_sock); } - else - *client_sock = NULL; - - if (param->has_bgworker) - { - *worker = (BackgroundWorker *) - MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker)); - memcpy(*worker, ¶m->bgworker, sizeof(BackgroundWorker)); - } - else - *worker = NULL; SetDataDir(param->DataDir); diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index f97035ca03..c266904b57 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -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. diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 6610bd5f86..9a82c3dafa 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -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 @@ -106,7 +106,6 @@ #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,16 +4330,43 @@ 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) +void +BackendMain(char *startup_data, size_t startup_data_len) { + BackendStartupData *bsdata = (BackendStartupData *) startup_data; + + Assert(startup_data_len == sizeof(BackendStartupData)); + Assert(MyClientSocket != NULL); + +#ifdef EXEC_BACKEND + + /* + * 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 +#endif + + /* Perform additional initialization and collect startup packet */ + BackendInitialize(MyClientSocket, bsdata->canAcceptConnections); + /* * Create a per-backend PGPROC struct in shared memory. We must do this * before we can use LWLocks or access any shared memory. @@ -4377,245 +4383,6 @@ BackendRun(void) } -#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[]) -{ - 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); - - /* Close the postmaster's sockets (as soon as we know them) */ - ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); - - /* 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 (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(); - - /* 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(); - - /* 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 */ - } - - abort(); /* shouldn't get here */ -} -#endif /* EXEC_BACKEND */ - - /* * ExitPostmaster -- cleanup * @@ -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(); - - 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); -#ifdef EXEC_BACKEND - ShmemBackendArrayAdd(rw->rw_backend); -#endif - return true; + /* 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; } - return false; + /* 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); +#endif + return true; } /* diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 8b51e45bad..ef6f98ebcd 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -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); diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index d9d042f562..08efe74cc9 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -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 + sysloggerPid = postmaster_child_launch(B_LOGGER, NULL, 0, NULL); +#endif /* EXEC_BACKEND */ + + if (sysloggerPid == -1) { - 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(); - - /* do the work */ - SysLoggerMain(0, NULL); - break; -#endif - - default: - /* success, in postmaster */ - - /* now we redirect stderr, if not done already */ - if (!redirection_done) - { -#ifdef WIN32 - 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))); - -#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; -#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); - - /* - * 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; + ereport(LOG, + (errmsg("could not fork system logger: %m"))); + return 0; } - /* we should never reach here */ - return 0; + /* success, in postmaster */ + + /* now we redirect stderr, if not done already */ + if (!redirection_done) + { +#ifdef WIN32 + 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))); + +#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; +#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); + + /* + * 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; } @@ -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 */ diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c index ec2874c18c..b412d0eb86 100644 --- a/src/backend/postmaster/walsummarizer.c +++ b/src/backend/postmaster/walsummarizer.c @@ -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"))); diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index e079dc65c8..6e7918a78d 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -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 * diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c index 5074c8409f..7b180bdb5c 100644 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@ -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. */ diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 5a0652c942..acda5f68d9 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -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). diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 5b536ac50d..3e38bb1311 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -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; diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index 80cf4cdd96..cae1e8b329 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -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); diff --git a/src/include/postmaster/auxprocess.h b/src/include/postmaster/auxprocess.h index 3e443edde7..4e80b1cfec 100644 --- a/src/include/postmaster/auxprocess.h +++ b/src/include/postmaster/auxprocess.h @@ -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 */ diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index 5e30525364..9106a0ef3f 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -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 */ diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index b52dc19ef0..407f26e530 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -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); diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h index 6135a9718d..a7a417226b 100644 --- a/src/include/postmaster/pgarch.h +++ b/src/include/postmaster/pgarch.h @@ -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); diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index 53f82bb5d4..333f81c2c5 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -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); +extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn(); + #ifdef EXEC_BACKEND - -extern pid_t postmaster_forkexec(int argc, char *argv[]); -extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); - 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 diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h index cf7a43e38c..dde7ebde88 100644 --- a/src/include/postmaster/startup.h +++ b/src/include/postmaster/startup.h @@ -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); diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h index b26a2f2947..0f28ebcba5 100644 --- a/src/include/postmaster/syslogger.h +++ b/src/include/postmaster/syslogger.h @@ -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); diff --git a/src/include/postmaster/walsummarizer.h b/src/include/postmaster/walsummarizer.h index ecb4ea37fb..ad346d0c11 100644 --- a/src/include/postmaster/walsummarizer.h +++ b/src/include/postmaster/walsummarizer.h @@ -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, diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h index 60f23618cb..5884d69fed 100644 --- a/src/include/postmaster/walwriter.h +++ b/src/include/postmaster/walwriter.h @@ -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 */ diff --git a/src/include/replication/slotsync.h b/src/include/replication/slotsync.h index dca57c5020..61e154b31b 100644 --- a/src/include/replication/slotsync.h +++ b/src/include/replication/slotsync.h @@ -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); diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index b906bb5ce8..12f71fa99b 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -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); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 6ca93b1e47..042d04c8de 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -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