Hi,

On Wed, Dec 10, 2008 at 1:43 AM, Tom Lane <[EMAIL PROTECTED]> wrote:
> Heikki Linnakangas <[EMAIL PROTECTED]> writes:
>> I'm surprised you feel that way. You suggested earlier
>> (http://archives.postgresql.org/message-id/[EMAIL PROTECTED])
>> that a solution that only works for processes attached to shared memory
>> would probably suffice for now.
>
> Well, I wasn't complaining about the dependence on being attached to
> shared memory.  What I'm complaining about is the dependence on the
> rather complex PGPROC data structure.
>
>> That seems hard, considering that we also want it to work without
>> locking. Hmm, I presume we can use spinlocks in a signal handler?
>> Perhaps some sort of a hash table protected by a spinlock would work.
>
> No, locks are right out if the postmaster is supposed to be able to use
> it.  What I was thinking of is a simple linear array of PIDs and
> sig_atomic_t flags.  The slots could be assigned on the basis of
> backendid, but callers trying to send a signal would have to scan the
> array looking for the matching PID.  (This doesn't seem outlandishly
> expensive considering that one is about to do a kernel call anyway.
> You might be able to save a few cycles by having the PID array separate
> from the flag array, which should improve the cache friendliness of the
> scan.)  Also, for those callers who do have access to a PGPROC, there
> could be a separate entry point that passes backendid instead of PID to
> eliminate the search.

Thanks for the comment!
I updated the patch so. Is this patch ready to apply?

Regards,

-- 
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
diff -rc base/src/backend/bootstrap/bootstrap.c new/src/backend/bootstrap/bootstrap.c
*** base/src/backend/bootstrap/bootstrap.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/bootstrap/bootstrap.c	2008-12-10 17:16:23.000000000 +0900
***************
*** 389,394 ****
--- 389,403 ----
  		InitAuxiliaryProcess();
  #endif
  
+ 		/*
+ 		 * Assign backend ID to auxiliary processes like backends, in order to
+ 		 * allow multiplexing signal to auxiliary processes. Since backends use
+ 		 * ID in the range from 1 to MaxBackends, we assign auxiliary processes
+ 		 * with MaxBackends + AuxProcType as an unique ID.
+ 		 */
+ 		MyBackendId = MaxBackends + auxType;
+ 		MyProc->backendId = MyBackendId;
+ 
  		/* finish setting up bufmgr.c */
  		InitBufferPoolBackend();
  
diff -rc base/src/backend/commands/async.c new/src/backend/commands/async.c
*** base/src/backend/commands/async.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/commands/async.c	2008-12-10 17:27:31.000000000 +0900
***************
*** 915,923 ****
   *		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
  DisableNotifyInterrupt(void)
--- 915,924 ----
   *		a frontend command.  Signal handler execution of inbound notifies
   *		is disabled until the next EnableNotifyInterrupt call.
   *
!  *		This also needs to be called when SIGUSR1 with 
!  *		PROCSIG_CATCHUP_INTERRUPT is received, so as to prevent conflicts 
!  *		if one signal interrupts the other.  So we must return the previous 
!  *		state of the flag.
   */
  bool
  DisableNotifyInterrupt(void)
***************
*** 954,960 ****
  				nulls[Natts_pg_listener];
  	bool		catchup_enabled;
  
! 	/* Must prevent SIGUSR1 interrupt while I am running */
  	catchup_enabled = DisableCatchupInterrupt();
  
  	if (Trace_notify)
--- 955,961 ----
  				nulls[Natts_pg_listener];
  	bool		catchup_enabled;
  
! 	/* Must prevent catchup interrupt while I am running */
  	catchup_enabled = DisableCatchupInterrupt();
  
  	if (Trace_notify)
diff -rc base/src/backend/postmaster/autovacuum.c new/src/backend/postmaster/autovacuum.c
*** base/src/backend/postmaster/autovacuum.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/postmaster/autovacuum.c	2008-12-10 17:28:05.000000000 +0900
***************
*** 1477,1483 ****
  	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);
