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
This commit is contained in:
Thomas Munro 2022-11-09 13:05:16 +13:00
parent 6bbd8b7385
commit b28ac1d24d
5 changed files with 53 additions and 79 deletions

View File

@ -110,16 +110,10 @@ pqinitmask(void)
* postmaster ever unblocks signals. * postmaster ever unblocks signals.
* *
* pqinitmask() must have been invoked previously. * 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 pqsigfunc
pqsignal_pm(int signo, pqsigfunc func) pqsignal_pm(int signo, pqsigfunc func)
{ {
#ifndef WIN32
struct sigaction act, struct sigaction act,
oact; oact;
@ -142,7 +136,4 @@ pqsignal_pm(int signo, pqsigfunc func)
if (sigaction(signo, &act, &oact) < 0) if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR; return SIG_ERR;
return oact.sa_handler; return oact.sa_handler;
#else /* WIN32 */
return pqsignal(signo, func);
#endif
} }

View File

@ -34,7 +34,7 @@ HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
static CRITICAL_SECTION pg_signal_crit_sec; static CRITICAL_SECTION pg_signal_crit_sec;
/* Note that array elements 0 are unused since they correspond to signal 0 */ /* 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]; static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
@ -85,7 +85,9 @@ pgwin32_signal_initialize(void)
for (i = 0; i < PG_SIGNAL_COUNT; i++) 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_defaults[i] = SIG_IGN;
} }
pg_signal_mask = 0; pg_signal_mask = 0;
@ -131,15 +133,27 @@ pgwin32_dispatch_queued_signals(void)
if (exec_mask & sigmask(i)) if (exec_mask & sigmask(i))
{ {
/* Execute this signal */ /* 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) if (sig == SIG_DFL)
sig = pg_signal_defaults[i]; sig = pg_signal_defaults[i];
pg_signal_queue &= ~sigmask(i); pg_signal_queue &= ~sigmask(i);
if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL) if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
{ {
sigset_t block_mask;
sigset_t save_mask;
LeaveCriticalSection(&pg_signal_crit_sec); 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); sig(i);
sigprocmask(SIG_SETMASK, &save_mask, NULL);
EnterCriticalSection(&pg_signal_crit_sec); EnterCriticalSection(&pg_signal_crit_sec);
break; /* Restart outer loop, in case signal mask or break; /* Restart outer loop, in case signal mask or
* queue has been modified inside signal * queue has been modified inside signal
@ -187,22 +201,25 @@ pqsigprocmask(int how, const sigset_t *set, sigset_t *oset)
return 0; return 0;
} }
/* /*
* Unix-like signal handler installation * Unix-like signal handler installation
* *
* Only called on main thread, no sync required * Only called on main thread, no sync required
*/ */
pqsigfunc int
pqsignal(int signum, pqsigfunc handler) pqsigaction(int signum, const struct sigaction *act,
struct sigaction *oldact)
{ {
pqsigfunc prevfunc;
if (signum >= PG_SIGNAL_COUNT || signum < 0) if (signum >= PG_SIGNAL_COUNT || signum < 0)
return SIG_ERR; {
prevfunc = pg_signal_array[signum]; errno = EINVAL;
pg_signal_array[signum] = handler; return -1;
return prevfunc; }
if (oldact)
*oldact = pg_signal_array[signum];
if (act)
pg_signal_array[signum] = *act;
return 0;
} }
/* Create the signal listener pipe for specified PID */ /* Create the signal listener pipe for specified PID */

View File

