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
This commit is contained in:
Heikki Linnakangas 2024-03-18 11:35:08 +02:00
parent f1baed18bc
commit aafc05de1b
28 changed files with 676 additions and 1008 deletions

View 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)
{
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);

View 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);
}
}
/*

View 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);

View 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.
*/

View 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;
/*

View 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);
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(&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)
if (param->client_sock.sock != PGINVALID_SOCKET)
{
*client_sock = (ClientSocket *) MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
memcpy(*client_sock, &param->client_sock, sizeof(ClientSocket));
read_inheritable_socket(&(*client_sock)->sock, &param->inh_sock);
MyClientSocket = MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
memcpy(MyClientSocket, &param->client_sock, sizeof(ClientSocket));
read_inheritable_socket(&MyClientSocket->sock, &param->inh_sock);
}
else
*client_sock = NULL;
if (param->has_bgworker)
{
*worker = (BackgroundWorker *)
MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
memcpy(*worker, &param->bgworker, sizeof(BackgroundWorker));
}
else
*worker = NULL;
SetDataDir(param->DataDir);

View 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.

View 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
@ -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;
}
/*

View 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);

View 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
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 */

View 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")));

View 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
*

View 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.
*/

View 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).

View 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;

View 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);

View 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 */

View 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 */

View 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);

View 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);

View 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);
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

View 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);

View 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);

View 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,

View 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 */

View 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);

View 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);

View 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