* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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();
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
#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"
/*
* 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
}
/*
- * 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 */
/*
* 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.
*/
{
/* 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");
}
}
*/
notifyInterruptOccurred = 1;
}
-
- errno = save_errno;
}
/*
* 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
* 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.
*
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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);
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)
{
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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 */
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 */
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
/*
#
# 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
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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());
* Set up interprocess signaling mechanisms
*/
PMSignalShmemInit();
+ ProcSignalShmemInit();
BgWriterShmemInit();
AutoVacuumShmemInit();
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 <signal.h>
+#include <unistd.h>
+
+#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;
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
/*
- * 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
* 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 */
*/
catchupInterruptOccurred = 1;
}
-
- errno = save_errno;
}
/*
* 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
/*
* 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();
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
* 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
* 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.
*
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);
}
*
*
* 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
#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"
* 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);
/*
*
*
* 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 $
*
*
*-------------------------------------------------------------------------
#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"
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
*/
* 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 $
*
*-------------------------------------------------------------------------
*/
BootstrapProcess,
StartupProcess,
BgWriterProcess,
- WalWriterProcess
+ WalWriterProcess,
+
+ NUM_AUXPROCTYPES /* Must be last! */
} AuxProcType;
#endif /* BOOTSTRAP_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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.