]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Provide sigaction() for Windows.
authorThomas Munro <tmunro@postgresql.org>
Wed, 9 Nov 2022 00:05:16 +0000 (13:05 +1300)
committerThomas Munro <tmunro@postgresql.org>
Wed, 9 Nov 2022 00:06:31 +0000 (13:06 +1300)
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

src/backend/libpq/pqsignal.c
src/backend/port/win32/signal.c
src/backend/postmaster/postmaster.c
src/include/libpq/pqsignal.h
src/port/pqsignal.c

index 26ed671d1aaea8e7d40ffd6c93dc56da05b1aad6..1ab34c5214dde5d08b6c0c0c05790b8c2319f3d7 100644 (file)
@@ -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
 }
index 53b93a50b26fda40e54675c0be0c12a61e7be470..d533de1bc6c92bede61369ece17ed886f1831c6b 100644 (file)
@@ -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 */
index 0b637ba6a2a59f703a1a9ff2595afdb7e0930dd2..1da5752047fcac32cfb79e2a47f047823dc899c3 100644 (file)
@@ -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;
 }
 
@@ -5106,14 +5069,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
@@ -5254,10 +5209,6 @@ sigusr1_handler(SIGNAL_ARGS)
                signal_child(StartupPID, SIGUSR2);
        }
 
-#ifdef WIN32
-       PG_SETMASK(&UnBlockSig);
-#endif
-
        errno = save_errno;
 }
 
index d17ddb787e753b60ce9f7c0ad041c543042e0487..7890b426a8baf336c879e71d2acd1a0f1c17c36d 100644 (file)
 /* 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)))
index 6cb0320edb15cc9b1898335f5ea157203a7ae557..01940ca398ffb65c48114f1296796881d42438e8 100644 (file)
@@ -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) */