Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7635543

Browse files
committed
Fix code so that we recover cleanly if there are no free semaphores
available in freeSemMap. As noted by Tatsuo, this is now a likely scenario for detecting MaxBackends-exceeded; if MaxBackends is a multiple of PROC_NSEMS_PER_SET then we will fail here and not in sinval.c. The cleanup path did not work correctly before, anyway.
1 parent 29c22ee commit 7635543

File tree

1 file changed

+60
-41
lines changed
  • src/backend/storage/lmgr

1 file changed

+60
-41
lines changed

src/backend/storage/lmgr/proc.c

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.105 2001/09/04 02:26:57 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.106 2001/09/04 21:42:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -186,6 +186,17 @@ InitProcess(void)
186186
unsigned long location,
187187
myOffset;
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+
189200
SpinAcquire(ProcStructLock);
190201

191202
/* attach to the ProcGlobal structure */
@@ -194,13 +205,14 @@ InitProcess(void)
194205
if (!found)
195206
{
196207
/* this should not happen. InitProcGlobal() is called before this. */
208+
SpinRelease(ProcStructLock);
197209
elog(STOP, "InitProcess: Proc Header uninitialized");
198210
}
199211

200212
if (MyProc != NULL)
201213
{
202214
SpinRelease(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
}
215227
else
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-
225235
MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
226236
if (!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-
260246
SHMQueueElemInit(&(MyProc->links));
247+
MyProc->sem.semId = -1; /* no wait-semaphore acquired yet */
248+
MyProc->sem.semNum = -1;
261249
MyProc->errType = STATUS_OK;
262-
MyProc->pid = MyProcPid;
263-
MyProc->databaseId = MyDatabaseId;
264250
MyProc->xid = InvalidTransactionId;
265251
MyProc->xmin = InvalidTransactionId;
252+
MyProc->logRec.xrecoff = 0;
266253
MyProc->waitLock = NULL;
267254
MyProc->waitHolder = NULL;
255+
MyProc->pid = MyProcPid;
256+
MyProc->databaseId = MyDatabaseId;
268257
SHMQueueInit(&(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
*/
273271
SpinRelease(ProcStructLock);
274272

@@ -283,10 +281,28 @@ InitProcess(void)
283281
elog(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
*/
288288
on_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

426442
SpinAcquire(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 */
432449
MyProc->links.next = ProcGlobal->freeProcs;
@@ -993,10 +1010,7 @@ ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum)
9931010
{
9941011
if ((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. */
10001014
freeSemMap[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
/*

0 commit comments

Comments
 (0)