--- 1477,1483 ----
  	pqsignal(SIGALRM, handle_sig_alarm);
  
  	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, proc_sigusr1_handler);
  	/* We don't listen for async notifies */
  	pqsignal(SIGUSR2, SIG_IGN);
  	pqsignal(SIGFPE, FloatExceptionHandler);
diff -rc base/src/backend/storage/ipc/Makefile new/src/backend/storage/ipc/Makefile
*** base/src/backend/storage/ipc/Makefile	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/storage/ipc/Makefile	2008-12-10 17:24:58.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 procsignal.o pmsignal.o procarray.o shmem.o shmqueue.o \
  	sinval.o sinvaladt.o
  
  include $(top_srcdir)/src/backend/common.mk
diff -rc base/src/backend/storage/ipc/ipci.c new/src/backend/storage/ipc/ipci.c
*** base/src/backend/storage/ipc/ipci.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/storage/ipc/ipci.c	2008-12-10 18:14:15.000000000 +0900
***************
*** 205,210 ****
--- 205,211 ----
  	 * Set up interprocess signaling mechanisms
  	 */
  	PMSignalInit();
+ 	ProcSignalInit();
  	BgWriterShmemInit();
  	AutoVacuumShmemInit();
  
diff -rc base/src/backend/storage/ipc/procsignal.c new/src/backend/storage/ipc/procsignal.c
*** base/src/backend/storage/ipc/procsignal.c	2008-12-10 19:26:37.000000000 +0900
--- new/src/backend/storage/ipc/procsignal.c	2008-12-10 19:12:34.000000000 +0900
***************
*** 0 ****
--- 1,127 ----
+ /*-------------------------------------------------------------------------
+  *
+  * procsignal.c
+  *	  routines for signaling the backend, autovacuum worker and auxiliary process
+  *
+  *
+  * Portions Copyright (c) 1996-2008, 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.25 2008/01/01 19:45:51 momjian Exp $
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include <signal.h>
+ 
+ #include "bootstrap/bootstrap.h"
+ #include "miscadmin.h"
+ #include "storage/procsignal.h"
+ 
+ 
+ /*
+  * The backend, autovacuum worker and auxiliary process are sent SIGUSR1
+  * with the specific reason, which 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 processes at the same
+  * time. (However, if the same reason is signaled more than once
+  * simultaneously, the backend, autovacuum worker and auxiliary process
+  * 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.
+  */
+ typedef struct ProcSignalData {
+ 	pid_t					pid;
+ 	volatile sig_atomic_t	flags[NUM_PROCSIGNALS];
+ } ProcSignalData;
+ 
+ static ProcSignalData *ProcSignal;
+ static int MaxProcSignal;
+ 
+ /*
+  * ProcSignalInit - initialize during shared-memory creation
+  */
+ void
+ ProcSignalInit(void)
+ {
+ 	bool		found;
+ 
+ 	MaxProcSignal = MaxBackends + NUM_AUXPROCTYPE;
+ 
+ 	ProcSignal = (ProcSignalData *)
+ 		ShmemInitStruct("ProcSignal",
+ 						MaxProcSignal * sizeof(ProcSignal),
+ 						&found);
+ 
+ 	if (!found)
+ 		MemSet(ProcSignal, 0, MaxProcSignal * sizeof(ProcSignal));
+ }
+ 
+ /*
+  * SendProcSignal - signal the process (such as the backend, autovacuum
+  * worker and auxiliary process) identified by backend ID or pid.
+  */
+ void
+ SendProcSignal(BackendId bid, pid_t pid, ProcSignalReason reason)
+ {
+ 	ProcSignalData *procSig = NULL;
+ 	int				index;
+ 
+ 	Assert(bid < MaxProcSignal);
+ 
+ 	/*
+ 	 * Since ProcSignal array is assigned on the basis of backend ID,
+ 	 * we can get the target slot immediately if backend ID is passed.
+ 	 */
+ 	if (bid != InvalidBackendId)
+ 		procSig = &ProcSignal[bid];
+ 	else
+ 	{
+ 		if (pid == 0)	/* never match dummy ProcSignal */
+ 			return;
+ 		
+ 		for (index = 0; index < MaxProcSignal; index++)
+ 		{
+ 			ProcSignalData *psig = &ProcSignal[index];
+ 			
+ 			if (psig->pid == pid)
+ 			{
+ 				procSig = psig;
+ 				break;
+ 			}
+ 		}
+ 
+ 		/* don't signal if not found */
+ 		if (procSig == NULL)
+ 			return;
+ 	}
+ 	
+ 	/* Atomically set the proper flag */
+ 	procSig->flags[reason] = true;
+ 
+ 	/* Send signal to the process */
+ 	kill(procSig->pid, SIGUSR1);
+ }
+ 
+ /*
+  * CheckProcSignal - check to see if a particular reason has been
+  * signaled, and clear the signal flag.  Should be called after
+  * receiving SIGUSR1.
+  */
+ bool
+ CheckProcSignal(ProcSignalReason reason)
+ {
+ 	ProcSignalData *procSig = &ProcSignal[MyBackendId];
+ 
+ 	/* Careful here --- don't clear flag if we haven't seen it set */
+ 	if (procSig->flags[reason])
+ 	{
+ 		procSig->flags[reason] = false;
+ 		return true;
+ 	}
+ 	return false;
+ }
diff -rc base/src/backend/storage/ipc/sinval.c new/src/backend/storage/ipc/sinval.c
*** base/src/backend/storage/ipc/sinval.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/storage/ipc/sinval.c	2008-12-10 17:32:06.000000000 +0900
***************
*** 27,33 ****
   * 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
