Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * pqsignal.c 4 : * reliable BSD-style signal(2) routine stolen from RWW who stole it 5 : * from Stevens... 6 : * 7 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group 8 : * Portions Copyright (c) 1994, Regents of the University of California 9 : * 10 : * 11 : * IDENTIFICATION 12 : * src/port/pqsignal.c 13 : * 14 : * This is the signal() implementation from "Advanced Programming in the UNIX 15 : * Environment", with minor changes. It was originally a replacement needed 16 : * for old SVR4 systems whose signal() behaved as if sa_flags = SA_RESETHAND | 17 : * SA_NODEFER, also known as "unreliable" signals due to races when the 18 : * handler was reset. 19 : * 20 : * By now, all known modern Unix systems have a "reliable" signal() call. 21 : * We still don't want to use it though, because it remains 22 : * implementation-defined by both C99 and POSIX whether the handler is reset 23 : * or signals are blocked when the handler runs, and default restart behavior 24 : * is also unspecified. Therefore we take POSIX's advice and call sigaction() 25 : * so we can provide explicit sa_flags, but wrap it in this more convenient 26 : * traditional interface style. It also provides a place to set any extra 27 : * flags we want everywhere, such as SA_NOCLDSTOP. 28 : * 29 : * Windows, of course, is resolutely in a class by itself. In the backend, 30 : * this relies on pqsigaction() in src/backend/port/win32/signal.c, which 31 : * provides limited emulation of reliable signals. 32 : * 33 : * Frontend programs can use this version of pqsignal() to forward to the 34 : * native Windows signal() call if they wish, but beware that Windows signals 35 : * behave quite differently. Only the 6 signals required by C are supported. 36 : * SIGINT handlers run in another thread instead of interrupting an existing 37 : * thread, and the others don't interrupt system calls either, so SA_RESTART 38 : * is moot. All except SIGFPE have SA_RESETHAND semantics, meaning the 39 : * handler is reset to SIG_DFL each time it runs. The set of things you are 40 : * allowed to do in a handler is also much more restricted than on Unix, 41 : * according to the documentation. 42 : * 43 : * ------------------------------------------------------------------------ 44 : */ 45 : 46 : #include "c.h" 47 : 48 : #include <signal.h> 49 : #ifndef FRONTEND 50 : #include <unistd.h> 51 : #endif 52 : 53 : #ifndef FRONTEND 54 : #include "libpq/pqsignal.h" 55 : #include "miscadmin.h" 56 : #endif 57 : 58 : #ifdef PG_SIGNAL_COUNT /* Windows */ 59 : #define PG_NSIG (PG_SIGNAL_COUNT) 60 : #elif defined(NSIG) 61 : #define PG_NSIG (NSIG) 62 : #else 63 : #define PG_NSIG (64) /* XXX: wild guess */ 64 : #endif 65 : 66 : /* Check a couple of common signals to make sure PG_NSIG is accurate. */ 67 : StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG"); 68 : StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG"); 69 : StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG"); 70 : StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG"); 71 : 72 : static volatile pqsigfunc pqsignal_handlers[PG_NSIG]; 73 : 74 : /* 75 : * Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function 76 : * as the handler for all signals. This wrapper handler function checks that 77 : * it is called within a process that the server knows about (i.e., any process 78 : * that has called InitProcessGlobals(), such as a client backend), and not a 79 : * child process forked by system(3), etc. This check ensures that such child 80 : * processes do not modify shared memory, which is often detrimental. If the 81 : * check succeeds, the function originally provided to pqsignal() is called. 82 : * Otherwise, the default signal handler is installed and then called. 83 : * 84 : * This wrapper also handles restoring the value of errno. 85 : */ 86 : static void 87 373876 : wrapper_handler(SIGNAL_ARGS) 88 : { 89 373876 : int save_errno = errno; 90 : 91 : #ifndef FRONTEND 92 : 93 : /* 94 : * We expect processes to set MyProcPid before calling pqsignal() or 95 : * before accepting signals. 96 : */ 97 : Assert(MyProcPid); 98 : Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster); 99 : 100 373876 : if (unlikely(MyProcPid != (int) getpid())) 101 : { 102 0 : pqsignal(postgres_signal_arg, SIG_DFL); 103 0 : raise(postgres_signal_arg); 104 0 : return; 105 : } 106 : #endif 107 : 108 373876 : (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg); 109 : 110 373876 : errno = save_errno; 111 0 : } 112 : 113 : /* 114 : * Set up a signal handler, with SA_RESTART, for signal "signo" 115 : * 116 : * Returns the previous handler. 117 : * 118 : * NB: If called within a signal handler, race conditions may lead to bogus 119 : * return values. You should either avoid calling this within signal handlers 120 : * or ignore the return value. 121 : * 122 : * XXX: Since no in-tree callers use the return value, and there is little 123 : * reason to do so, it would be nice if we could convert this to a void 124 : * function instead of providing potentially-bogus return values. 125 : * Unfortunately, that requires modifying the pqsignal() in legacy-pqsignal.c, 126 : * which in turn requires an SONAME bump, which is probably not worth it. 127 : */ 128 : pqsigfunc 129 487294 : pqsignal(int signo, pqsigfunc func) 130 : { 131 487294 : pqsigfunc orig_func = pqsignal_handlers[signo]; /* assumed atomic */ 132 : #if !(defined(WIN32) && defined(FRONTEND)) 133 : struct sigaction act, 134 : oact; 135 : #else 136 : pqsigfunc ret; 137 : #endif 138 : 139 : Assert(signo < PG_NSIG); 140 : 141 487294 : if (func != SIG_IGN && func != SIG_DFL) 142 : { 143 366122 : pqsignal_handlers[signo] = func; /* assumed atomic */ 144 366122 : func = wrapper_handler; 145 : } 146 : 147 : #if !(defined(WIN32) && defined(FRONTEND)) 148 487294 : act.sa_handler = func; 149 487294 : sigemptyset(&act.sa_mask); 150 487294 : act.sa_flags = SA_RESTART; 151 : #ifdef SA_NOCLDSTOP 152 487294 : if (signo == SIGCHLD) 153 37226 : act.sa_flags |= SA_NOCLDSTOP; 154 : #endif 155 487294 : if (sigaction(signo, &act, &oact) < 0) 156 0 : return SIG_ERR; 157 487294 : else if (oact.sa_handler == wrapper_handler) 158 327418 : return orig_func; 159 : else 160 159876 : return oact.sa_handler; 161 : #else 162 : /* Forward to Windows native signal system. */ 163 : if ((ret = signal(signo, func)) == wrapper_handler) 164 : return orig_func; 165 : else 166 : return ret; 167 : #endif 168 : }