pgpool2.git / summary / log / commit / refs
commit 0f1e7b87c52a602b1db55835606dc9047321ac8a
Author: Taiki Koshino <koshino@sraoss.co.jp>
Date: Wed Sep 16 09:18:31 2026 +0000
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 <koshino@sraoss.co.jp>
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,
[parent: ab6ef59adeac]