mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Move more bgworker code to bgworker.c; also, some renaming.
Per discussion on pgsql-hackers. Michael Paquier, slightly modified by me. Original suggestion from Amit Kapila.
This commit is contained in:
@ -12,13 +12,24 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "libpq/pqsignal.h"
|
||||||
#include "postmaster/bgworker_internals.h"
|
#include "postmaster/bgworker_internals.h"
|
||||||
#include "storage/barrier.h"
|
#include "storage/barrier.h"
|
||||||
|
#include "storage/ipc.h"
|
||||||
|
#include "storage/latch.h"
|
||||||
#include "storage/lwlock.h"
|
#include "storage/lwlock.h"
|
||||||
#include "storage/pmsignal.h"
|
#include "storage/pmsignal.h"
|
||||||
|
#include "storage/proc.h"
|
||||||
|
#include "storage/procsignal.h"
|
||||||
#include "storage/shmem.h"
|
#include "storage/shmem.h"
|
||||||
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/ascii.h"
|
#include "utils/ascii.h"
|
||||||
|
#include "utils/ps_status.h"
|
||||||
|
#include "utils/timeout.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The postmaster's list of registered background workers, in private memory.
|
* The postmaster's list of registered background workers, in private memory.
|
||||||
@ -354,6 +365,214 @@ SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start a new background worker
|
||||||
|
*
|
||||||
|
* This is the main entry point for background worker, to be called from
|
||||||
|
* postmaster.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
StartBackgroundWorker(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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register a new background worker while processing shared_preload_libraries.
|
* Register a new background worker while processing shared_preload_libraries.
|
||||||
*
|
*
|
||||||
|
@ -383,7 +383,6 @@ static void dummy_handler(SIGNAL_ARGS);
|
|||||||
static void StartupPacketTimeoutHandler(void);
|
static void StartupPacketTimeoutHandler(void);
|
||||||
static void CleanupBackend(int pid, int exitstatus);
|
static void CleanupBackend(int pid, int exitstatus);
|
||||||
static bool CleanupBackgroundWorker(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 HandleChildCrash(int pid, int exitstatus, const char *procname);
|
||||||
static void LogChildExit(int lev, const char *procname,
|
static void LogChildExit(int lev, const char *procname,
|
||||||
int pid, int exitstatus);
|
int pid, int exitstatus);
|
||||||
@ -409,7 +408,7 @@ static void TerminateChildren(int signal);
|
|||||||
|
|
||||||
static int CountChildren(int target);
|
static int CountChildren(int target);
|
||||||
static int CountUnconnectedWorkers(void);
|
static int CountUnconnectedWorkers(void);
|
||||||
static void StartOneBackgroundWorker(void);
|
static void maybe_start_bgworker(void);
|
||||||
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
|
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
|
||||||
static pid_t StartChildProcess(AuxProcType type);
|
static pid_t StartChildProcess(AuxProcType type);
|
||||||
static void StartAutovacuumWorker(void);
|
static void StartAutovacuumWorker(void);
|
||||||
@ -1232,7 +1231,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
pmState = PM_STARTUP;
|
pmState = PM_STARTUP;
|
||||||
|
|
||||||
/* Some workers may be scheduled to start now */
|
/* Some workers may be scheduled to start now */
|
||||||
StartOneBackgroundWorker();
|
maybe_start_bgworker();
|
||||||
|
|
||||||
status = ServerLoop();
|
status = ServerLoop();
|
||||||
|
|
||||||
@ -1650,7 +1649,7 @@ ServerLoop(void)
|
|||||||
|
|
||||||
/* Get other worker processes running, if needed */
|
/* Get other worker processes running, if needed */
|
||||||
if (StartWorkerNeeded || HaveCrashedWorker)
|
if (StartWorkerNeeded || HaveCrashedWorker)
|
||||||
StartOneBackgroundWorker();
|
maybe_start_bgworker();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Touch Unix socket and lock files every 58 minutes, to ensure that
|
* Touch Unix socket and lock files every 58 minutes, to ensure that
|
||||||
@ -2610,7 +2609,7 @@ reaper(SIGNAL_ARGS)
|
|||||||
PgStatPID = pgstat_start();
|
PgStatPID = pgstat_start();
|
||||||
|
|
||||||
/* some workers may be scheduled to start now */
|
/* some workers may be scheduled to start now */
|
||||||
StartOneBackgroundWorker();
|
maybe_start_bgworker();
|
||||||
|
|
||||||
/* at this point we are really open for business */
|
/* at this point we are really open for business */
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
@ -4626,7 +4625,7 @@ SubPostmasterMain(int argc, char *argv[])
|
|||||||
|
|
||||||
shmem_slot = atoi(argv[1] + 15);
|
shmem_slot = atoi(argv[1] + 15);
|
||||||
MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot);
|
MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot);
|
||||||
do_start_bgworker();
|
StartBackgroundWorker();
|
||||||
}
|
}
|
||||||
if (strcmp(argv[1], "--forkarch") == 0)
|
if (strcmp(argv[1], "--forkarch") == 0)
|
||||||
{
|
{
|
||||||
@ -4741,7 +4740,7 @@ sigusr1_handler(SIGNAL_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (start_bgworker)
|
if (start_bgworker)
|
||||||
StartOneBackgroundWorker();
|
maybe_start_bgworker();
|
||||||
|
|
||||||
if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
|
if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
|
||||||
PgArchPID != 0)
|
PgArchPID != 0)
|
||||||
@ -5253,208 +5252,6 @@ BackgroundWorkerUnblockSignals(void)
|
|||||||
PG_SETMASK(&UnBlockSig);
|
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
|
#ifdef EXEC_BACKEND
|
||||||
static pid_t
|
static pid_t
|
||||||
bgworker_forkexec(int shmem_slot)
|
bgworker_forkexec(int shmem_slot)
|
||||||
@ -5483,7 +5280,7 @@ bgworker_forkexec(int shmem_slot)
|
|||||||
* This code is heavily based on autovacuum.c, q.v.
|
* This code is heavily based on autovacuum.c, q.v.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
start_bgworker(RegisteredBgWorker *rw)
|
do_start_bgworker(RegisteredBgWorker *rw)
|
||||||
{
|
{
|
||||||
pid_t worker_pid;
|
pid_t worker_pid;
|
||||||
|
|
||||||
@ -5514,7 +5311,7 @@ start_bgworker(RegisteredBgWorker *rw)
|
|||||||
/* Do NOT release postmaster's working memory context */
|
/* Do NOT release postmaster's working memory context */
|
||||||
|
|
||||||
MyBgworkerEntry = &rw->rw_worker;
|
MyBgworkerEntry = &rw->rw_worker;
|
||||||
do_start_bgworker();
|
StartBackgroundWorker();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -5618,7 +5415,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw)
|
|||||||
* system state requires it.
|
* system state requires it.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
StartOneBackgroundWorker(void)
|
maybe_start_bgworker(void)
|
||||||
{
|
{
|
||||||
slist_mutable_iter iter;
|
slist_mutable_iter iter;
|
||||||
TimestampTz now = 0;
|
TimestampTz now = 0;
|
||||||
@ -5689,7 +5486,7 @@ StartOneBackgroundWorker(void)
|
|||||||
else
|
else
|
||||||
rw->rw_child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
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)
|
if (rw->rw_backend)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +41,9 @@ extern void BackgroundWorkerShmemInit(void);
|
|||||||
extern void BackgroundWorkerStateChange(void);
|
extern void BackgroundWorkerStateChange(void);
|
||||||
extern void ForgetBackgroundWorker(slist_mutable_iter *cur);
|
extern void ForgetBackgroundWorker(slist_mutable_iter *cur);
|
||||||
|
|
||||||
|
/* Function to start a background worker, called from postmaster.c */
|
||||||
|
extern void StartBackgroundWorker(void);
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
extern BackgroundWorker *BackgroundWorkerEntry(int slotno);
|
extern BackgroundWorker *BackgroundWorkerEntry(int slotno);
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user