From 489dd6b6d0f39c7c3bbf36a42a81b03b0ea07e30 Mon Sep 17 00:00:00 2001 From: Taiki Koshino Date: Thu, 20 Aug 2026 10:18:27 +0900 Subject: [PATCH v1] 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 Author: Taiki Koshino 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