diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 5a0f852b6f..ff31e5f040 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.250 2009/02/18 15:58:41 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.251 2009/07/31 20:26:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "storage/bufmgr.h" #include "storage/ipc.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -388,6 +389,19 @@ AuxiliaryProcessMain(int argc, char *argv[]) InitAuxiliaryProcess(); #endif + /* + * Assign the ProcSignalSlot for an auxiliary process. Since it + * doesn't have a BackendId, the slot is statically allocated based on + * the auxiliary process type (auxType). Backends use slots indexed + * in the range from 1 to MaxBackends (inclusive), so we use + * MaxBackends + AuxProcType + 1 as the index of the slot for an + * auxiliary process. + * + * This will need rethinking if we ever want more than one of a + * particular auxiliary process type. + */ + ProcSignalInit(MaxBackends + auxType + 1); + /* finish setting up bufmgr.c */ InitBufferPoolBackend(); diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index de09872cd7..21c7bbe726 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.148 2009/07/21 20:24:51 petere Exp $ + * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.149 2009/07/31 20:26:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,14 +35,15 @@ * If the listenerPID in a matching tuple is ours, we just send a notify * message to our own front end. If it is not ours, and "notification" * is not already nonzero, we set notification to our own PID and send a - * SIGUSR2 signal to the receiving process (indicated by listenerPID). + * PROCSIG_NOTIFY_INTERRUPT signal to the receiving process (indicated by + * listenerPID). * BTW: if the signal operation fails, we presume that the listener backend * crashed without removing this tuple, and remove the tuple for it. * - * 4. Upon receipt of a SIGUSR2 signal, the signal handler can call inbound- - * notify processing immediately if this backend is idle (ie, it is - * waiting for a frontend command and is not within a transaction block). - * Otherwise the handler may only set a flag, which will cause the + * 4. Upon receipt of a PROCSIG_NOTIFY_INTERRUPT signal, the signal handler + * can call inbound-notify processing immediately if this backend is idle + * (ie, it is waiting for a frontend command and is not within a transaction + * block). Otherwise the handler may only set a flag, which will cause the * processing to occur just before we next go idle. * * 5. Inbound-notify processing consists of scanning pg_listener for tuples @@ -95,6 +96,7 @@ #include "libpq/pqformat.h" #include "miscadmin.h" #include "storage/ipc.h" +#include "storage/procsignal.h" #include "storage/sinval.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" @@ -634,12 +636,17 @@ Send_Notify(Relation lRel) /* * If someone has already notified this listener, we don't bother - * modifying the table, but we do still send a SIGUSR2 signal, - * just in case that backend missed the earlier signal for some - * reason. It's OK to send the signal first, because the other - * guy can't read pg_listener until we unlock it. + * modifying the table, but we do still send a NOTIFY_INTERRUPT + * signal, just in case that backend missed the earlier signal for + * some reason. It's OK to send the signal first, because the + * other guy can't read pg_listener until we unlock it. + * + * Note: we don't have the other guy's BackendId available, so + * this will incur a search of the ProcSignal table. That's + * probably not worth worrying about. */ - if (kill(listenerPID, SIGUSR2) < 0) + if (SendProcSignal(listenerPID, PROCSIG_NOTIFY_INTERRUPT, + InvalidBackendId) < 0) { /* * Get rid of pg_listener entry if it refers to a PID that no @@ -777,24 +784,22 @@ AtSubAbort_Notify(void) } /* - * NotifyInterruptHandler + * HandleNotifyInterrupt * - * This is the signal handler for SIGUSR2. + * This is called when PROCSIG_NOTIFY_INTERRUPT is received. * * If we are idle (notifyInterruptEnabled is set), we can safely invoke * ProcessIncomingNotify directly. Otherwise, just set a flag * to do it later. */ void -NotifyInterruptHandler(SIGNAL_ARGS) +HandleNotifyInterrupt(void) { - int save_errno = errno; - /* - * Note: this is a SIGNAL HANDLER. You must be very wary what you do - * here. Some helpful soul had this routine sprinkled with TPRINTFs, which - * would likely lead to corruption of stdio buffers if they were ever - * turned on. + * Note: this is called by a SIGNAL HANDLER. You must be very wary what + * you do here. Some helpful soul had this routine sprinkled with + * TPRINTFs, which would likely lead to corruption of stdio buffers if + * they were ever turned on. */ /* Don't joggle the elbow of proc_exit */ @@ -815,7 +820,7 @@ NotifyInterruptHandler(SIGNAL_ARGS) /* * I'm not sure whether some flavors of Unix might allow another - * SIGUSR2 occurrence to recursively interrupt this routine. To cope + * SIGUSR1 occurrence to recursively interrupt this routine. To cope * with the possibility, we do the same sort of dance that * EnableNotifyInterrupt must do --- see that routine for comments. */ @@ -831,12 +836,12 @@ NotifyInterruptHandler(SIGNAL_ARGS) { /* Here, it is finally safe to do stuff. */ if (Trace_notify) - elog(DEBUG1, "NotifyInterruptHandler: perform async notify"); + elog(DEBUG1, "HandleNotifyInterrupt: perform async notify"); ProcessIncomingNotify(); if (Trace_notify) - elog(DEBUG1, "NotifyInterruptHandler: done"); + elog(DEBUG1, "HandleNotifyInterrupt: done"); } } @@ -854,8 +859,6 @@ NotifyInterruptHandler(SIGNAL_ARGS) */ notifyInterruptOccurred = 1; } - - errno = save_errno; } /* @@ -922,8 +925,8 @@ EnableNotifyInterrupt(void) * a frontend command. Signal handler execution of inbound notifies * is disabled until the next EnableNotifyInterrupt call. * - * The SIGUSR1 signal handler also needs to call this, so as to - * prevent conflicts if one signal interrupts the other. So we + * The PROCSIG_CATCHUP_INTERRUPT signal handler also needs to call this, + * so as to prevent conflicts if one signal interrupts the other. So we * must return the previous state of the flag. */ bool @@ -940,8 +943,8 @@ DisableNotifyInterrupt(void) * ProcessIncomingNotify * * Deal with arriving NOTIFYs from other backends. - * This is called either directly from the SIGUSR2 signal handler, - * or the next time control reaches the outer idle loop. + * This is called either directly from the PROCSIG_NOTIFY_INTERRUPT + * signal handler, or the next time control reaches the outer idle loop. * Scan pg_listener for arriving notifies, report them to my front end, * and clear the notification field in pg_listener until next time. * @@ -961,7 +964,7 @@ ProcessIncomingNotify(void) nulls[Natts_pg_listener]; bool catchup_enabled; - /* Must prevent SIGUSR1 interrupt while I am running */ + /* Must prevent catchup interrupt while I am running */ catchup_enabled = DisableCatchupInterrupt(); if (Trace_notify) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index a5388678d6..34c4a4a428 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -55,7 +55,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.99 2009/06/12 16:17:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.100 2009/07/31 20:26:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -91,6 +91,7 @@ #include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/procarray.h" +#include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "tcop/tcopprot.h" #include "utils/dynahash.h" @@ -436,7 +437,6 @@ AutoVacLauncherMain(int argc, char *argv[]) pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, avl_sigusr1_handler); - /* We don't listen for async notifies */ pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); pqsignal(SIGCHLD, SIG_DFL); @@ -1322,7 +1322,7 @@ avl_sighup_handler(SIGNAL_ARGS) got_SIGHUP = true; } -/* SIGUSR1: a worker is up and running, or just finished */ +/* SIGUSR1: a worker is up and running, or just finished, or failed to fork */ static void avl_sigusr1_handler(SIGNAL_ARGS) { @@ -1501,8 +1501,7 @@ AutoVacWorkerMain(int argc, char *argv[]) pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, CatchupInterruptHandler); - /* We don't listen for async notifies */ + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); pqsignal(SIGCHLD, SIG_DFL); diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 831ea9478a..bcdb5d7bb7 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -38,7 +38,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.62 2009/06/26 20:29:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.63 2009/07/31 20:26:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -223,7 +223,7 @@ BackgroundWriterMain(void) * tell us it's okay to shut down (via SIGUSR2). * * SIGUSR1 is presently unused; keep it spare in case someday we want this - * process to participate in sinval messaging. + * process to participate in ProcSignal signalling. */ pqsignal(SIGHUP, BgSigHupHandler); /* set flag to read config file */ pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */ @@ -231,7 +231,7 @@ BackgroundWriterMain(void) pqsignal(SIGQUIT, bg_quickdie); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, SIG_IGN); /* reserve for sinval */ + pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */ pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */ /* diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 9e08a5b710..7f13e682a5 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -34,7 +34,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/walwriter.c,v 1.7 2009/06/11 14:49:01 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/walwriter.c,v 1.8 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -113,7 +113,7 @@ WalWriterMain(void) pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, SIG_IGN); /* reserve for sinval */ + pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */ pqsignal(SIGUSR2, SIG_IGN); /* not used */ /* diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index cc74f8812b..20ac1e75e4 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -1,7 +1,7 @@ # # Makefile for storage/ipc # -# $PostgreSQL: pgsql/src/backend/storage/ipc/Makefile,v 1.21 2008/02/19 10:30:08 petere Exp $ +# $PostgreSQL: pgsql/src/backend/storage/ipc/Makefile,v 1.22 2009/07/31 20:26:23 tgl Exp $ # subdir = src/backend/storage/ipc @@ -15,7 +15,7 @@ override CFLAGS+= -fno-inline endif endif -OBJS = ipc.o ipci.o pmsignal.o procarray.o shmem.o shmqueue.o \ +OBJS = ipc.o ipci.o pmsignal.o procarray.o procsignal.o shmem.o shmqueue.o \ sinval.o sinvaladt.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 281215d218..bd4f168bfb 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.100 2009/05/05 19:59:00 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.101 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,6 +30,7 @@ #include "storage/pg_shmem.h" #include "storage/pmsignal.h" #include "storage/procarray.h" +#include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "storage/spin.h" @@ -112,6 +113,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) size = add_size(size, BackendStatusShmemSize()); size = add_size(size, SInvalShmemSize()); size = add_size(size, PMSignalShmemSize()); + size = add_size(size, ProcSignalShmemSize()); size = add_size(size, BgWriterShmemSize()); size = add_size(size, AutoVacuumShmemSize()); size = add_size(size, BTreeShmemSize()); @@ -208,6 +210,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) * Set up interprocess signaling mechanisms */ PMSignalShmemInit(); + ProcSignalShmemInit(); BgWriterShmemInit(); AutoVacuumShmemInit(); diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c new file mode 100644 index 0000000000..9da2c5201e --- /dev/null +++ b/src/backend/storage/ipc/procsignal.c @@ -0,0 +1,262 @@ +/*------------------------------------------------------------------------- + * + * procsignal.c + * Routines for interprocess signalling + * + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/storage/ipc/procsignal.c,v 1.1 2009/07/31 20:26:23 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include + +#include "bootstrap/bootstrap.h" +#include "commands/async.h" +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/procsignal.h" +#include "storage/shmem.h" +#include "storage/sinval.h" + + +/* + * The SIGUSR1 signal is multiplexed to support signalling multiple event + * types. 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 to a process concurrently. (However, if the same + * reason is signaled more than once nearly simultaneously, the process may + * observe it only once.) + * + * Each process that wants to receive signals registers its process ID + * in the ProcSignalSlots array. The array is indexed by backend ID to make + * slot allocation simple, and to avoid having to search the array when you + * know the backend ID of the process you're signalling. (We do support + * signalling without backend ID, but it's a bit less efficient.) + * + * 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. + */ +typedef struct +{ + pid_t pss_pid; + sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS]; +} ProcSignalSlot; + +/* + * We reserve a slot for each possible BackendId, plus one for each + * possible auxiliary process type. (This scheme assumes there is not + * more than one of any auxiliary process type at a time.) + */ +#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES) + +static ProcSignalSlot *ProcSignalSlots = NULL; +static volatile ProcSignalSlot *MyProcSignalSlot = NULL; + +static bool CheckProcSignal(ProcSignalReason reason); +static void CleanupProcSignalState(int status, Datum arg); + +/* + * ProcSignalShmemInit + * Compute space needed for procsignal's shared memory + */ +Size +ProcSignalShmemSize(void) +{ + return NumProcSignalSlots * sizeof(ProcSignalSlot); +} + +/* + * ProcSignalShmemInit + * Allocate and initialize procsignal's shared memory + */ +void +ProcSignalShmemInit(void) +{ + Size size = ProcSignalShmemSize(); + bool found; + + ProcSignalSlots = (ProcSignalSlot *) + ShmemInitStruct("ProcSignalSlots", size, &found); + + /* If we're first, set everything to zeroes */ + if (!found) + MemSet(ProcSignalSlots, 0, size); +} + +/* + * ProcSignalInit + * Register the current process in the procsignal array + * + * The passed index should be my BackendId if the process has one, + * or MaxBackends + aux process type if not. + */ +void +ProcSignalInit(int pss_idx) +{ + volatile ProcSignalSlot *slot; + + Assert(pss_idx >= 1 && pss_idx <= NumProcSignalSlots); + + slot = &ProcSignalSlots[pss_idx - 1]; + + /* sanity check */ + if (slot->pss_pid != 0) + elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty", + MyProcPid, pss_idx); + + /* Clear out any leftover signal reasons */ + MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t)); + + /* Mark slot with my PID */ + slot->pss_pid = MyProcPid; + + /* Remember slot location for CheckProcSignal */ + MyProcSignalSlot = slot; + + /* Set up to release the slot on process exit */ + on_shmem_exit(CleanupProcSignalState, Int32GetDatum(pss_idx)); +} + +/* + * CleanupProcSignalState + * Remove current process from ProcSignalSlots + * + * This function is called via on_shmem_exit() during backend shutdown. + */ +static void +CleanupProcSignalState(int status, Datum arg) +{ + int pss_idx = DatumGetInt32(arg); + volatile ProcSignalSlot *slot; + + slot = &ProcSignalSlots[pss_idx - 1]; + Assert(slot == MyProcSignalSlot); + + /* sanity check */ + if (slot->pss_pid != MyProcPid) + { + /* + * don't ERROR here. We're exiting anyway, and don't want to + * get into infinite loop trying to exit + */ + elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d", + MyProcPid, pss_idx, (int) slot->pss_pid); + return; /* XXX better to zero the slot anyway? */ + } + + slot->pss_pid = 0; +} + +/* + * SendProcSignal + * Send a signal to a Postgres process + * + * Providing backendId is optional, but it will speed up the operation. + * + * On success (a signal was sent), zero is returned. + * On error, -1 is returned, and errno is set (typically to ESRCH or EPERM). + * + * Not to be confused with ProcSendSignal + */ +int +SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId) +{ + volatile ProcSignalSlot *slot; + + if (backendId != InvalidBackendId) + { + slot = &ProcSignalSlots[backendId - 1]; + + /* + * Note: Since there's no locking, it's possible that the target + * process detaches from shared memory and exits right after this + * test, before we set the flag and send signal. And the signal slot + * might even be recycled by a new process, so it's remotely possible + * that we set a flag for a wrong process. That's OK, all the signals + * are such that no harm is done if they're mistakenly fired. + */ + if (slot->pss_pid == pid) + { + /* Atomically set the proper flag */ + slot->pss_signalFlags[reason] = true; + /* Send signal */ + return kill(pid, SIGUSR1); + } + } + else + { + /* + * BackendId not provided, so search the array using pid. We search + * the array back to front so as to reduce search overhead. Passing + * InvalidBackendId means that the target is most likely an auxiliary + * process, which will have a slot near the end of the array. + */ + int i; + + for (i = NumProcSignalSlots - 1; i >= 0; i--) + { + slot = &ProcSignalSlots[i]; + + if (slot->pss_pid == pid) + { + /* the above note about race conditions applies here too */ + + /* Atomically set the proper flag */ + slot->pss_signalFlags[reason] = true; + /* Send signal */ + return kill(pid, SIGUSR1); + } + } + } + + errno = ESRCH; + return -1; +} + +/* + * CheckProcSignal - check to see if a particular reason has been + * signaled, and clear the signal flag. Should be called after receiving + * SIGUSR1. + */ +static bool +CheckProcSignal(ProcSignalReason reason) +{ + volatile ProcSignalSlot *slot = MyProcSignalSlot; + + if (slot != NULL) + { + /* Careful here --- don't clear flag if we haven't seen it set */ + if (slot->pss_signalFlags[reason]) + { + slot->pss_signalFlags[reason] = false; + return true; + } + } + + return false; +} + +/* + * procsignal_sigusr1_handler - handle SIGUSR1 signal. + */ +void +procsignal_sigusr1_handler(SIGNAL_ARGS) +{ + int save_errno = errno; + + if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) + HandleCatchupInterrupt(); + + if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT)) + HandleNotifyInterrupt(); + + errno = save_errno; +} diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c index 3f063989e0..1b6f3b2fc4 100644 --- a/src/backend/storage/ipc/sinval.c +++ b/src/backend/storage/ipc/sinval.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.90 2009/06/11 14:49:02 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.91 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,8 +26,8 @@ * Because backends sitting idle will not be reading sinval events, we * need a way to give an idle backend a swift kick in the rear and make * it catch up before the sinval queue overflows and forces it to go - * through a cache reset exercise. This is done by sending SIGUSR1 - * to any backend that gets too far behind. + * through a cache reset exercise. This is done by sending + * PROCSIG_CATCHUP_INTERRUPT to any backend that gets too far behind. * * State for catchup events consists of two flags: one saying whether * the signal handler is currently allowed to call ProcessCatchupEvent @@ -145,9 +145,9 @@ ReceiveSharedInvalidMessages( /* - * CatchupInterruptHandler + * HandleCatchupInterrupt * - * This is the signal handler for SIGUSR1. + * This is called when PROCSIG_CATCHUP_INTERRUPT is received. * * If we are idle (catchupInterruptEnabled is set), we can safely * invoke ProcessCatchupEvent directly. Otherwise, just set a flag @@ -157,13 +157,11 @@ ReceiveSharedInvalidMessages( * since there's no longer any reason to do anything.) */ void -CatchupInterruptHandler(SIGNAL_ARGS) +HandleCatchupInterrupt(void) { - int save_errno = errno; - /* - * Note: this is a SIGNAL HANDLER. You must be very wary what you do - * here. + * Note: this is called by a SIGNAL HANDLER. You must be very wary what + * you do here. */ /* Don't joggle the elbow of proc_exit */ @@ -217,8 +215,6 @@ CatchupInterruptHandler(SIGNAL_ARGS) */ catchupInterruptOccurred = 1; } - - errno = save_errno; } /* @@ -273,8 +269,8 @@ EnableCatchupInterrupt(void) * a frontend command. Signal handler execution of catchup events * is disabled until the next EnableCatchupInterrupt call. * - * The SIGUSR2 signal handler also needs to call this, so as to - * prevent conflicts if one signal interrupts the other. So we + * The PROCSIG_NOTIFY_INTERRUPT signal handler also needs to call this, + * so as to prevent conflicts if one signal interrupts the other. So we * must return the previous state of the flag. */ bool @@ -290,18 +286,19 @@ DisableCatchupInterrupt(void) /* * ProcessCatchupEvent * - * Respond to a catchup event (SIGUSR1) from another backend. + * Respond to a catchup event (PROCSIG_CATCHUP_INTERRUPT) from another + * backend. * - * This is called either directly from the SIGUSR1 signal handler, - * or the next time control reaches the outer idle loop (assuming - * there's still anything to do by then). + * This is called either directly from the PROCSIG_CATCHUP_INTERRUPT + * signal handler, or the next time control reaches the outer idle loop + * (assuming there's still anything to do by then). */ static void ProcessCatchupEvent(void) { bool notify_enabled; - /* Must prevent SIGUSR2 interrupt while I am running */ + /* Must prevent notify interrupt while I am running */ notify_enabled = DisableNotifyInterrupt(); /* diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index fcd1e42a7f..dfa0ad7b5e 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.78 2009/06/11 14:49:02 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.79 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "storage/backendid.h" #include "storage/ipc.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "storage/shmem.h" #include "storage/sinvaladt.h" #include "storage/spin.h" @@ -118,7 +119,7 @@ * we exceed CLEANUP_MIN. Should be a power of 2 for speed. * * SIG_THRESHOLD: the minimum number of messages a backend must have fallen - * behind before we'll send it SIGUSR1. + * behind before we'll send it PROCSIG_CATCHUP_INTERRUPT. * * WRITE_QUANTUM: the max number of messages to push into the buffer per * iteration of SIInsertDataEntries. Noncritical but should be less than @@ -551,7 +552,7 @@ SIGetDataEntries(SharedInvalidationMessage *data, int datasize) * minFree is the minimum number of message slots to make free. * * Possible side effects of this routine include marking one or more - * backends as "reset" in the array, and sending a catchup interrupt (SIGUSR1) + * backends as "reset" in the array, and sending PROCSIG_CATCHUP_INTERRUPT * to some backend that seems to be getting too far behind. We signal at * most one backend at a time, for reasons explained at the top of the file. * @@ -644,18 +645,20 @@ SICleanupQueue(bool callerHasWriteLock, int minFree) segP->nextThreshold = (numMsgs / CLEANUP_QUANTUM + 1) * CLEANUP_QUANTUM; /* - * Lastly, signal anyone who needs a catchup interrupt. Since kill() - * might not be fast, we don't want to hold locks while executing it. + * Lastly, signal anyone who needs a catchup interrupt. Since + * SendProcSignal() might not be fast, we don't want to hold locks while + * executing it. */ if (needSig) { pid_t his_pid = needSig->procPid; + BackendId his_backendId = (needSig - &segP->procState[0]) + 1; needSig->signaled = true; LWLockRelease(SInvalReadLock); LWLockRelease(SInvalWriteLock); elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid); - kill(his_pid, SIGUSR1); + SendProcSignal(his_pid, PROCSIG_CATCHUP_INTERRUPT, his_backendId); if (callerHasWriteLock) LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 43e912f5cf..42e7f79f70 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.568 2009/06/18 10:08:08 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.569 2009/07/31 20:26:23 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -59,6 +59,7 @@ #include "storage/bufmgr.h" #include "storage/ipc.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "storage/sinval.h" #include "tcop/fastpath.h" #include "tcop/pquery.h" @@ -3221,8 +3222,8 @@ PostgresMain(int argc, char *argv[], const char *username) * of output during who-knows-what operation... */ pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, CatchupInterruptHandler); - pqsignal(SIGUSR2, NotifyInterruptHandler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); + pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); /* diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index bdb2fec104..e6a63c0269 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.192 2009/07/08 17:53:29 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.193 2009/07/31 20:26:23 tgl Exp $ * * *------------------------------------------------------------------------- @@ -39,6 +39,7 @@ #include "storage/lmgr.h" #include "storage/proc.h" #include "storage/procarray.h" +#include "storage/procsignal.h" #include "storage/sinvaladt.h" #include "storage/smgr.h" #include "utils/acl.h" @@ -451,6 +452,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); + /* Now that we have a BackendId, we can participate in ProcSignal */ + ProcSignalInit(MyBackendId); + /* * bufmgr needs another initialization call too */ diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index ab549eabb1..acc6468f9d 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.51 2009/01/01 17:23:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.52 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -70,7 +70,9 @@ typedef enum BootstrapProcess, StartupProcess, BgWriterProcess, - WalWriterProcess + WalWriterProcess, + + NUM_AUXPROCTYPES /* Must be last! */ } AuxProcType; #endif /* BOOTSTRAP_H */ diff --git a/src/include/commands/async.h b/src/include/commands/async.h index 789a8d9c79..5ee10f583c 100644 --- a/src/include/commands/async.h +++ b/src/include/commands/async.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/async.h,v 1.37 2009/01/01 17:23:58 momjian Exp $ + * $PostgreSQL: pgsql/src/include/commands/async.h,v 1.38 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,8 +29,8 @@ extern void AtSubCommit_Notify(void); extern void AtSubAbort_Notify(void); extern void AtPrepare_Notify(void); -/* signal handler for inbound notifies (SIGUSR2) */ -extern void NotifyInterruptHandler(SIGNAL_ARGS); +/* signal handler for inbound notifies (PROCSIG_NOTIFY_INTERRUPT) */ +extern void HandleNotifyInterrupt(void); /* * enable/disable processing of inbound notifies directly from signal handler. diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h new file mode 100644 index 0000000000..8f493ac77f --- /dev/null +++ b/src/include/storage/procsignal.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * procsignal.h + * Routines for interprocess signalling + * + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/storage/procsignal.h,v 1.1 2009/07/31 20:26:23 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef PROCSIGNAL_H +#define PROCSIGNAL_H + +#include "storage/backendid.h" + + +/* + * Reasons for signalling a Postgres child process (a backend or an auxiliary + * process, like bgwriter). We can cope with concurrent signals for different + * reasons. However, if the same reason is signaled multiple times in quick + * succession, the process is likely to observe only one notification of it. + * This is okay for the present uses. + * + * Also, because of race conditions, it's important that all the signals be + * defined so that no harm is done if a process mistakenly receives one. + */ +typedef enum +{ + PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ + PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ + + NUM_PROCSIGNALS /* Must be last! */ +} ProcSignalReason; + +/* + * prototypes for functions in procsignal.c + */ +extern Size ProcSignalShmemSize(void); +extern void ProcSignalShmemInit(void); + +extern void ProcSignalInit(int pss_idx); +extern int SendProcSignal(pid_t pid, ProcSignalReason reason, + BackendId backendId); + +extern void procsignal_sigusr1_handler(SIGNAL_ARGS); + +#endif /* PROCSIGNAL_H */ diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h index f332ec285e..84edb5b31e 100644 --- a/src/include/storage/sinval.h +++ b/src/include/storage/sinval.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.52 2009/06/11 14:49:12 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.53 2009/07/31 20:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -89,8 +89,8 @@ extern void ReceiveSharedInvalidMessages( void (*invalFunction) (SharedInvalidationMessage *msg), void (*resetFunction) (void)); -/* signal handler for catchup events (SIGUSR1) */ -extern void CatchupInterruptHandler(SIGNAL_ARGS); +/* signal handler for catchup events (PROCSIG_CATCHUP_INTERRUPT) */ +extern void HandleCatchupInterrupt(void); /* * enable/disable processing of catchup events directly from signal handler.