diff -rcN base/src/backend/bootstrap/bootstrap.c new/src/backend/bootstrap/bootstrap.c *** base/src/backend/bootstrap/bootstrap.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/bootstrap/bootstrap.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 35,40 **** --- 35,41 ---- #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,393 **** --- 389,404 ---- InitAuxiliaryProcess(); #endif + /* + * Assign the ProcSignalSlot to an auxiliary process. Since it doesn't + * have backend ID, the slot which lies behind the ProcSignalSlot array + * is statically allocated to it according to the process type (auxType). + * Backends use the slot 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. + */ + ProcSignalInit(MaxBackends + auxType + 1); + /* finish setting up bufmgr.c */ InitBufferPoolBackend(); diff -rcN base/src/backend/commands/async.c new/src/backend/commands/async.c *** base/src/backend/commands/async.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/commands/async.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 35,48 **** * 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). * 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 * processing to occur just before we next go idle. * * 5. Inbound-notify processing consists of scanning pg_listener for tuples --- 35,49 ---- * 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 ! * 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 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,100 **** --- 96,102 ---- #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,645 **** /* * 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. */ ! if (kill(listenerPID, SIGUSR2) < 0) { /* * Get rid of pg_listener entry if it refers to a PID that no --- 636,648 ---- /* * If someone has already notified this listener, we don't bother ! * modifying the table, but we do still send a PROCSIG_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. */ ! if (SendProcSignal(listenerPID, PROCSIG_NOTIFY_INTERRUPT, ! InvalidBackendId) < 0) { /* * Get rid of pg_listener entry if it refers to a PID that no *************** *** 777,797 **** } /* ! * NotifyInterruptHandler * ! * This is the signal handler for SIGUSR2. * * 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) { - 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. --- 780,798 ---- } /* ! * HandleNotifyInterrupt * ! * This is called when PROCSIG_NOTIFY_INTERRUPT signal 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 ! HandleNotifyInterrupt(void) { /* ! * 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. *************** *** 815,821 **** /* * I'm not sure whether some flavors of Unix might allow another ! * SIGUSR2 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. */ --- 816,822 ---- /* * I'm not sure whether some flavors of Unix might allow another ! * 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. */ *************** *** 854,861 **** */ notifyInterruptOccurred = 1; } - - errno = save_errno; } /* --- 855,860 ---- *************** *** 922,929 **** * 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 * must return the previous state of the flag. */ bool --- 921,928 ---- * a frontend command. Signal handler execution of inbound notifies * is disabled until the next EnableNotifyInterrupt call. * ! * 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,947 **** * 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. * Scan pg_listener for arriving notifies, report them to my front end, * and clear the notification field in pg_listener until next time. * --- 939,946 ---- * ProcessIncomingNotify * * Deal with arriving NOTIFYs from other backends. ! * 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,967 **** nulls[Natts_pg_listener]; bool catchup_enabled; ! /* Must prevent SIGUSR1 interrupt while I am running */ catchup_enabled = DisableCatchupInterrupt(); if (Trace_notify) --- 960,966 ---- nulls[Natts_pg_listener]; bool catchup_enabled; ! /* Must prevent catchup interrupt while I am running */ catchup_enabled = DisableCatchupInterrupt(); if (Trace_notify) diff -rcN base/src/backend/postmaster/autovacuum.c new/src/backend/postmaster/autovacuum.c *** base/src/backend/postmaster/autovacuum.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/postmaster/autovacuum.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 91,96 **** --- 91,97 ---- #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" *************** *** 1501,1507 **** pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, CatchupInterruptHandler); /* We don't listen for async notifies */ pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); --- 1502,1508 ---- pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, procsignal_sigusr1_handler); /* We don't listen for async notifies */ pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); diff -rcN base/src/backend/storage/ipc/Makefile new/src/backend/storage/ipc/Makefile *** base/src/backend/storage/ipc/Makefile 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/storage/ipc/Makefile 2009-07-29 18:35:46.000000000 +0900 *************** *** 15,21 **** endif endif ! OBJS = ipc.o ipci.o pmsignal.o procarray.o shmem.o shmqueue.o \ sinval.o sinvaladt.o include $(top_srcdir)/src/backend/common.mk --- 15,21 ---- endif endif ! 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 -rcN base/src/backend/storage/ipc/ipci.c new/src/backend/storage/ipc/ipci.c *** base/src/backend/storage/ipc/ipci.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/storage/ipc/ipci.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 30,35 **** --- 30,36 ---- #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" *************** *** 114,119 **** --- 115,121 ---- size = add_size(size, PMSignalShmemSize()); size = add_size(size, BgWriterShmemSize()); size = add_size(size, AutoVacuumShmemSize()); + size = add_size(size, ProcSignalShmemSize()); size = add_size(size, BTreeShmemSize()); size = add_size(size, SyncScanShmemSize()); #ifdef EXEC_BACKEND *************** *** 210,215 **** --- 212,218 ---- PMSignalShmemInit(); BgWriterShmemInit(); AutoVacuumShmemInit(); + ProcSignalShmemInit(); /* * Set up other modules that need some shared memory space diff -rcN base/src/backend/storage/ipc/procsignal.c new/src/backend/storage/ipc/procsignal.c *** base/src/backend/storage/ipc/procsignal.c 1970-01-01 09:00:00.000000000 +0900 --- new/src/backend/storage/ipc/procsignal.c 2009-07-29 18:45:25.000000000 +0900 *************** *** 0 **** --- 1,248 ---- + /*------------------------------------------------------------------------- + * + * procsignal.c + * routines for signaling processes + * + * + * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ + #include "postgres.h" + + #include + #include + + #include "bootstrap/bootstrap.h" + #include "commands/async.h" + #include "miscadmin.h" + #include "storage/backendid.h" + #include "storage/ipc.h" + #include "storage/procsignal.h" + #include "storage/shmem.h" + #include "storage/sinval.h" + + /* + * SIGUSR1 signal is multiplexed for multiple events. 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 process will 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 signaling. + * + * 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; + + static ProcSignalSlot *ProcSignalSlots; + + static bool CheckProcSignal(ProcSignalReason reason); + static void CleanupProcSignalState(int status, Datum arg); + + /* + * ProcSignalShmemInit - initialize during shared-memory creation + */ + Size + ProcSignalShmemSize(void) + { + return (MaxBackends + NUM_AUXPROCTYPE) * sizeof(ProcSignalSlot); + } + + /* + * ProcSignalShmemInit - initialize during shared-memory creation + */ + void + ProcSignalShmemInit(void) + { + bool found; + + ProcSignalSlots = (ProcSignalSlot *) + ShmemInitStruct("ProcSignalSlots", ProcSignalShmemSize(), + &found); + + if (!found) + MemSet(ProcSignalSlots, 0, ProcSignalShmemSize()); + } + + /* + * ProcSignalInit - register a process to the procsignal array + */ + void + ProcSignalInit(int pss_idx) + { + volatile ProcSignalSlot *slot; + + Assert(pss_idx >= 1 && + pss_idx <= MaxBackends + NUM_AUXPROCTYPE); + + slot = &ProcSignalSlots[pss_idx - 1]; + MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t)); + slot->pss_pid = MyProcPid; + + 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]; + + /* 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(WARNING, "current process not in ProcSignalSlots array"); + return; + } + slot->pss_pid = 0; + } + + /* + * SendProcSignal - signal a process with a reason code + * + * Providing backendId is optional, but it will speed up the operation. + * + * On success (at least one signal was sent), zero is returned. On error, + * -1 is returned. + * + * 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 + { + /* + * Same as above, but linear search the array using pid. Search the + * array back to front so as to reduce the search overhead. Passing + * InvalidBackendId means that the target is most likely an auxiliary + * process. Its slot lies behind the array, so the backward search + * is efficient here. + */ + int i; + for (i = MaxBackends + NUM_AUXPROCTYPE - 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); + } + } + } + + 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; + + if (MyBackendId != InvalidBackendId) + { + slot = &ProcSignalSlots[MyBackendId - 1]; + + /* 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; + } + } + else + { + int i; + for (i = MaxBackends + NUM_AUXPROCTYPE - 1; i >= 0; i--) + { + slot = &ProcSignalSlots[i]; + if (slot->pss_pid == MyProcPid) + { + /* 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; + } + + break; + } + } + } + + 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 -rcN base/src/backend/storage/ipc/sinval.c new/src/backend/storage/ipc/sinval.c *** base/src/backend/storage/ipc/sinval.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/storage/ipc/sinval.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 26,33 **** * 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. * * State for catchup events consists of two flags: one saying whether * the signal handler is currently allowed to call ProcessCatchupEvent --- 26,33 ---- * 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 ! * PROCSIG_CATHCUP_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,153 **** /* ! * CatchupInterruptHandler * ! * This is the signal handler for SIGUSR1. * * If we are idle (catchupInterruptEnabled is set), we can safely * invoke ProcessCatchupEvent directly. Otherwise, just set a flag --- 145,153 ---- /* ! * HandleCatchupInterrupt * ! * This is called when PROCSIG_CATCHUP_INTERRUPT signal is received. * * If we are idle (catchupInterruptEnabled is set), we can safely * invoke ProcessCatchupEvent directly. Otherwise, just set a flag *************** *** 157,169 **** * since there's no longer any reason to do anything.) */ void ! CatchupInterruptHandler(SIGNAL_ARGS) { - int save_errno = errno; - /* ! * Note: this is a SIGNAL HANDLER. You must be very wary what you do ! * here. */ /* Don't joggle the elbow of proc_exit */ --- 157,167 ---- * since there's no longer any reason to do anything.) */ void ! HandleCatchupInterrupt(void) { /* ! * 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,224 **** */ catchupInterruptOccurred = 1; } - - errno = save_errno; } /* --- 215,220 ---- *************** *** 273,280 **** * 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 * must return the previous state of the flag. */ bool --- 269,276 ---- * a frontend command. Signal handler execution of catchup events * is disabled until the next EnableCatchupInterrupt call. * ! * 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,307 **** /* * ProcessCatchupEvent * ! * Respond to a catchup event (SIGUSR1) 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). */ static void ProcessCatchupEvent(void) { bool notify_enabled; ! /* Must prevent SIGUSR2 interrupt while I am running */ notify_enabled = DisableNotifyInterrupt(); /* --- 286,304 ---- /* * ProcessCatchupEvent * ! * Respond to a catchup event (PROCSIG_CATCHUP_INTERRUPT) from another ! * backend. * ! * 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 notify interrupt while I am running */ notify_enabled = DisableNotifyInterrupt(); /* diff -rcN base/src/backend/storage/ipc/sinvaladt.c new/src/backend/storage/ipc/sinvaladt.c *** base/src/backend/storage/ipc/sinvaladt.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/storage/ipc/sinvaladt.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 21,26 **** --- 21,27 ---- #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" *************** *** 138,143 **** --- 139,145 ---- { /* procPid is zero in an inactive ProcState array entry. */ pid_t procPid; /* PID of backend, for signaling */ + BackendId backendId; /* backend ID, for signaling */ /* nextMsgNum is meaningless if procPid == 0 or resetState is true. */ int nextMsgNum; /* next message number to read */ bool resetState; /* backend needs to reset its state */ *************** *** 236,241 **** --- 238,244 ---- for (i = 0; i < shmInvalBuffer->maxBackends; i++) { shmInvalBuffer->procState[i].procPid = 0; /* inactive */ + shmInvalBuffer->procState[i].backendId = InvalidBackendId; shmInvalBuffer->procState[i].nextMsgNum = 0; /* meaningless */ shmInvalBuffer->procState[i].resetState = false; shmInvalBuffer->procState[i].signaled = false; *************** *** 304,309 **** --- 307,313 ---- /* mark myself active, with all extant messages already read */ stateP->procPid = MyProcPid; + stateP->backendId = MyBackendId; stateP->nextMsgNum = segP->maxMsgNum; stateP->resetState = false; stateP->signaled = false; *************** *** 342,347 **** --- 346,352 ---- /* Mark myself inactive */ stateP->procPid = 0; + stateP->backendId = InvalidBackendId; stateP->nextMsgNum = 0; stateP->resetState = false; stateP->signaled = false; *************** *** 644,661 **** 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. */ if (needSig) { ! pid_t his_pid = needSig->procPid; needSig->signaled = true; LWLockRelease(SInvalReadLock); LWLockRelease(SInvalWriteLock); elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid); ! kill(his_pid, SIGUSR1); if (callerHasWriteLock) LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); } --- 649,668 ---- segP->nextThreshold = (numMsgs / CLEANUP_QUANTUM + 1) * CLEANUP_QUANTUM; /* ! * 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->backendId; needSig->signaled = true; LWLockRelease(SInvalReadLock); LWLockRelease(SInvalWriteLock); elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid); ! SendProcSignal(his_pid, PROCSIG_CATCHUP_INTERRUPT, his_backendId); if (callerHasWriteLock) LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); } diff -rcN base/src/backend/tcop/postgres.c new/src/backend/tcop/postgres.c *** base/src/backend/tcop/postgres.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/tcop/postgres.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 59,64 **** --- 59,65 ---- #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,3228 **** * of output during who-knows-what operation... */ pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, CatchupInterruptHandler); ! pqsignal(SIGUSR2, NotifyInterruptHandler); pqsignal(SIGFPE, FloatExceptionHandler); /* --- 3222,3229 ---- * of output during who-knows-what operation... */ pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, procsignal_sigusr1_handler); ! pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); /* diff -rcN base/src/backend/utils/init/postinit.c new/src/backend/utils/init/postinit.c *** base/src/backend/utils/init/postinit.c 2009-07-29 18:35:42.000000000 +0900 --- new/src/backend/utils/init/postinit.c 2009-07-29 18:35:46.000000000 +0900 *************** *** 39,44 **** --- 39,45 ---- #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,456 **** --- 452,459 ---- if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); + ProcSignalInit(MyBackendId); + /* * bufmgr needs another initialization call too */ diff -rcN base/src/include/bootstrap/bootstrap.h new/src/include/bootstrap/bootstrap.h *** base/src/include/bootstrap/bootstrap.h 2009-07-29 18:35:42.000000000 +0900 --- new/src/include/bootstrap/bootstrap.h 2009-07-29 18:35:46.000000000 +0900 *************** *** 70,76 **** BootstrapProcess, StartupProcess, BgWriterProcess, ! WalWriterProcess } AuxProcType; #endif /* BOOTSTRAP_H */ --- 70,78 ---- BootstrapProcess, StartupProcess, BgWriterProcess, ! WalWriterProcess, ! ! NUM_AUXPROCTYPE } AuxProcType; #endif /* BOOTSTRAP_H */ diff -rcN base/src/include/commands/async.h new/src/include/commands/async.h *** base/src/include/commands/async.h 2009-07-29 18:35:42.000000000 +0900 --- new/src/include/commands/async.h 2009-07-29 18:35:46.000000000 +0900 *************** *** 29,36 **** extern void AtSubAbort_Notify(void); extern void AtPrepare_Notify(void); ! /* signal handler for inbound notifies (SIGUSR2) */ ! extern void NotifyInterruptHandler(SIGNAL_ARGS); /* * enable/disable processing of inbound notifies directly from signal handler. --- 29,36 ---- extern void AtSubAbort_Notify(void); extern void AtPrepare_Notify(void); ! /* signal handler for inbound notifies (PROCSIG_NOTIFY_INTERRUPT) */ ! extern void HandleNotifyInterrupt(void); /* * enable/disable processing of inbound notifies directly from signal handler. diff -rcN base/src/include/storage/procsignal.h new/src/include/storage/procsignal.h *** base/src/include/storage/procsignal.h 1970-01-01 09:00:00.000000000 +0900 --- new/src/include/storage/procsignal.h 2009-07-29 18:35:46.000000000 +0900 *************** *** 0 **** --- 1,45 ---- + /*------------------------------------------------------------------------- + * + * procsignal.h + * routines for signaling processes XXX + * + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ + #ifndef PROCSIGNAL_H + #define PROCSIGNAL_H + + #include "storage/backendid.h" + + + /* + * Reasons for signaling a process (a backend or an auxiliary process, like + * autovacuum worker). We can cope with simultaneous signals for different + * reasons. If the same reason is signaled multiple times in quick succession, + * however, the process is likely to observe only one notification of it. + * This is okay for the present uses. + */ + typedef enum + { + PROCSIG_CATCHUP_INTERRUPT, /* catchup interrupt */ + PROCSIG_NOTIFY_INTERRUPT, /* notify interrupt */ + NUM_PROCSIGNALS /* Must be last value of enum! */ + } 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 -rcN base/src/include/storage/sinval.h new/src/include/storage/sinval.h *** base/src/include/storage/sinval.h 2009-07-29 18:35:42.000000000 +0900 --- new/src/include/storage/sinval.h 2009-07-29 18:35:46.000000000 +0900 *************** *** 89,96 **** void (*invalFunction) (SharedInvalidationMessage *msg), void (*resetFunction) (void)); ! /* signal handler for catchup events (SIGUSR1) */ ! extern void CatchupInterruptHandler(SIGNAL_ARGS); /* * enable/disable processing of catchup events directly from signal handler. --- 89,96 ---- void (*invalFunction) (SharedInvalidationMessage *msg), void (*resetFunction) (void)); ! /* signal handler for catchup events (PROCSIG_CATCHUP_INTERRUPT) */ ! extern void HandleCatchupInterrupt(void); /* * enable/disable processing of catchup events directly from signal handler.