@ -620,10 +620,10 @@ PostmasterMain(int argc, char *argv[])
* is used by all child processes and client processes). That has a * is used by all child processes and client processes). That has a
* couple of special behaviors: * couple of special behaviors:
* *
* 1. Except on Windows, we tell sigaction() to block all signals for the * 1. We tell sigaction() to block all signals for the duration of the
* duration of the signal handler. This is faster than our old approach * signal handler. This is faster than our old approach of
* of blocking/unblocking explicitly in the signal handler, and it should * blocking/unblocking explicitly in the signal handler, and it should also
* also prevent excessive stack consumption if signals arrive quickly. * prevent excessive stack consumption if signals arrive quickly.
* *
* 2. We do not set the SA_RESTART flag. This is because signals will be * 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 * blocked at all times except when ServerLoop is waiting for something to
@ -2726,14 +2726,6 @@ SIGHUP_handler(SIGNAL_ARGS)
{ {
int save_errno = errno; 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) if (Shutdown <= SmartShutdown)
{ {
ereport(LOG, ereport(LOG,
@ -2790,10 +2782,6 @@ SIGHUP_handler(SIGNAL_ARGS)
#endif #endif
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -2806,14 +2794,6 @@ pmdie(SIGNAL_ARGS)
{ {
int save_errno = errno; 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, ereport(DEBUG2,
(errmsg_internal("postmaster received signal %d", (errmsg_internal("postmaster received signal %d",
postgres_signal_arg))); postgres_signal_arg)));
@ -2938,10 +2918,6 @@ pmdie(SIGNAL_ARGS)
break; break;
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -2955,14 +2931,6 @@ reaper(SIGNAL_ARGS)
int pid; /* process id of dead child process */ int pid; /* process id of dead child process */
int exitstatus; /* its exit status */ 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, ereport(DEBUG4,
(errmsg_internal("reaping dead processes"))); (errmsg_internal("reaping dead processes")));
@ -3255,11 +3223,6 @@ reaper(SIGNAL_ARGS)
*/ */
PostmasterStateMachine(); PostmasterStateMachine();
/* Done with signal handler */
#ifdef WIN32
PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -5106,14 +5069,6 @@ sigusr1_handler(SIGNAL_ARGS)
{ {
int save_errno = errno; 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 * RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in
* unexpected states. If the startup process quickly starts up, completes * unexpected states. If the startup process quickly starts up, completes
@ -5254,10 +5209,6 @@ sigusr1_handler(SIGNAL_ARGS)
signal_child(StartupPID, SIGUSR2); signal_child(StartupPID, SIGUSR2);
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }

View File

@ -21,12 +21,26 @@
/* Emulate POSIX sigset_t APIs on Windows */ /* Emulate POSIX sigset_t APIs on Windows */
typedef int sigset_t; 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 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_BLOCK 1
#define SIG_UNBLOCK 2 #define SIG_UNBLOCK 2
#define SIG_SETMASK 3 #define SIG_SETMASK 3
#define sigprocmask(how, set, oset) pqsigprocmask((how), (set), (oset)) #define sigprocmask(how, set, oset) pqsigprocmask((how), (set), (oset))
#define sigaction(signum, act, oldact) pqsigaction((signum), (act), (oldact))
#define sigemptyset(set) (*(set) = 0) #define sigemptyset(set) (*(set) = 0)
#define sigfillset(set) (*(set) = ~0) #define sigfillset(set) (*(set) = ~0)
#define sigaddset(set, signum) (*(set) |= (sigmask(signum))) #define sigaddset(set, signum) (*(set) |= (sigmask(signum)))

View File

@ -29,7 +29,9 @@
#include <signal.h> #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" * Set up a signal handler, with SA_RESTART, for signal "signo"
@ -39,7 +41,7 @@
pqsigfunc pqsigfunc
pqsignal(int signo, pqsigfunc func) pqsignal(int signo, pqsigfunc func)
{ {
#ifndef WIN32 #if !(defined(WIN32) && defined(FRONTEND))
struct sigaction act, struct sigaction act,
oact; oact;
@ -53,9 +55,8 @@ pqsignal(int signo, pqsigfunc func)
if (sigaction(signo, &act, &oact) < 0) if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR; return SIG_ERR;
return oact.sa_handler; return oact.sa_handler;
#else /* WIN32 */ #else
/* Forward to Windows native signal system. */
return signal(signo, func); return signal(signo, func);
#endif #endif
} }
#endif /* !defined(WIN32) || defined(FRONTEND) */