From d436c9a62f1e596e11e015caf294b58745e3c6de Mon Sep 17 00:00:00 2001 From: Taiki Koshino Date: Wed, 2 Sep 2026 19:46:13 +0900 Subject: [PATCH v2] Convert pcp_worker die handler to flag-only. die() (SIGTERM/SIGINT/SIGQUIT handler in the PCP worker child) directly called ereport() and proceeded to exit logic from signal context. These operations are not async-signal-safe, and ereport() in particular can allocate memory or acquire locks that the main loop may already be holding, risking corruption or a hang if the signal arrives at the wrong point. Convert die() to the canonical pgpool flag-only pattern used elsewhere in this file. die() now only saves errno, records the signal number into pcp_worker_shutdown_signal, sets pcp_worker_shutdown_request, and restores errno before returning. The actual handling, logging the shutdown request and performing the SIGTERM "smart shutdown" or SIGINT/SIGQUIT immediate exit, is moved into the new process_pcp_worker_shutdown_request(), which is called from the main loop at safe points (before and after each PCP packet read). Reported-by: Emond Papegaaij Reported-by: Claude code Author: Taiki Koshino Discussion: https://www.postgresql.org/message-id/OS9P286MB6486805F1222F8F50767639094AE2%40OS9P286MB6486.JPNP286.PROD.OUTLOOK.COM Backpatch-through: v4.3 --- src/pcp_con/pcp_worker.c | 53 +++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c index 86714d207..4d61b0220 100644 --- a/src/pcp_con/pcp_worker.c +++ b/src/pcp_con/pcp_worker.c @@ -64,10 +64,13 @@ extern char *pcp_conf_file; /* global variable defined in main.c holds the * path for pcp.conf */ volatile sig_atomic_t pcp_worker_wakeup_request = 0; +static volatile sig_atomic_t pcp_worker_shutdown_request = 0; +static volatile sig_atomic_t pcp_worker_shutdown_signal = 0; PCP_CONNECTION *volatile pcp_frontend = NULL; static RETSIGTYPE die(int sig); static RETSIGTYPE wakeup_handler_child(int sig); +static void process_pcp_worker_shutdown_request(void); static void unset_nonblock(int fd); static int user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len); @@ -122,15 +125,15 @@ pcp_worker_main(int port) init_ps_display("", "", "", ""); /* set up signal handlers */ - signal(SIGTERM, die); - signal(SIGINT, die); - signal(SIGQUIT, die); - signal(SIGCHLD, SIG_DFL); - signal(SIGUSR2, wakeup_handler_child); - signal(SIGUSR1, SIG_IGN); - signal(SIGHUP, SIG_IGN); - signal(SIGPIPE, SIG_IGN); - signal(SIGALRM, SIG_IGN); + pool_signal(SIGTERM, die); + pool_signal(SIGINT, die); + pool_signal(SIGQUIT, die); + pool_signal(SIGCHLD, SIG_DFL); + pool_signal(SIGUSR2, wakeup_handler_child); + pool_signal(SIGUSR1, SIG_IGN); + pool_signal(SIGHUP, SIG_IGN); + pool_signal(SIGPIPE, SIG_IGN); + pool_signal(SIGALRM, SIG_IGN); /* Create per loop iteration memory context */ PCPMemoryContext = AllocSetContextCreate(TopMemoryContext, "PCP_worker_main_loop", @@ -174,10 +177,16 @@ pcp_worker_main(int port) errno = 0; + if (pcp_worker_shutdown_request) + process_pcp_worker_shutdown_request(); + /* read a PCP packet */ do_pcp_read(pcp_frontend, &tos, 1); do_pcp_read(pcp_frontend, &rsize, sizeof(int)); + if (pcp_worker_shutdown_request) + process_pcp_worker_shutdown_request(); + rsize = ntohl(rsize); if (rsize <= 0 || rsize >= MAX_PCP_PACKET_LENGTH) @@ -368,11 +377,37 @@ pcp_process_command(char tos, char *buf, int buf_len) } } +/* + * Signal handler for SIGTERM/SIGINT/SIGQUIT. Async-signal-safe: only + * record the request; the main loop runs process_pcp_worker_shutdown_request() + * to log the event and exit cleanly. + */ static RETSIGTYPE die(int sig) { + int save_errno = errno; + + pcp_worker_shutdown_signal = sig; + pcp_worker_shutdown_request = 1; + errno = save_errno; +} + +/* + * Called from the main loop at safe points. Acts on a pending SIGTERM, + * SIGINT or SIGQUIT recorded by die(). SIGTERM ("smart shutdown") only + * logs and lets the worker terminate when the client disconnects, matching + * the historical behaviour. SIGINT/SIGQUIT trigger an immediate clean exit. + */ +static void +process_pcp_worker_shutdown_request(void) +{ + int sig = pcp_worker_shutdown_signal; + + pcp_worker_shutdown_request = 0; + ereport(DEBUG1, (errmsg("PCP worker child receives shutdown request signal %d", sig))); + if (sig == SIGTERM) { ereport(DEBUG1, -- 2.52.0