aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro <tmunro@postgresql.org>2022-11-09 13:05:16 +1300
committerThomas Munro <tmunro@postgresql.org>2022-11-09 13:06:31 +1300
commitb28ac1d24db44ae763a57688e7a559352002badc (patch)
tree670e399144d8747435c2aa2397481d7e074cfdaf
parent6bbd8b73857a337e3aba2f6cdcaca6355b4c2b51 (diff)
downloadpostgresql-b28ac1d24db44ae763a57688e7a559352002badc.tar.gz
postgresql-b28ac1d24db44ae763a57688e7a559352002badc.zip
Provide sigaction() for Windows.
Commit 9abb2bfc left behind code to block signals inside signal handlers on Windows, because our signal porting layer didn't have sigaction(). Provide a minimal implementation that is capable of blocking signals, to get rid of platform differences. See also related commit c94ae9d8. Discussion: https://postgr.es/m/CA%2BhUKGKKKfcgx6jzok9AYenp2TNti_tfs8FMoJpL8%2B0Gsy%3D%3D_A%40mail.gmail.com
-rw-r--r--src/backend/libpq/pqsignal.c9
-rw-r--r--src/backend/port/win32/signal.c41
-rw-r--r--src/backend/postmaster/postmaster.c57
-rw-r--r--src/include/libpq/pqsignal.h14
-rw-r--r--src/port/pqsignal.c11
5 files changed, 53 insertions, 79 deletions
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
index 26ed671d1aa..1ab34c5214d 100644
--- a/src/backend/libpq/pqsignal.c
+++ b/src/backend/libpq/pqsignal.c
@@ -110,16 +110,10 @@ pqinitmask(void)
* postmaster ever unblocks signals.
*
* pqinitmask() must have been invoked previously.
- *
- * On Windows, this function is just an alias for pqsignal()
- * (and note that it's calling the code in src/backend/port/win32/signal.c,
- * not src/port/pqsignal.c). On that platform, the postmaster's signal
- * handlers still have to block signals for themselves.
*/
pqsigfunc
pqsignal_pm(int signo, pqsigfunc func)
{
-#ifndef WIN32
struct sigaction act,
oact;
@@ -142,7 +136,4 @@ pqsignal_pm(int signo, pqsigfunc func)
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
-#else /* WIN32 */
- return pqsignal(signo, func);
-#endif
}
diff --git a/src/backend/port/win32/signal.c b/src/backend/port/win32/signal.c
index 53b93a50b26..d533de1bc6c 100644
--- a/src/backend/port/win32/signal.c
+++ b/src/backend/port/win32/signal.c
@@ -34,7 +34,7 @@ HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
static CRITICAL_SECTION pg_signal_crit_sec;
/* Note that array elements 0 are unused since they correspond to signal 0 */
-static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
+static struct sigaction pg_signal_array[PG_SIGNAL_COUNT];
static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
@@ -85,7 +85,9 @@ pgwin32_signal_initialize(void)
for (i = 0; i < PG_SIGNAL_COUNT; i++)
{
- pg_signal_array[i] = SIG_DFL;
+ pg_signal_array[i].sa_handler = SIG_DFL;
+ pg_signal_array[i].sa_mask = 0;
+ pg_signal_array[i].sa_flags = 0;
pg_signal_defaults[i] = SIG_IGN;
}
pg_signal_mask = 0;
@@ -131,15 +133,27 @@ pgwin32_dispatch_queued_signals(void)
if (exec_mask & sigmask(i))
{
/* Execute this signal */
- pqsigfunc sig = pg_signal_array[i];
+ struct sigaction *act = &pg_signal_array[i];
+ pqsigfunc sig = act->sa_handler;
if (sig == SIG_DFL)
sig = pg_signal_defaults[i];
pg_signal_queue &= ~sigmask(i);
if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
{
+ sigset_t block_mask;
+ sigset_t save_mask;
+
LeaveCriticalSection(&pg_signal_crit_sec);
+
+ block_mask = act->sa_mask;
+ if ((act->sa_flags & SA_NODEFER) == 0)
+ block_mask |= sigmask(i);
+
+ sigprocmask(SIG_BLOCK, &block_mask, &save_mask);
sig(i);
+ sigprocmask(SIG_SETMASK, &save_mask, NULL);
+
EnterCriticalSection(&pg_signal_crit_sec);
break; /* Restart outer loop, in case signal mask or
* queue has been modified inside signal
@@ -187,22 +201,25 @@ pqsigprocmask(int how, const sigset_t *set, sigset_t *oset)
return 0;
}
-
/*
* Unix-like signal handler installation
*
* Only called on main thread, no sync required
*/
-pqsigfunc
-pqsignal(int signum, pqsigfunc handler)
+int
+pqsigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact)
{
- pqsigfunc prevfunc;
-
if (signum >= PG_SIGNAL_COUNT || signum < 0)
- return SIG_ERR;
- prevfunc = pg_signal_array[signum];
- pg_signal_array[signum] = handler;
- return prevfunc;
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (oldact)
+ *oldact = pg_signal_array[signum];
+ if (act)
+ pg_signal_array[signum] = *act;
+ return 0;
}
/* Create the signal listener pipe for specified PID */
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 0b637ba6a2a..1da5752047f 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -620,10 +620,10 @@ PostmasterMain(int argc, char *argv[])
* is used by all child processes and client processes). That has a
* couple of special behaviors:
*
- * 1. Except on Windows, we tell sigaction() to block all signals for the
- * duration of the signal handler. This is faster than our old approach
- * of blocking/unblocking explicitly in the signal handler, and it should
- * also prevent excessive stack consumption if signals arrive quickly.
+ * 1. We tell sigaction() to block all signals for the duration of the
+ * signal handler. This is faster than our old approach of
+ * blocking/unblocking explicitly in the signal handler, and it should also
+ * prevent excessive stack consumption if signals arrive quickly.
*
* 2. We do not set the SA_RESTART flag. This is because signals will be
* blocked at all times except when ServerLoop is waiting for something to
@@ -2726,14 +2726,6 @@ SIGHUP_handler(SIGNAL_ARGS)
{
int save_errno = errno;
- /*
- * We rely on the signal mechanism to have blocked all signals ... except
- * on Windows, which lacks sigaction(), so we have to do it manually.
- */
-#ifdef WIN32
- PG_SETMASK(&BlockSig);
-#endif
-
if (Shutdown <= SmartShutdown)
{
ereport(LOG,
@@ -2790,10 +2782,6 @@ SIGHUP_handler(SIGNAL_ARGS)
#endif
}
-#ifdef WIN32
- PG_SETMASK(&UnBlockSig);
-#endif
-
errno = save_errno;
}
@@ -2806,14 +2794,6 @@ pmdie(SIGNAL_ARGS)
{
int save_errno = errno;
- /*
- * We rely on the signal mechanism to have blocked all signals ... except
- * on Windows, which lacks sigaction(), so we have to do it manually.
- */
-#ifdef WIN32
- PG_SETMASK(&BlockSig);
-#endif
-
ereport(DEBUG2,
(errmsg_internal("postmaster received signal %d",
postgres_signal_arg)));
@@ -2938,10 +2918,6 @@ pmdie(SIGNAL_ARGS)
break;
}
-#ifdef WIN32
- PG_SETMASK(&UnBlockSig);
-#endif
-
errno = save_errno;
}
@@ -2955,14 +2931,6 @@ reaper(SIGNAL_ARGS)
int pid; /* process id of dead child process */
int exitstatus; /* its exit status */
- /*
- * We rely on the signal mechanism to have blocked all signals ... except
- * on Windows, which lacks sigaction(), so we have to do it manually.
- */
-#ifdef WIN32
- PG_SETMASK(&BlockSig);
-#endif
-
ereport(DEBUG4,
(errmsg_internal("reaping dead processes")));
@@ -3255,11 +3223,6 @@ reaper(SIGNAL_ARGS)
*/
PostmasterStateMachine();
- /* Done with signal handler */
-#ifdef WIN32
- PG_SETMASK(&UnBlockSig);
-#endif
-
errno = save_errno;
}
@@ -5107,14 +5070,6 @@ sigusr1_handler(SIGNAL_ARGS)
int save_errno = errno;
/*
- * We rely on the signal mechanism to have blocked all signals ... except
- * on Windows, which lacks sigaction(), so we have to do it manually.
- */
-#ifdef WIN32
- PG_SETMASK(&BlockSig);
-#endif
-
- /*
* RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in
* unexpected states. If the startup process quickly starts up, completes
* recovery, exits, we might process the death of the startup process
@@ -5254,10 +5209,6 @@ sigusr1_handler(SIGNAL_ARGS)
signal_child(StartupPID, SIGUSR2);
}
-#ifdef WIN32
- PG_SETMASK(&UnBlockSig);
-#endif
-
errno = save_errno;
}
diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h
index d17ddb787e7..7890b426a8b 100644
--- a/src/include/libpq/pqsignal.h
+++ b/src/include/libpq/pqsignal.h
@@ -21,12 +21,26 @@
/* Emulate POSIX sigset_t APIs on Windows */
typedef int sigset_t;
+#define SA_RESTART 1
+#define SA_NODEFER 2
+
+struct sigaction
+{
+ void (*sa_handler) (int);
+ /* sa_sigaction not yet implemented */
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
extern int pqsigprocmask(int how, const sigset_t *set, sigset_t *oset);
+extern int pqsigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact);
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 3
#define sigprocmask(how, set, oset) pqsigprocmask((how), (set), (oset))
+#define sigaction(signum, act, oldact) pqsigaction((signum), (act), (oldact))
#define sigemptyset(set) (*(set) = 0)
#define sigfillset(set) (*(set) = ~0)
#define sigaddset(set, signum) (*(set) |= (sigmask(signum)))
diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c
index 6cb0320edb1..01940ca398f 100644
--- a/src/port/pqsignal.c
+++ b/src/port/pqsignal.c
@@ -29,7 +29,9 @@
#include <signal.h>
-#if !defined(WIN32) || defined(FRONTEND)
+#ifndef FRONTEND
+#include "libpq/pqsignal.h"
+#endif
/*
* Set up a signal handler, with SA_RESTART, for signal "signo"
@@ -39,7 +41,7 @@
pqsigfunc
pqsignal(int signo, pqsigfunc func)
{
-#ifndef WIN32
+#if !(defined(WIN32) && defined(FRONTEND))
struct sigaction act,
oact;
@@ -53,9 +55,8 @@ pqsignal(int signo, pqsigfunc func)
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
-#else /* WIN32 */
+#else
+ /* Forward to Windows native signal system. */
return signal(signo, func);
#endif
}
-
-#endif /* !defined(WIN32) || defined(FRONTEND) */