|
|
|
@ -383,7 +383,6 @@ static void dummy_handler(SIGNAL_ARGS); |
|
|
|
|
static void StartupPacketTimeoutHandler(void); |
|
|
|
|
static void CleanupBackend(int pid, int exitstatus); |
|
|
|
|
static bool CleanupBackgroundWorker(int pid, int exitstatus); |
|
|
|
|
static void do_start_bgworker(void); |
|
|
|
|
static void HandleChildCrash(int pid, int exitstatus, const char *procname); |
|
|
|
|
static void LogChildExit(int lev, const char *procname, |
|
|
|
|
int pid, int exitstatus); |
|
|
|
@ -409,7 +408,7 @@ static void TerminateChildren(int signal); |
|
|
|
|
|
|
|
|
|
static int CountChildren(int target); |
|
|
|
|
static int CountUnconnectedWorkers(void); |
|
|
|
|
static void StartOneBackgroundWorker(void); |
|
|
|
|
static void maybe_start_bgworker(void); |
|
|
|
|
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname); |
|
|
|
|
static pid_t StartChildProcess(AuxProcType type); |
|
|
|
|
static void StartAutovacuumWorker(void); |
|
|
|
@ -1232,7 +1231,7 @@ PostmasterMain(int argc, char *argv[]) |
|
|
|
|
pmState = PM_STARTUP; |
|
|
|
|
|
|
|
|
|
/* Some workers may be scheduled to start now */ |
|
|
|
|
StartOneBackgroundWorker(); |
|
|
|
|
maybe_start_bgworker(); |
|
|
|
|
|
|
|
|
|
status = ServerLoop(); |
|
|
|
|
|
|
|
|
@ -1650,7 +1649,7 @@ ServerLoop(void) |
|
|
|
|
|
|
|
|
|
/* Get other worker processes running, if needed */ |
|
|
|
|
if (StartWorkerNeeded || HaveCrashedWorker) |
|
|
|
|
StartOneBackgroundWorker(); |
|
|
|
|
maybe_start_bgworker(); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Touch Unix socket and lock files every 58 minutes, to ensure that |
|
|
|
@ -2610,7 +2609,7 @@ reaper(SIGNAL_ARGS) |
|
|
|
|
PgStatPID = pgstat_start(); |
|
|
|
|
|
|
|
|
|
/* some workers may be scheduled to start now */ |
|
|
|
|
StartOneBackgroundWorker(); |
|
|
|
|
maybe_start_bgworker(); |
|
|
|
|
|
|
|
|
|
/* at this point we are really open for business */ |
|
|
|
|
ereport(LOG, |
|
|
|
@ -4626,7 +4625,7 @@ SubPostmasterMain(int argc, char *argv[]) |
|
|
|
|
|
|
|
|
|
shmem_slot = atoi(argv[1] + 15); |
|
|
|
|
MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); |
|
|
|
|
do_start_bgworker(); |
|
|
|
|
StartBackgroundWorker(); |
|
|
|
|
} |
|
|
|
|
if (strcmp(argv[1], "--forkarch") == 0) |
|
|
|
|
{ |
|
|
|
@ -4741,7 +4740,7 @@ sigusr1_handler(SIGNAL_ARGS) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (start_bgworker) |
|
|
|
|
StartOneBackgroundWorker(); |
|
|
|
|
maybe_start_bgworker(); |
|
|
|
|
|
|
|
|
|
if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) && |
|
|
|
|
PgArchPID != 0) |
|
|
|
@ -5253,208 +5252,6 @@ BackgroundWorkerUnblockSignals(void) |
|
|
|
|
PG_SETMASK(&UnBlockSig); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
bgworker_quickdie(SIGNAL_ARGS) |
|
|
|
|
{ |
|
|
|
|
sigaddset(&BlockSig, SIGQUIT); /* prevent nested calls */ |
|
|
|
|
PG_SETMASK(&BlockSig); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We DO NOT want to run proc_exit() callbacks -- we're here because |
|
|
|
|
* shared memory may be corrupted, so we don't want to try to clean up our |
|
|
|
|
* transaction. Just nail the windows shut and get out of town. Now that |
|
|
|
|
* there's an atexit callback to prevent third-party code from breaking |
|
|
|
|
* things by calling exit() directly, we have to reset the callbacks |
|
|
|
|
* explicitly to make this work as intended. |
|
|
|
|
*/ |
|
|
|
|
on_exit_reset(); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note we do exit(0) here, not exit(2) like quickdie. The reason is that |
|
|
|
|
* we don't want to be seen this worker as independently crashed, because |
|
|
|
|
* then postmaster would delay restarting it again afterwards. If some |
|
|
|
|
* idiot DBA manually sends SIGQUIT to a random bgworker, the "dead man |
|
|
|
|
* switch" will ensure that postmaster sees this as a crash. |
|
|
|
|
*/ |
|
|
|
|
exit(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Standard SIGTERM handler for background workers |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
bgworker_die(SIGNAL_ARGS) |
|
|
|
|
{ |
|
|
|
|
PG_SETMASK(&BlockSig); |
|
|
|
|
|
|
|
|
|
ereport(FATAL, |
|
|
|
|
(errcode(ERRCODE_ADMIN_SHUTDOWN), |
|
|
|
|
errmsg("terminating background worker \"%s\" due to administrator command", |
|
|
|
|
MyBgworkerEntry->bgw_name))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Standard SIGUSR1 handler for unconnected workers |
|
|
|
|
* |
|
|
|
|
* Here, we want to make sure an unconnected worker will at least heed |
|
|
|
|
* latch activity. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
bgworker_sigusr1_handler(SIGNAL_ARGS) |
|
|
|
|
{ |
|
|
|
|
int save_errno = errno; |
|
|
|
|
|
|
|
|
|
latch_sigusr1_handler(); |
|
|
|
|
|
|
|
|
|
errno = save_errno; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
do_start_bgworker(void) |
|
|
|
|
{ |
|
|
|
|
sigjmp_buf local_sigjmp_buf; |
|
|
|
|
char buf[MAXPGPATH]; |
|
|
|
|
BackgroundWorker *worker = MyBgworkerEntry; |
|
|
|
|
bgworker_main_type entrypt; |
|
|
|
|
|
|
|
|
|
if (worker == NULL) |
|
|
|
|
elog(FATAL, "unable to find bgworker entry"); |
|
|
|
|
|
|
|
|
|
/* we are a postmaster subprocess now */ |
|
|
|
|
IsUnderPostmaster = true; |
|
|
|
|
IsBackgroundWorker = true; |
|
|
|
|
|
|
|
|
|
/* reset MyProcPid */ |
|
|
|
|
MyProcPid = getpid(); |
|
|
|
|
|
|
|
|
|
/* record Start Time for logging */ |
|
|
|
|
MyStartTime = time(NULL); |
|
|
|
|
|
|
|
|
|
/* Identify myself via ps */ |
|
|
|
|
snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name); |
|
|
|
|
init_ps_display(buf, "", "", ""); |
|
|
|
|
|
|
|
|
|
SetProcessingMode(InitProcessing); |
|
|
|
|
|
|
|
|
|
/* Apply PostAuthDelay */ |
|
|
|
|
if (PostAuthDelay > 0) |
|
|
|
|
pg_usleep(PostAuthDelay * 1000000L); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If possible, make this process a group leader, so that the postmaster |
|
|
|
|
* can signal any child processes too. |
|
|
|
|
*/ |
|
|
|
|
#ifdef HAVE_SETSID |
|
|
|
|
if (setsid() < 0) |
|
|
|
|
elog(FATAL, "setsid() failed: %m"); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up signal handlers. |
|
|
|
|
*/ |
|
|
|
|
if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* SIGINT is used to signal canceling the current action |
|
|
|
|
*/ |
|
|
|
|
pqsignal(SIGINT, StatementCancelHandler); |
|
|
|
|
pqsignal(SIGUSR1, procsignal_sigusr1_handler); |
|
|
|
|
pqsignal(SIGFPE, FloatExceptionHandler); |
|
|
|
|
|
|
|
|
|
/* XXX Any other handlers needed here? */ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
pqsignal(SIGINT, SIG_IGN); |
|
|
|
|
pqsignal(SIGUSR1, bgworker_sigusr1_handler); |
|
|
|
|
pqsignal(SIGFPE, SIG_IGN); |
|
|
|
|
} |
|
|
|
|
pqsignal(SIGTERM, bgworker_die); |
|
|
|
|
pqsignal(SIGHUP, SIG_IGN); |
|
|
|
|
|
|
|
|
|
pqsignal(SIGQUIT, bgworker_quickdie); |
|
|
|
|
InitializeTimeouts(); /* establishes SIGALRM handler */ |
|
|
|
|
|
|
|
|
|
pqsignal(SIGPIPE, SIG_IGN); |
|
|
|
|
pqsignal(SIGUSR2, SIG_IGN); |
|
|
|
|
pqsignal(SIGCHLD, SIG_DFL); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If an exception is encountered, processing resumes here. |
|
|
|
|
* |
|
|
|
|
* See notes in postgres.c about the design of this coding. |
|
|
|
|
*/ |
|
|
|
|
if (sigsetjmp(local_sigjmp_buf, 1) != 0) |
|
|
|
|
{ |
|
|
|
|
/* Since not using PG_TRY, must reset error stack by hand */ |
|
|
|
|
error_context_stack = NULL; |
|
|
|
|
|
|
|
|
|
/* Prevent interrupts while cleaning up */ |
|
|
|
|
HOLD_INTERRUPTS(); |
|
|
|
|
|
|
|
|
|
/* Report the error to the server log */ |
|
|
|
|
EmitErrorReport(); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do we need more cleanup here? For shmem-connected bgworkers, we |
|
|
|
|
* will call InitProcess below, which will install ProcKill as exit |
|
|
|
|
* callback. That will take care of releasing locks, etc. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/* and go away */ |
|
|
|
|
proc_exit(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* We can now handle ereport(ERROR) */ |
|
|
|
|
PG_exception_stack = &local_sigjmp_buf; |
|
|
|
|
|
|
|
|
|
/* Early initialization */ |
|
|
|
|
BaseInit(); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If necessary, create a per-backend PGPROC struct in shared memory, |
|
|
|
|
* except in the EXEC_BACKEND case where this was done in |
|
|
|
|
* SubPostmasterMain. We must do this before we can use LWLocks (and in |
|
|
|
|
* the EXEC_BACKEND case we already had to do some stuff with LWLocks). |
|
|
|
|
*/ |
|
|
|
|
#ifndef EXEC_BACKEND |
|
|
|
|
if (worker->bgw_flags & BGWORKER_SHMEM_ACCESS) |
|
|
|
|
InitProcess(); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If bgw_main is set, we use that value as the initial entrypoint. |
|
|
|
|
* However, if the library containing the entrypoint wasn't loaded at |
|
|
|
|
* postmaster startup time, passing it as a direct function pointer is |
|
|
|
|
* not possible. To work around that, we allow callers for whom a |
|
|
|
|
* function pointer is not available to pass a library name (which will |
|
|
|
|
* be loaded, if necessary) and a function name (which will be looked up |
|
|
|
|
* in the named library). |
|
|
|
|
*/ |
|
|
|
|
if (worker->bgw_main != NULL) |
|
|
|
|
entrypt = worker->bgw_main; |
|
|
|
|
else |
|
|
|
|
entrypt = (bgworker_main_type) |
|
|
|
|
load_external_function(worker->bgw_library_name, |
|
|
|
|
worker->bgw_function_name, |
|
|
|
|
true, NULL); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note that in normal processes, we would call InitPostgres here. For a |
|
|
|
|
* worker, however, we don't know what database to connect to, yet; so we |
|
|
|
|
* need to wait until the user code does it via |
|
|
|
|
* BackgroundWorkerInitializeConnection(). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now invoke the user-defined worker code |
|
|
|
|
*/ |
|
|
|
|
entrypt(worker->bgw_main_arg); |
|
|
|
|
|
|
|
|
|
/* ... and if it returns, we're done */ |
|
|
|
|
proc_exit(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef EXEC_BACKEND |
|
|
|
|
static pid_t |
|
|
|
|
bgworker_forkexec(int shmem_slot) |
|
|
|
@ -5483,7 +5280,7 @@ bgworker_forkexec(int shmem_slot) |
|
|
|
|
* This code is heavily based on autovacuum.c, q.v. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
start_bgworker(RegisteredBgWorker *rw) |
|
|
|
|
do_start_bgworker(RegisteredBgWorker *rw) |
|
|
|
|
{ |
|
|
|
|
pid_t worker_pid; |
|
|
|
|
|
|
|
|
@ -5514,7 +5311,7 @@ start_bgworker(RegisteredBgWorker *rw) |
|
|
|
|
/* Do NOT release postmaster's working memory context */ |
|
|
|
|
|
|
|
|
|
MyBgworkerEntry = &rw->rw_worker; |
|
|
|
|
do_start_bgworker(); |
|
|
|
|
StartBackgroundWorker(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
default: |
|
|
|
@ -5618,7 +5415,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw) |
|
|
|
|
* system state requires it. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
StartOneBackgroundWorker(void) |
|
|
|
|
maybe_start_bgworker(void) |
|
|
|
|
{ |
|
|
|
|
slist_mutable_iter iter; |
|
|
|
|
TimestampTz now = 0; |
|
|
|
@ -5689,7 +5486,7 @@ StartOneBackgroundWorker(void) |
|
|
|
|
else |
|
|
|
|
rw->rw_child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); |
|
|
|
|
|
|
|
|
|
start_bgworker(rw); /* sets rw->rw_pid */ |
|
|
|
|
do_start_bgworker(rw); /* sets rw->rw_pid */ |
|
|
|
|
|
|
|
|
|
if (rw->rw_backend) |
|
|
|
|
{ |
|
|
|
|