--- 27,34 ----
   * 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
!  * with 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
***************
*** 144,152 ****
  
  
  /*
!  * 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,154 ----
  
  
  /*
!  * HandleCatchupInterrupt
   *
!  * This is called when SIGUSR1 with PROCSIG_CATCHUP_INTERRUPT is
!  * received.
   *
   * If we are idle (catchupInterruptEnabled is set), we can safely
   * invoke ProcessCatchupEvent directly.  Otherwise, just set a flag
***************
*** 156,168 ****
   * 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 */
--- 158,168 ----
   * 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 */
***************
*** 216,223 ****
  		 */
  		catchupInterruptOccurred = 1;
  	}
- 
- 	errno = save_errno;
  }
  
  /*
--- 216,221 ----
***************
*** 289,295 ****
  /*
   * 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
--- 287,294 ----
  /*
   * ProcessCatchupEvent
   *
!  * Respond to a catchup event (SIGUSR1 with 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
diff -rc base/src/backend/storage/ipc/sinvaladt.c new/src/backend/storage/ipc/sinvaladt.c
*** base/src/backend/storage/ipc/sinvaladt.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/storage/ipc/sinvaladt.c	2008-12-10 19:13:06.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"
***************
*** 644,650 ****
  		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)
--- 645,651 ----
  		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)
***************
*** 655,661 ****
  		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);
  	}
--- 656,662 ----
  		LWLockRelease(SInvalReadLock);
  		LWLockRelease(SInvalWriteLock);
  		elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid);
! 		SendProcSignal(InvalidBackendId, his_pid, SIGUSR1);
  		if (callerHasWriteLock)
  			LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE);
  	}
diff -rc base/src/backend/tcop/postgres.c new/src/backend/tcop/postgres.c
*** base/src/backend/tcop/postgres.c	2008-12-10 16:29:10.000000000 +0900
--- new/src/backend/tcop/postgres.c	2008-12-10 19:13:42.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"
***************
*** 2437,2442 ****
--- 2438,2465 ----
   */
  
  /*
+  * proc_sigusr1_handler - handle SIGUSR1 signal.
+  *
+  * SIGUSR1 is multiplexed to handle multiple different events. The signalFlags
+  * array in PGPROC indicates which events have been signaled.
+  */
+ void
+ proc_sigusr1_handler(SIGNAL_ARGS)
+ {
+ 	int			save_errno = errno;
+ 	
+ 	if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
+ 	{
+ 		/*
+ 		 * Catchup interrupt has been sent.
+ 		 */
+ 		HandleCatchupInterrupt();
+ 	}
+ 	
+ 	errno = save_errno;
+ }
+ 
+ /*
   * quickdie() occurs when signalled SIGQUIT by the postmaster.
   *
   * Some backend has bought the farm,
***************
*** 3180,3186 ****
  	 * of output during who-knows-what operation...
  	 */
  	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, CatchupInterruptHandler);
  	pqsignal(SIGUSR2, NotifyInterruptHandler);
  	pqsignal(SIGFPE, FloatExceptionHandler);
  
