summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro2022-11-09 00:05:16 +0000
committerThomas Munro2022-11-09 00:06:31 +0000
commitb28ac1d24db44ae763a57688e7a559352002badc (patch)
tree670e399144d8747435c2aa2397481d7e074cfdaf
parent6bbd8b73857a337e3aba2f6cdcaca6355b4c2b51 (diff)
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) */