88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.105 2001/09/0402:26:57 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.106 2001/09/0421:42:17 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -186,6 +186,17 @@ InitProcess(void)
186186unsigned long location ,
187187myOffset ;
188188
189+ /*
190+ * ProcStructLock protects the freelist of PROC entries and the map
191+ * of free semaphores. Note that when we acquire it here, we do not
192+ * have a PROC entry and so the ownership of the spinlock is not
193+ * recorded anywhere; even if it was, until we register ProcKill as
194+ * an on_shmem_exit callback, there is no exit hook that will cause
195+ * owned spinlocks to be released. Upshot: during the first part of
196+ * this routine, be careful to release the lock manually before any
197+ * elog(), else you'll have a stuck spinlock to add to your woes.
198+ */
199+
189200SpinAcquire (ProcStructLock );
190201
191202/* attach to the ProcGlobal structure */
@@ -194,13 +205,14 @@ InitProcess(void)
194205if (!found )
195206{
196207/* this should not happen. InitProcGlobal() is called before this. */
208+ SpinRelease (ProcStructLock );
197209elog (STOP ,"InitProcess: Proc Header uninitialized" );
198210}
199211
200212if (MyProc != NULL )
201213{
202214SpinRelease (ProcStructLock );
203- elog (ERROR ,"ProcInit : you already exist" );
215+ elog (ERROR ,"InitProcess : you already exist" );
204216}
205217
206218/* try to get a proc struct from the free list first */
@@ -214,14 +226,12 @@ InitProcess(void)
214226}
215227else
216228{
217-
218229/*
219230 * have to allocate one. We can't use the normal shmem index
220231 * table mechanism because the proc structure is stored by PID
221232 * instead of by a global name (need to look it up by PID when we
222233 * cleanup dead processes).
223234 */
224-
225235MyProc = (PROC * )ShmemAlloc (sizeof (PROC ));
226236if (!MyProc )
227237{
@@ -231,44 +241,32 @@ InitProcess(void)
231241}
232242
233243/*
234- * zero out the spin lock counts and set the sLocks field for
235- * ProcStructLock to 1 as we have acquired this spinlock above but
236- * didn't record it since we didn't have MyProc until now.
237- */
238- MemSet (MyProc -> sLocks ,0 ,sizeof (MyProc -> sLocks ));
239- MyProc -> sLocks [ProcStructLock ]= 1 ;
240-
241- /*
242- * Set up a wait-semaphore for the proc.
244+ * Initialize all fields of MyProc.
243245 */
244- if (IsUnderPostmaster )
245- {
246- ProcGetNewSemIdAndNum (& MyProc -> sem .semId ,& MyProc -> sem .semNum );
247-
248- /*
249- * we might be reusing a semaphore that belongs to a dead backend.
250- * So be careful and reinitialize its value here.
251- */
252- ZeroProcSemaphore (MyProc );
253- }
254- else
255- {
256- MyProc -> sem .semId = -1 ;
257- MyProc -> sem .semNum = -1 ;
258- }
259-
260246SHMQueueElemInit (& (MyProc -> links ));
247+ MyProc -> sem .semId = -1 ;/* no wait-semaphore acquired yet */
248+ MyProc -> sem .semNum = -1 ;
261249MyProc -> errType = STATUS_OK ;
262- MyProc -> pid = MyProcPid ;
263- MyProc -> databaseId = MyDatabaseId ;
264250MyProc -> xid = InvalidTransactionId ;
265251MyProc -> xmin = InvalidTransactionId ;
252+ MyProc -> logRec .xrecoff = 0 ;
266253MyProc -> waitLock = NULL ;
267254MyProc -> waitHolder = NULL ;
255+ MyProc -> pid = MyProcPid ;
256+ MyProc -> databaseId = MyDatabaseId ;
268257SHMQueueInit (& (MyProc -> procHolders ));
258+ /*
259+ * Zero out the spin lock counts and set the sLocks field for
260+ * ProcStructLock to 1 as we have acquired this spinlock above but
261+ * didn't record it since we didn't have MyProc until now.
262+ */
263+ MemSet (MyProc -> sLocks ,0 ,sizeof (MyProc -> sLocks ));
264+ MyProc -> sLocks [ProcStructLock ]= 1 ;
269265
270266/*
271- * Release the lock.
267+ * Release the lock while accessing shmem index; we still haven't
268+ * installed ProcKill and so we don't want to hold lock if there's
269+ * an error.
272270 */
273271SpinRelease (ProcStructLock );
274272
@@ -283,10 +281,28 @@ InitProcess(void)
283281elog (STOP ,"InitProcess: ShmemPID table broken" );
284282
285283/*
286- * Arrange to clean up at backend exit.
284+ * Arrange to clean up at backend exit. Once we do this, owned
285+ * spinlocks will be released on exit, and so we can be a lot less
286+ * tense about errors.
287287 */
288288on_shmem_exit (ProcKill ,0 );
289289
290+ /*
291+ * Set up a wait-semaphore for the proc. (Do this last so that we
292+ * can rely on ProcKill to clean up if it fails.)
293+ */
294+ if (IsUnderPostmaster )
295+ {
296+ SpinAcquire (ProcStructLock );
297+ ProcGetNewSemIdAndNum (& MyProc -> sem .semId ,& MyProc -> sem .semNum );
298+ SpinRelease (ProcStructLock );
299+ /*
300+ * We might be reusing a semaphore that belongs to a dead backend.
301+ * So be careful and reinitialize its value here.
302+ */
303+ ZeroProcSemaphore (MyProc );
304+ }
305+
290306/*
291307 * Now that we have a PROC, we could try to acquire locks, so
292308 * initialize the deadlock checker.
@@ -425,8 +441,9 @@ ProcKill(void)
425441
426442SpinAcquire (ProcStructLock );
427443
428- /* Free up my wait semaphore */
429- ProcFreeSem (MyProc -> sem .semId ,MyProc -> sem .semNum );
444+ /* Free up my wait semaphore, if I got one */
445+ if (MyProc -> sem .semId >=0 )
446+ ProcFreeSem (MyProc -> sem .semId ,MyProc -> sem .semNum );
430447
431448/* Add PROC struct to freelist so space can be recycled in future */
432449MyProc -> links .next = ProcGlobal -> freeProcs ;
@@ -993,10 +1010,7 @@ ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum)
9931010{
9941011if ((freeSemMap [i ]& mask )== 0 )
9951012{
996-
997- /*
998- * a free semaphore found. Mark it as allocated.
999- */
1013+ /* A free semaphore found. Mark it as allocated. */
10001014freeSemMap [i ] |=mask ;
10011015
10021016* semId = procSemIds [i ];
@@ -1007,8 +1021,13 @@ ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum)
10071021}
10081022}
10091023
1010- /* if we reach here, all the semaphores are in use. */
1011- elog (ERROR ,"ProcGetNewSemIdAndNum: cannot allocate a free semaphore" );
1024+ /*
1025+ * If we reach here, all the semaphores are in use. This is one of the
1026+ * possible places to detect "too many backends", so give the standard
1027+ * error message. (Whether we detect it here or in sinval.c depends on
1028+ * whether MaxBackends is a multiple of PROC_NSEMS_PER_SET.)
1029+ */
1030+ elog (FATAL ,"Sorry, too many clients already" );
10121031}
10131032
10141033/*