/
githubmirror
/
postgres
Обзор
Документация
Войти
/
githubmirror
/
postgres
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/port/pqsignal.c
220 строк
6 KB
Michael Paquier
Fix set of typos and grammar mistakes
24 июн 2026, 10:00
24 июн 2026, 10:00
b3a9556
Код
Авторство
О чём код?
/*------------------------------------------------------------------------- * * pqsignal.c * reliable BSD-style signal(2) routine stolen from RWW who stole it * from Stevens... * * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/port/pqsignal.c * * This is the signal() implementation from "Advanced Programming in the UNIX * Environment", with minor changes. It was originally a replacement needed * for old SVR4 systems whose signal() behaved as if sa_flags = SA_RESETHAND | * SA_NODEFER, also known as "unreliable" signals due to races when the * handler was reset. * * By now, all known modern Unix systems have a "reliable" signal() call. * We still don't want to use it though, because it remains * implementation-defined by both C99 and POSIX whether the handler is reset * or signals are blocked when the handler runs, and default restart behavior * is also unspecified. Therefore we take POSIX's advice and call sigaction() * so we can provide explicit sa_flags, but wrap it in this more convenient * traditional interface style. It also provides a place to set any extra * flags we want everywhere, such as SA_NOCLDSTOP. * * Windows, of course, is resolutely in a class by itself. In the backend, * this relies on pqsigaction() in src/backend/port/win32/signal.c, which * provides limited emulation of reliable signals. * * Frontend programs can use this version of pqsignal() to forward to the * native Windows signal() call if they wish, but beware that Windows signals * behave quite differently. Only the 6 signals required by C are supported. * SIGINT handlers run in another thread instead of interrupting an existing * thread, and the others don't interrupt system calls either, so SA_RESTART * is moot. All except SIGFPE have SA_RESETHAND semantics, meaning the * handler is reset to SIG_DFL each time it runs. The set of things you are * allowed to do in a handler is also much more restricted than on Unix, * according to the documentation. * * ------------------------------------------------------------------------ */ #include "c.h" #include <signal.h> #ifndef FRONTEND #include <unistd.h> #endif #ifndef FRONTEND #include "libpq/pqsignal.h" #include "miscadmin.h" #endif #ifdef PG_SIGNAL_COUNT /* Windows */ #define PG_NSIG (PG_SIGNAL_COUNT) #elif defined(NSIG) #define PG_NSIG (NSIG) #else #define PG_NSIG (64) /* XXX: wild guess */ #endif #if !(defined(WIN32) && defined(FRONTEND)) #define USE_SIGACTION #endif #if defined(USE_SIGACTION) && defined(HAVE_SA_SIGINFO) #define USE_SIGINFO #endif /* Check a couple of common signals to make sure PG_NSIG is accurate. */ StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG"); StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG"); StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG"); StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG"); static volatile pqsigfunc pqsignal_handlers[PG_NSIG]; /* * Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function * as the handler for all signals. This wrapper handler function checks that * it is called within a process that knew to maintain MyProcPid, and not a * child process forked by system(3), etc. This check ensures that such child * processes do not modify shared memory, which is often detrimental. If the * check succeeds, the function originally provided to pqsignal() is called. * Otherwise, the default signal handler is installed and then called. * * This wrapper also handles restoring the value of errno. */ #if defined(USE_SIGACTION) && defined(USE_SIGINFO) static void wrapper_handler(int postgres_signal_arg, siginfo_t *info, void *context) #else /* no USE_SIGINFO */ static void wrapper_handler(int postgres_signal_arg) #endif { int save_errno = errno; pg_signal_info pg_info; Assert(postgres_signal_arg > 0); Assert(postgres_signal_arg < PG_NSIG); #ifndef FRONTEND /* * We expect processes to set MyProcPid before calling pqsignal() or * before accepting signals. */ Assert(MyProcPid); Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster); if (unlikely(MyProcPid != (int) getpid())) { pqsignal(postgres_signal_arg, PG_SIG_DFL); raise(postgres_signal_arg); return; } #endif #ifdef HAVE_SA_SIGINFO /* * If supported by the system, forward interesting information from the * system's extended signal information to our platform independent * format. */ pg_info.pid = info->si_pid; pg_info.uid = info->si_uid; #else /* * Otherwise forward values indicating that we do not have the * information. */ pg_info.pid = 0; pg_info.uid = 0; #endif (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info); errno = save_errno; } /* * Set up a signal handler, with SA_RESTART, for signal "signo" * * Note: the actual name of this function is either pqsignal_fe when * compiled with -DFRONTEND, or pqsignal_be when compiled without that. * This is to avoid a name collision with libpq's legacy-pqsignal.c. */ void pqsignal(int signo, pqsigfunc func) { #ifdef USE_SIGACTION struct sigaction act; #else void (*wrapper_func_ptr) (int); #endif bool is_ign = func == PG_SIG_IGN; bool is_dfl = func == PG_SIG_DFL; Assert(signo > 0); Assert(signo < PG_NSIG); /* set up indirection handler */ if (!(is_ign || is_dfl)) { pqsignal_handlers[signo] = func; /* assumed atomic */ } /* * Configure system to either ignore/reset the signal handler, or to * forward it to wrapper_handler. */ #ifdef USE_SIGACTION sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; if (is_ign) act.sa_handler = SIG_IGN; else if (is_dfl) act.sa_handler = SIG_DFL; #ifdef USE_SIGINFO else { act.sa_sigaction = wrapper_handler; act.sa_flags |= SA_SIGINFO; } #else else act.sa_handler = wrapper_handler; #endif #ifdef SA_NOCLDSTOP if (signo == SIGCHLD) act.sa_flags |= SA_NOCLDSTOP; #endif if (sigaction(signo, &act, NULL) < 0) Assert(false); /* probably indicates coding error */ #else /* no USE_SIGACTION */ /* * Forward to the native Windows signal handler through a wrapper, since * it accepts only one argument. */ if (is_ign) wrapper_func_ptr = SIG_IGN; else if (is_dfl) wrapper_func_ptr = SIG_DFL; else wrapper_func_ptr = wrapper_handler; if (signal(signo, wrapper_func_ptr) == SIG_ERR) Assert(false); /* probably indicates coding error */ #endif }