pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Heikki Linnakangas <hlinnaka@iki.fi>
To: Andres Freund <andres@anarazel.de>
Cc: pgsql-hackers@postgresql.org <pgsql-hackers@postgresql.org>
Subject: Use standard die() handler for SIGTERM in bgworkers
Date: Tue, 17 Feb 2026 23:18:00 +0200
Message-ID: <5238fe45-e486-4c62-a7f3-c7d8d416e812@iki.fi> (raw)

Starting a separate thread for this change that was part of the giant 
"Interrupts vs signals" patch set 
[https://www.postgresql.org/message-id/818bafaf-1e77-4c78-8037-d7120878d87c%40iki.fi]

On 14/02/2026 23:56, Andres Freund wrote:
>> From 63d1a57f4906a924c426def4e1a7f27a71611b28 Mon Sep 17 00:00:00 2001
>> From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
>> Date: Tue, 20 Jan 2026 16:57:25 +0200
>> Subject: [PATCH 3/5] Use standard die() handler for SIGTERM in bgworkers
>> -/*
>> - * Standard SIGTERM handler for background workers
>> - */
>> -static void
>> -bgworker_die(SIGNAL_ARGS)
>> -{
>> -	sigprocmask(SIG_SETMASK, &BlockSig, NULL);
>> -
>> -	ereport(FATAL,
>> -			(errcode(ERRCODE_ADMIN_SHUTDOWN),
>> -			 errmsg("terminating background worker \"%s\" due to administrator command",
>> -					MyBgworkerEntry->bgw_type)));
>> -}
>> -
>>  /*
>>   * Main entry point for background worker processes.
>>   */
> 
> Uh, huh. So we were defaulting to completely unsafe code in bgworkers all this
> time?  This obviously can self-deadlock against memory allocations etc in the
> interrupted code... Or cause confusion with the IO streams for stderr. Or ...

Yep.

Here's this patch again, now with updated documentation.

> We really need some instrumentation that fails if we do allocations in signal
> handlers etc.

Yeah, that would be nice..

- Heikki

Attachments:

0001-Use-standard-die-handler-for-SIGTERM-in-bgworkers.patch (text/x-patch, 5.3K) download From 39f1e972895fb32fa20e96f4adc42a0267f953a8 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakangas@iki.fi> Date: Tue, 17 Feb 2026 23:04:26 +0200 Subject: [PATCH 1/1] Use standard die() handler for SIGTERM in bgworkers The previous default bgworker_die() signal would exit with elog(FATAL) directly from the signal handler. That could cause deadlocks or crashes if the signal handler runs while we're e.g holding a spinlock or in the middle of a memory allocation. All the built-in background workers overrode that to use the normal die() handler and CHECK_FOR_INTERRUPTS(). Let's make that the default for all background workers. Some extensions relying on the old behavior might need to adapt, but the new default is much safer and the right thing to do for most background workers. --- doc/src/sgml/bgworker.sgml | 10 ++++++++++ src/backend/access/transam/parallel.c | 1 - src/backend/postmaster/bgworker.c | 16 +--------------- .../replication/logical/applyparallelworker.c | 1 - src/backend/replication/logical/launcher.c | 1 - src/backend/replication/logical/worker.c | 1 - 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml index 4699ef6345f..2affba74382 100644 --- a/doc/src/sgml/bgworker.sgml +++ b/doc/src/sgml/bgworker.sgml @@ -232,6 +232,8 @@ typedef struct BackgroundWorker </para> <para> + A well-behaved background worker must react promptly to standard signals + that the postmaster uses to control its child processes. Signals are initially blocked when control reaches the background worker's main function, and must be unblocked by it; this is to allow the process to customize its signal handlers, if necessary. @@ -240,6 +242,14 @@ typedef struct BackgroundWorker <function>BackgroundWorkerBlockSignals</function>. </para> + <para> + The default signal handlers merely set interrupt flags + that are processed later by <function>CHECK_FOR_INTERRUPTS()</function>. + <function>CHECK_FOR_INTERRUPTS()</function> should be called in any + long-running loop to ensure that the background worker doesn't prevent the + system from shutting down in a timely fashion. + </para> + <para> If <structfield>bgw_restart_time</structfield> for a background worker is configured as <literal>BGW_NEVER_RESTART</literal>, or if it exits with an exit diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index fe00488487d..44786dc131f 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -1327,7 +1327,6 @@ ParallelWorkerMain(Datum main_arg) InitializingParallelWorker = true; /* Establish signal handlers. */ - pqsignal(SIGTERM, die); BackgroundWorkerUnblockSignals(); /* Determine and set our parallel worker number. */ diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 261ccd3f59c..8678ea4e139 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -718,20 +718,6 @@ SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel) return true; } -/* - * Standard SIGTERM handler for background workers - */ -static void -bgworker_die(SIGNAL_ARGS) -{ - sigprocmask(SIG_SETMASK, &BlockSig, NULL); - - ereport(FATAL, - (errcode(ERRCODE_ADMIN_SHUTDOWN), - errmsg("terminating background worker \"%s\" due to administrator command", - MyBgworkerEntry->bgw_type))); -} - /* * Main entry point for background worker processes. */ @@ -787,7 +773,7 @@ BackgroundWorkerMain(const void *startup_data, size_t startup_data_len) pqsignal(SIGUSR1, SIG_IGN); pqsignal(SIGFPE, SIG_IGN); } - pqsignal(SIGTERM, bgworker_die); + pqsignal(SIGTERM, die); /* SIGQUIT handler was already set up by InitPostmasterChild */ pqsignal(SIGHUP, SIG_IGN); diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c index 8a01f16a2ca..1730ace5490 100644 --- a/src/backend/replication/logical/applyparallelworker.c +++ b/src/backend/replication/logical/applyparallelworker.c @@ -879,7 +879,6 @@ ParallelApplyWorkerMain(Datum main_arg) * receiving SIGTERM. */ pqsignal(SIGHUP, SignalHandlerForConfigReload); - pqsignal(SIGTERM, die); pqsignal(SIGUSR2, SignalHandlerForShutdownRequest); BackgroundWorkerUnblockSignals(); diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index 3ed86480be2..e6112e11ec2 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -1213,7 +1213,6 @@ ApplyLauncherMain(Datum main_arg) /* Establish signal handlers. */ pqsignal(SIGHUP, SignalHandlerForConfigReload); - pqsignal(SIGTERM, die); BackgroundWorkerUnblockSignals(); /* diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 32725c48623..75af3a71ca8 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -5890,7 +5890,6 @@ SetupApplyOrSyncWorker(int worker_slot) /* Setup signal handling */ pqsignal(SIGHUP, SignalHandlerForConfigReload); - pqsignal(SIGTERM, die); BackgroundWorkerUnblockSignals(); /* -- 2.47.3

view thread (5+ messages)  latest in thread

Message-ID: <5238fe45-e486-4c62-a7f3-c7d8d416e812@iki.fi>
Permalink:  ../5238fe45-e486-4c62-a7f3-c7d8d416e812@iki.fi/
Also on:    postgresql.org/message-id/5238fe45-e486-4c62-a7f3-c7d8d416e812@iki.fi

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: hlinnaka@iki.fi, andres@anarazel.de
  Subject: Re: Use standard die() handler for SIGTERM in bgworkers
  In-Reply-To: <5238fe45-e486-4c62-a7f3-c7d8d416e812@iki.fi>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox