diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/transam/xlog.c | 5 | ||||
-rw-r--r-- | src/backend/commands/user.c | 7 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 208 | ||||
-rw-r--r-- | src/backend/storage/ipc/Makefile | 4 | ||||
-rw-r--r-- | src/backend/storage/ipc/ipci.c | 8 | ||||
-rw-r--r-- | src/backend/storage/ipc/pmsignal.c | 86 | ||||
-rw-r--r-- | src/backend/storage/ipc/sinvaladt.c | 18 | ||||
-rw-r--r-- | src/include/storage/pmsignal.h | 39 |
8 files changed, 254 insertions, 121 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index c0bfe968d25..e5c2f7d7582 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.80 2001/10/28 06:25:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.81 2001/11/04 19:55:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "catalog/pg_control.h" #include "storage/bufpage.h" #include "storage/lwlock.h" +#include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/sinval.h" #include "storage/spin.h" @@ -1048,7 +1049,7 @@ XLogWrite(XLogwrtRqst WriteRqst) { if (XLOG_DEBUG) elog(DEBUG, "XLogWrite: time for a checkpoint, signaling postmaster"); - kill(getppid(), SIGUSR1); + SendPostmasterSignal(PMSIGNAL_DO_CHECKPOINT); } } LWLockRelease(ControlFileLock); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 3897a5c75ec..9b95ecad274 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.88 2001/11/02 18:39:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.89 2001/11/04 19:55:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,6 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> -#include <signal.h> #include <unistd.h> #include "access/heapam.h" @@ -27,6 +26,7 @@ #include "commands/user.h" #include "libpq/crypt.h" #include "miscadmin.h" +#include "storage/pmsignal.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -180,8 +180,7 @@ write_password_file(Relation rel) /* * Signal the postmaster to reload its password-file cache. */ - if (IsUnderPostmaster) - kill(getppid(), SIGHUP); + SendPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE); } diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2c96486cd06..ae8e5a6fe15 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.254 2001/11/02 18:39:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.255 2001/11/04 19:55:31 tgl Exp $ * * NOTES * @@ -98,6 +98,7 @@ #include "nodes/nodes.h" #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/pmsignal.h" #include "storage/proc.h" #include "access/xlog.h" #include "tcop/tcopprot.h" @@ -155,9 +156,6 @@ int MaxBackends = DEF_MAXBACKENDS; static char *progname = (char *) NULL; -/* flag to indicate that SIGHUP arrived during server loop */ -static volatile bool got_SIGHUP = false; - /* * Default Values */ @@ -239,7 +237,8 @@ static void reset_shared(unsigned short port); static void SIGHUP_handler(SIGNAL_ARGS); static void pmdie(SIGNAL_ARGS); static void reaper(SIGNAL_ARGS); -static void schedule_checkpoint(SIGNAL_ARGS); +static void sigusr1_handler(SIGNAL_ARGS); +static void dummy_handler(SIGNAL_ARGS); static void CleanupProc(int pid, int exitstatus); static int DoBackend(Port *port); static void ExitPostmaster(int status); @@ -722,9 +721,8 @@ PostmasterMain(int argc, char *argv[]) pqsignal(SIGTERM, pmdie); /* wait for children and ShutdownDataBase */ pqsignal(SIGALRM, SIG_IGN); /* ignored */ pqsignal(SIGPIPE, SIG_IGN); /* ignored */ - pqsignal(SIGUSR1, schedule_checkpoint); /* start a background - * checkpoint */ - pqsignal(SIGUSR2, pmdie); /* send SIGUSR2, don't die */ + pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */ + pqsignal(SIGUSR2, dummy_handler); /* unused, reserve for children */ pqsignal(SIGCHLD, reaper); /* handle child termination */ pqsignal(SIGTTIN, SIG_IGN); /* ignored */ pqsignal(SIGTTOU, SIG_IGN); /* ignored */ @@ -867,8 +865,19 @@ ServerLoop(void) Port *port; fd_set rmask, wmask; - struct timeval *timeout = NULL; - struct timeval timeout_tv; + struct timeval timeout; + + /* + * The timeout for the select() below is normally set on the basis + * of the time to the next checkpoint. However, if for some reason + * we don't have a next-checkpoint time, time out after 60 seconds. + * This keeps checkpoint scheduling from locking up when we get new + * connection requests infrequently (since we are likely to detect + * checkpoint completion just after enabling signals below, after + * we've already made the decision about how long to wait this time). + */ + timeout.tv_sec = 60; + timeout.tv_usec = 0; if (CheckPointPID == 0 && checkpointed && Shutdown == NoShutdown && !FatalError && random_seed != 0) @@ -878,12 +887,9 @@ ServerLoop(void) if (CheckPointTimeout + checkpointed > now) { /* - * Not time for checkpoint yet, so set a timeout for - * select + * Not time for checkpoint yet, so set select timeout */ - timeout_tv.tv_sec = CheckPointTimeout + checkpointed - now; - timeout_tv.tv_usec = 0; - timeout = &timeout_tv; + timeout.tv_sec = CheckPointTimeout + checkpointed - now; } else { @@ -895,7 +901,10 @@ ServerLoop(void) * delay */ if (CheckPointPID == 0) - checkpointed = now - (9 * CheckPointTimeout) / 10; + { + timeout.tv_sec = CheckPointTimeout / 10; + checkpointed = now + timeout.tv_sec - CheckPointTimeout; + } } } @@ -907,32 +916,22 @@ ServerLoop(void) PG_SETMASK(&UnBlockSig); - if (select(nSockets, &rmask, &wmask, (fd_set *) NULL, timeout) < 0) + if (select(nSockets, &rmask, &wmask, (fd_set *) NULL, &timeout) < 0) { PG_SETMASK(&BlockSig); if (errno == EINTR || errno == EWOULDBLOCK) continue; - elog(DEBUG, "ServerLoop: select failed: %s", strerror(errno)); + elog(DEBUG, "ServerLoop: select failed: %m"); return STATUS_ERROR; } /* - * Block all signals until we wait again + * Block all signals until we wait again. (This makes it safe + * for our signal handlers to do nontrivial work.) */ PG_SETMASK(&BlockSig); /* - * Respond to signals, if needed - */ - if (got_SIGHUP) - { - got_SIGHUP = false; - ProcessConfigFile(PGC_SIGHUP); - load_hba_and_ident(); - load_password_cache(); - } - - /* * Select a random seed at the time of first receiving a request. */ while (random_seed == 0) @@ -1382,10 +1381,13 @@ SIGHUP_handler(SIGNAL_ARGS) if (Shutdown <= SmartShutdown) { - got_SIGHUP = true; SignalChildren(SIGHUP); + ProcessConfigFile(PGC_SIGHUP); + load_hba_and_ident(); } + PG_SETMASK(&UnBlockSig); + errno = save_errno; } @@ -1406,20 +1408,6 @@ pmdie(SIGNAL_ARGS) switch (postgres_signal_arg) { - case SIGUSR2: - - /* - * Send SIGUSR2 to all children (AsyncNotifyHandler) - */ - if (Shutdown > SmartShutdown) - { - errno = save_errno; - return; - } - SignalChildren(SIGUSR2); - errno = save_errno; - return; - case SIGTERM: /* @@ -1428,27 +1416,18 @@ pmdie(SIGNAL_ARGS) * Wait for children to end their work and ShutdownDataBase. */ if (Shutdown >= SmartShutdown) - { - errno = save_errno; - return; - } + break; Shutdown = SmartShutdown; elog(DEBUG, "smart shutdown request"); if (DLGetHead(BackendList)) /* let reaper() handle this */ - { - errno = save_errno; - return; - } + break; /* * No children left. Shutdown data base system. */ if (StartupPID > 0 || FatalError) /* let reaper() handle * this */ - { - errno = save_errno; - return; - } + break; if (ShutdownPID > 0) { elog(REALLYFATAL, "shutdown process %d already running", @@ -1457,8 +1436,7 @@ pmdie(SIGNAL_ARGS) } ShutdownPID = ShutdownDataBase(); - errno = save_errno; - return; + break; case SIGINT: @@ -1469,10 +1447,7 @@ pmdie(SIGNAL_ARGS) * and exit) and ShutdownDataBase when they are gone. */ if (Shutdown >= FastShutdown) - { - errno = save_errno; - return; - } + break; elog(DEBUG, "fast shutdown request"); if (DLGetHead(BackendList)) /* let reaper() handle this */ { @@ -1482,14 +1457,12 @@ pmdie(SIGNAL_ARGS) elog(DEBUG, "aborting any active transactions"); SignalChildren(SIGTERM); } - errno = save_errno; - return; + break; } if (Shutdown > NoShutdown) { Shutdown = FastShutdown; - errno = save_errno; - return; + break; } Shutdown = FastShutdown; @@ -1498,10 +1471,7 @@ pmdie(SIGNAL_ARGS) */ if (StartupPID > 0 || FatalError) /* let reaper() handle * this */ - { - errno = save_errno; - return; - } + break; if (ShutdownPID > 0) { elog(REALLYFATAL, "shutdown process %d already running", @@ -1510,8 +1480,7 @@ pmdie(SIGNAL_ARGS) } ShutdownPID = ShutdownDataBase(); - errno = save_errno; - return; + break; case SIGQUIT: @@ -1528,11 +1497,13 @@ pmdie(SIGNAL_ARGS) kill(StartupPID, SIGQUIT); if (DLGetHead(BackendList)) SignalChildren(SIGQUIT); + ExitPostmaster(0); break; } - /* exit postmaster */ - ExitPostmaster(0); + PG_SETMASK(&UnBlockSig); + + errno = save_errno; } /* @@ -1542,10 +1513,8 @@ static void reaper(SIGNAL_ARGS) { int save_errno = errno; - #ifdef HAVE_WAITPID int status; /* backend exit status */ - #else union wait status; /* backend exit status */ #endif @@ -1553,8 +1522,6 @@ reaper(SIGNAL_ARGS) int pid; /* process id of dead backend */ PG_SETMASK(&BlockSig); - /* It's not really necessary to reset the handler each time is it? */ - pqsignal(SIGCHLD, reaper); if (DebugLvl) elog(DEBUG, "reaping dead processes"); @@ -1640,8 +1607,7 @@ reaper(SIGNAL_ARGS) CheckPointPID = 0; checkpointed = time(NULL); - errno = save_errno; - return; + goto reaper_done; } CleanupProc(pid, exitstatus); @@ -1654,35 +1620,29 @@ reaper(SIGNAL_ARGS) * StartupDataBase. */ if (DLGetHead(BackendList) || StartupPID > 0 || ShutdownPID > 0) - { - errno = save_errno; - return; - } + goto reaper_done; elog(DEBUG, "all server processes terminated; reinitializing shared memory and semaphores"); shmem_exit(0); reset_shared(PostPortNumber); StartupPID = StartupDataBase(); - errno = save_errno; - return; + + goto reaper_done; } if (Shutdown > NoShutdown) { if (DLGetHead(BackendList)) - { - errno = save_errno; - return; - } + goto reaper_done; if (StartupPID > 0 || ShutdownPID > 0) - { - errno = save_errno; - return; - } + goto reaper_done; ShutdownPID = ShutdownDataBase(); } +reaper_done: + PG_SETMASK(&UnBlockSig); + errno = save_errno; } @@ -2260,27 +2220,71 @@ ExitPostmaster(int status) proc_exit(status); } -/* Request to schedule a checkpoint (no-op if one is currently running) */ +/* + * sigusr1_handler - handle signal conditions from child processes + */ static void -schedule_checkpoint(SIGNAL_ARGS) +sigusr1_handler(SIGNAL_ARGS) { int save_errno = errno; PG_SETMASK(&BlockSig); - /* Ignore request if checkpointing is currently disabled */ - if (CheckPointPID == 0 && checkpointed && - Shutdown == NoShutdown && !FatalError && random_seed != 0) + if (CheckPostmasterSignal(PMSIGNAL_DO_CHECKPOINT)) { - CheckPointPID = CheckPointDataBase(); - /* note: if fork fails, CheckPointPID stays 0; nothing happens */ + /* + * Request to schedule a checkpoint + * + * Ignore request if checkpoint is already running or + * checkpointing is currently disabled + */ + if (CheckPointPID == 0 && checkpointed && + Shutdown == NoShutdown && !FatalError && random_seed != 0) + { + CheckPointPID = CheckPointDataBase(); + /* note: if fork fails, CheckPointPID stays 0; nothing happens */ + } + } + + if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE)) + { + /* + * Password file has changed. + */ + load_password_cache(); } + if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN)) + { + /* + * Send SIGUSR2 to all children (triggers AsyncNotifyHandler). + * See storage/ipc/sinvaladt.c for the use of this. + */ + if (Shutdown == NoShutdown) + SignalChildren(SIGUSR2); + } + + PG_SETMASK(&UnBlockSig); + errno = save_errno; } /* + * Dummy signal handler + * + * We use this for signals that we don't actually use in the postmaster, + * but we do use in backends. If we SIG_IGN such signals in the postmaster, + * then a newly started backend might drop a signal that arrives before it's + * able to reconfigure its signal processing. (See notes in postgres.c.) + */ +static void +dummy_handler(SIGNAL_ARGS) +{ +} + + +/* * CharRemap: given an int in range 0..61, produce textual encoding of it * per crypt(3) conventions. */ diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index 585ae7f6eff..960097b1d18 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -1,7 +1,7 @@ # # Makefile for storage/ipc # -# $Header: /cvsroot/pgsql/src/backend/storage/ipc/Makefile,v 1.16 2001/09/27 19:10:02 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/storage/ipc/Makefile,v 1.17 2001/11/04 19:55:31 tgl Exp $ # subdir = src/backend/storage/ipc @@ -15,7 +15,7 @@ override CFLAGS+= -fno-inline endif endif -OBJS = ipc.o ipci.o shmem.o shmqueue.o sinval.o sinvaladt.o +OBJS = ipc.o ipci.o pmsignal.o shmem.o shmqueue.o sinval.o sinvaladt.o all: SUBSYS.o diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index cf841a614d3..9b178883fe4 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.44 2001/10/25 05:49:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.45 2001/11/04 19:55:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "storage/freespace.h" #include "storage/lmgr.h" #include "storage/lwlock.h" +#include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/sinval.h" #include "storage/spin.h" @@ -121,4 +122,9 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends) * Set up free-space map */ InitFreeSpaceMap(); + + /* + * Set up child-to-postmaster signaling mechanism + */ + PMSignalInit(); } diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c new file mode 100644 index 00000000000..38c5d730c7f --- /dev/null +++ b/src/backend/storage/ipc/pmsignal.c @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------- + * + * pmsignal.c + * routines for signaling the postmaster from its child processes + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/pmsignal.c,v 1.1 2001/11/04 19:55:31 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <signal.h> +#include <unistd.h> + +#include "miscadmin.h" +#include "storage/pmsignal.h" +#include "storage/shmem.h" + + +/* + * The postmaster is signaled by its children by sending SIGUSR1. The + * specific reason is communicated via flags in shared memory. We keep + * a boolean flag for each possible "reason", so that different reasons + * can be signaled by different backends at the same time. (However, + * if the same reason is signaled more than once simultaneously, the + * postmaster will observe it only once.) + * + * The flags are actually declared as "volatile sig_atomic_t" for maximum + * portability. This should ensure that loads and stores of the flag + * values are atomic, allowing us to dispense with any explicit locking. + */ + +static volatile sig_atomic_t * PMSignalFlags; + + +/* + * PMSignalInit - initialize during shared-memory creation + */ +void +PMSignalInit(void) +{ + /* Should be called only once */ + Assert(!PMSignalFlags); + + PMSignalFlags = (sig_atomic_t *) + ShmemAlloc(NUM_PMSIGNALS * sizeof(sig_atomic_t)); + + MemSet(PMSignalFlags, 0, NUM_PMSIGNALS * sizeof(sig_atomic_t)); +} + +/* + * SendPostmasterSignal - signal the postmaster from a child process + */ +void +SendPostmasterSignal(PMSignalReason reason) +{ + /* If called in a standalone backend, do nothing */ + if (!IsUnderPostmaster) + return; + /* Atomically set the proper flag */ + PMSignalFlags[reason] = true; + /* Send signal to postmaster (assume it is our direct parent) */ + kill(getppid(), SIGUSR1); +} + +/* + * CheckPostmasterSignal - check to see if a particular reason has been + * signaled, and clear the signal flag. Should be called by postmaster + * after receiving SIGUSR1. + */ +bool +CheckPostmasterSignal(PMSignalReason reason) +{ + /* Careful here --- don't clear flag if we haven't seen it set */ + if (PMSignalFlags[reason]) + { + PMSignalFlags[reason] = false; + return true; + } + return false; +} diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index d05a651097f..35931f00a14 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -8,17 +8,15 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.41 2001/09/29 04:02:24 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.42 2001/11/04 19:55:31 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <signal.h> -#include <unistd.h> - #include "miscadmin.h" #include "storage/backendid.h" +#include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/sinvaladt.h" @@ -205,11 +203,11 @@ SIInsertDataEntry(SISeg *segP, SharedInvalidationMessage *data) /* * Try to prevent table overflow. When the table is 70% full send a - * SIGUSR2 (ordinarily a NOTIFY signal) to the postmaster, which will - * send it back to all the backends. This will force idle backends to - * execute a transaction to look through pg_listener for NOTIFY - * messages, and as a byproduct of the transaction start they will - * read SI entries. + * WAKEN_CHILDREN request to the postmaster. The postmaster will send + * a SIGUSR2 signal (ordinarily a NOTIFY signal) to all the backends. + * This will force idle backends to execute a transaction to look through + * pg_listener for NOTIFY messages, and as a byproduct of the transaction + * start they will read SI entries. * * This should never happen if all the backends are actively executing * queries, but if a backend is sitting idle then it won't be starting @@ -222,7 +220,7 @@ SIInsertDataEntry(SISeg *segP, SharedInvalidationMessage *data) { if (DebugLvl >= 1) elog(DEBUG, "SIInsertDataEntry: table is 70%% full, signaling postmaster"); - kill(getppid(), SIGUSR2); + SendPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN); } /* diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h new file mode 100644 index 00000000000..f86c06656ef --- /dev/null +++ b/src/include/storage/pmsignal.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * pmsignal.h + * routines for signaling the postmaster from its child processes + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: pmsignal.h,v 1.1 2001/11/04 19:55:31 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef PMSIGNAL_H +#define PMSIGNAL_H + +/* + * Reasons for signaling the postmaster. We can cope with simultaneous + * signals for different reasons. If the same reason is signaled multiple + * times in quick succession, however, the postmaster is likely to observe + * only one notification of it. This is okay for the present uses. + */ +typedef enum +{ + PMSIGNAL_DO_CHECKPOINT, /* request to start a checkpoint */ + PMSIGNAL_PASSWORD_CHANGE, /* pg_pwd file has changed */ + PMSIGNAL_WAKEN_CHILDREN, /* send a NOTIFY signal to all backends */ + + NUM_PMSIGNALS /* Must be last value of enum! */ +} PMSignalReason; + +/* + * prototypes for functions in pmsignal.c + */ +extern void PMSignalInit(void); +extern void SendPostmasterSignal(PMSignalReason reason); +extern bool CheckPostmasterSignal(PMSignalReason reason); + +#endif /* PMSIGNAL_H */ |