Skip to content

Commit 2dee799

Browse files
committed
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.
1 parent ac76ec2 commit 2dee799

File tree

3 files changed

+232
-213
lines changed

3 files changed

+232
-213
lines changed

src/backend/postmaster/bgworker.c

+219
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,24 @@
1212

1313
#include "postgres.h"
1414

15+
#include <unistd.h>
16+
#include <time.h>
17+
1518
#include "miscadmin.h"
19+
#include "libpq/pqsignal.h"
1620
#include "postmaster/bgworker_internals.h"
1721
#include "storage/barrier.h"
22+
#include "storage/ipc.h"
23+
#include "storage/latch.h"
1824
#include "storage/lwlock.h"
1925
#include "storage/pmsignal.h"
26+
#include "storage/proc.h"
27+
#include "storage/procsignal.h"
2028
#include "storage/shmem.h"
29+
#include "tcop/tcopprot.h"
2130
#include "utils/ascii.h"
31+
#include "utils/ps_status.h"
32+
#include "utils/timeout.h"
2233

2334
/*
2435
* The postmaster's list of registered background workers, in private memory.
@@ -354,6 +365,214 @@ SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel)
354365
return true;
355366
}
356367

368+
static void
369+
bgworker_quickdie(SIGNAL_ARGS)
370+
{
371+
sigaddset(&BlockSig, SIGQUIT); /* prevent nested calls */
372+
PG_SETMASK(&BlockSig);
373+
374+
/*
375+
* We DO NOT want to run proc_exit() callbacks -- we're here because
376+
* shared memory may be corrupted, so we don't want to try to clean up our
377+
* transaction. Just nail the windows shut and get out of town. Now that
378+
* there's an atexit callback to prevent third-party code from breaking
379+
* things by calling exit() directly, we have to reset the callbacks
380+
* explicitly to make this work as intended.
381+
*/
382+
on_exit_reset();
383+
384+
/*
385+
* Note we do exit(0) here, not exit(2) like quickdie. The reason is that
386+
* we don't want to be seen this worker as independently crashed, because
387+
* then postmaster would delay restarting it again afterwards. If some
388+
* idiot DBA manually sends SIGQUIT to a random bgworker, the "dead man
389+
* switch" will ensure that postmaster sees this as a crash.
390+
*/
391+
exit(0);
392+
}
393+
394+
/*
395+
* Standard SIGTERM handler for background workers
396+
*/
397+
static void
398+
bgworker_die(SIGNAL_ARGS)
399+
{
400+
PG_SETMASK(&BlockSig);
401+
402+
ereport(FATAL,
403+
(errcode(ERRCODE_ADMIN_SHUTDOWN),
404+
errmsg("terminating background worker \"%s\" due to administrator command",
405+
MyBgworkerEntry->bgw_name)));
406+
}
407+
408+
/*
409+
* Standard SIGUSR1 handler for unconnected workers
410+
*
411+
* Here, we want to make sure an unconnected worker will at least heed
412+
* latch activity.
413+
*/
414+
static void
415+
bgworker_sigusr1_handler(SIGNAL_ARGS)
416+
{
417+
int save_errno = errno;
418+
419+
latch_sigusr1_handler();
420+
421+
errno = save_errno;
422+
}
423+
424+
/*
425+
* Start a new background worker
426+
*
427+
* This is the main entry point for background worker, to be called from
428+
* postmaster.
429+
*/
430+
void
431+
StartBackgroundWorker(void)
432+
{
433+
sigjmp_buf local_sigjmp_buf;
434+
char buf[MAXPGPATH];
435+
BackgroundWorker *worker = MyBgworkerEntry;
436+
bgworker_main_type entrypt;
437+
438+
if (worker == NULL)
439+
elog(FATAL, "unable to find bgworker entry");
440+
441+
/* we are a postmaster subprocess now */
442+
IsUnderPostmaster = true;
443+
IsBackgroundWorker = true;
444+
445+
/* reset MyProcPid */
446+
MyProcPid = getpid();
447+
448+
/* record Start Time for logging */
449+
MyStartTime = time(NULL);
450+
451+
/* Identify myself via ps */
452+
snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name);
453+
init_ps_display(buf, "", "", "");
454+
455+
SetProcessingMode(InitProcessing);
456+
457+
/* Apply PostAuthDelay */
458+
if (PostAuthDelay > 0)
459+
pg_usleep(PostAuthDelay * 1000000L);
460+
461+
/*
462+
* If possible, make this process a group leader, so that the postmaster
463+
* can signal any child processes too.
464+
*/
465+
#ifdef HAVE_SETSID
466+
if (setsid() < 0)
467+
elog(FATAL, "setsid() failed: %m");
468+
#endif
469+
470+
/*
471+
* Set up signal handlers.
472+
*/
473+
if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
474+
{
475+
/*
476+
* SIGINT is used to signal canceling the current action
477+
*/
478+
pqsignal(SIGINT, StatementCancelHandler);
479+
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
480+
pqsignal(SIGFPE, FloatExceptionHandler);
481+
482+
/* XXX Any other handlers needed here? */
483+
}
484+
else
485+
{
486+
pqsignal(SIGINT, SIG_IGN);
487+
pqsignal(SIGUSR1, bgworker_sigusr1_handler);
488+
pqsignal(SIGFPE, SIG_IGN);
489+
}
490+
pqsignal(SIGTERM, bgworker_die);
491+
pqsignal(SIGHUP, SIG_IGN);
492+
493+
pqsignal(SIGQUIT, bgworker_quickdie);
494+
InitializeTimeouts(); /* establishes SIGALRM handler */
495+
496+
pqsignal(SIGPIPE, SIG_IGN);
497+
pqsignal(SIGUSR2, SIG_IGN);
498+
pqsignal(SIGCHLD, SIG_DFL);
499+
500+
/*
501+
* If an exception is encountered, processing resumes here.
502+
*
503+
* See notes in postgres.c about the design of this coding.
504+
*/
505+
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
506+
{
507+
/* Since not using PG_TRY, must reset error stack by hand */
508+
error_context_stack = NULL;
509+
510+
/* Prevent interrupts while cleaning up */
511+
HOLD_INTERRUPTS();
512+
513+
/* Report the error to the server log */
514+
EmitErrorReport();
515+
516+
/*
517+
* Do we need more cleanup here? For shmem-connected bgworkers, we
518+
* will call InitProcess below, which will install ProcKill as exit
519+
* callback. That will take care of releasing locks, etc.
520+
*/
521+
522+
/* and go away */
523+
proc_exit(1);
524+
}
525+
526+
/* We can now handle ereport(ERROR) */
527+
PG_exception_stack = &local_sigjmp_buf;
528+
529+
/* Early initialization */
530+
BaseInit();
531+
532+
/*
533+
* If necessary, create a per-backend PGPROC struct in shared memory,
534+
* except in the EXEC_BACKEND case where this was done in
535+
* SubPostmasterMain. We must do this before we can use LWLocks (and in
536+
* the EXEC_BACKEND case we already had to do some stuff with LWLocks).
537+
*/
538+
#ifndef EXEC_BACKEND
539+
if (worker->bgw_flags & BGWORKER_SHMEM_ACCESS)
540+
InitProcess();
541+
#endif
542+
543+
/*
544+
* If bgw_main is set, we use that value as the initial entrypoint.
545+
* However, if the library containing the entrypoint wasn't loaded at
546+
* postmaster startup time, passing it as a direct function pointer is
547+
* not possible. To work around that, we allow callers for whom a
548+
* function pointer is not available to pass a library name (which will
549+
* be loaded, if necessary) and a function name (which will be looked up
550+
* in the named library).
551+
*/
552+
if (worker->bgw_main != NULL)
553+
entrypt = worker->bgw_main;
554+
else
555+
entrypt = (bgworker_main_type)
556+
load_external_function(worker->bgw_library_name,
557+
worker->bgw_function_name,
558+
true, NULL);
559+
560+
/*
561+
* Note that in normal processes, we would call InitPostgres here. For a
562+
* worker, however, we don't know what database to connect to, yet; so we
563+
* need to wait until the user code does it via
564+
* BackgroundWorkerInitializeConnection().
565+
*/
566+
567+
/*
568+
* Now invoke the user-defined worker code
569+
*/
570+
entrypt(worker->bgw_main_arg);
571+
572+
/* ... and if it returns, we're done */
573+
proc_exit(0);
574+
}
575+
357576
/*
358577
* Register a new background worker while processing shared_preload_libraries.
359578
*

0 commit comments

Comments
 (0)