--- 3203,3209 ----
  	 * of output during who-knows-what operation...
  	 */
  	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, proc_sigusr1_handler);
  	pqsignal(SIGUSR2, NotifyInterruptHandler);
  	pqsignal(SIGFPE, FloatExceptionHandler);
  
diff -rc base/src/include/bootstrap/bootstrap.h new/src/include/bootstrap/bootstrap.h
*** base/src/include/bootstrap/bootstrap.h	2008-12-10 16:29:10.000000000 +0900
--- new/src/include/bootstrap/bootstrap.h	2008-12-10 18:08:12.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 -rc base/src/include/storage/procsignal.h new/src/include/storage/procsignal.h
*** base/src/include/storage/procsignal.h	2008-12-10 19:26:52.000000000 +0900
--- new/src/include/storage/procsignal.h	2008-12-10 19:07:11.000000000 +0900
***************
*** 0 ****
--- 1,41 ----
+ /*-------------------------------------------------------------------------
+  *
+  * procsignal.h
+  *	  routines for signaling the backend, autovacuum worker and auxiliary process
+  *
+  *
+  * 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.20 2008/06/19 21:32:56 tgl Exp $
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PROCSIGNAL_H
+ #define PROCSIGNAL_H
+ 
+ #include "storage/backendid.h"
+ 
+ /*
+  * Reasons for signaling the process (such as backend, autovacuum worker
+  * and auxiliary process). 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
+ {
+ 	PROCSIG_CATCHUP_INTERRUPT,	/* catchup interrupt */
+ 	
+ 	NUM_PROCSIGNALS				/* Must be last value of enum! */
+ } ProcSignalReason;
+ 
+ 
+ /*
+  * prototypes for functions in procsignal.c
+  */
+ extern void ProcSignalInit(void);
+ extern void SendProcSignal(BackendId bid, pid_t pid, ProcSignalReason reason);
+ extern bool CheckProcSignal(ProcSignalReason reason);
+ 
+ #endif   /* PMSIGNAL_H */
diff -rc base/src/include/storage/sinval.h new/src/include/storage/sinval.h
*** base/src/include/storage/sinval.h	2008-12-10 16:29:10.000000000 +0900
--- new/src/include/storage/sinval.h	2008-12-10 18:53:51.000000000 +0900
***************
*** 90,96 ****
  							 void (*resetFunction) (void));
  
  /* signal handler for catchup events (SIGUSR1) */
! extern void CatchupInterruptHandler(SIGNAL_ARGS);
  
  /*
   * enable/disable processing of catchup events directly from signal handler.
--- 90,96 ----
  							 void (*resetFunction) (void));
  
  /* signal handler for catchup events (SIGUSR1) */
! extern void HandleCatchupInterrupt(void);
  
  /*
   * enable/disable processing of catchup events directly from signal handler.
diff -rc base/src/include/tcop/tcopprot.h new/src/include/tcop/tcopprot.h
*** base/src/include/tcop/tcopprot.h	2008-12-10 16:29:10.000000000 +0900
--- new/src/include/tcop/tcopprot.h	2008-12-10 18:54:26.000000000 +0900
***************
*** 56,61 ****
--- 56,62 ----
  
  extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);
  
+ extern void proc_sigusr1_handler(SIGNAL_ARGS);
  extern void die(SIGNAL_ARGS);
  extern void quickdie(SIGNAL_ARGS);
  extern void authdie(SIGNAL_ARGS);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to