1 /*-------------------------------------------------------------------------
4 * routines to manage per-process shared memory data structure
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.12 1996/12/26 22:07:28 momjian Exp $
12 *-------------------------------------------------------------------------
15 * Each postgres backend gets one of these. We'll use it to
16 * clean up after the process should the process suddenly die.
20 * ProcSleep(), ProcWakeup(), ProcWakeupNext(),
21 * ProcQueueAlloc() -- create a shm queue for sleeping processes
22 * ProcQueueInit() -- create a queue without allocing memory
24 * Locking and waiting for buffers can cause the backend to be
25 * put to sleep. Whoever releases the lock, etc. wakes the
26 * process up again (and gives it an error code so it knows
27 * whether it was awoken on an error condition).
31 * ProcReleaseLocks -- frees the locks associated with this process,
32 * ProcKill -- destroys the shared memory state (and locks)
33 * associated with the process.
35 * 5/15/91 -- removed the buffer pool based lock chain in favor
36 * of a shared memory lock chain. The write-protection is
37 * more expensive if the lock chain is in the buffer pool.
38 * The only reason I kept the lock chain in the buffer pool
39 * in the first place was to allow the lock table to grow larger
40 * than available shared memory and that isn't going to work
41 * without a lot of unimplemented support anyway.
43 * 4/7/95 -- instead of allocating a set of 1 semaphore per process, we
44 * allocate a semaphore from a set of PROC_NSEMS_PER_SET semaphores
45 * shared among backends (we keep a few sets of semaphores around).
46 * This is so that we can support more backends. (system-wide semaphore
47 * sets run out pretty fast.) -ay 4/95
49 * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.12 1996/12/26 22:07:28 momjian Exp $
57 #include <sys/types.h>
61 #if defined(sparc_solaris)
67 #include "miscadmin.h"
68 #include "libpq/pqsignal.h"
70 #include "access/xact.h"
71 #include "utils/hsearch.h"
73 #include "storage/buf.h"
74 #include "storage/lock.h"
75 #include "storage/lmgr.h"
76 #include "storage/shmem.h"
77 #include "storage/spin.h"
78 #include "storage/proc.h"
81 * timeout (in seconds) for resolving possible deadlock
83 #ifndef DEADLOCK_TIMEOUT
84 #define DEADLOCK_TIMEOUT 60
87 /* --------------------
88 * Spin lock for manipulating the shared process data structure:
89 * ProcGlobal.... Adding an extra spin lock seemed like the smallest
90 * hack to get around reading and updating this structure in shared
91 * memory. -mer 17 July 1991
92 * --------------------
94 SPINLOCK ProcStructLock;
97 * For cleanup routines. Don't cleanup if the initialization
100 static bool ProcInitialized = FALSE;
102 static PROC_HDR *ProcGlobal = NULL;
106 static void ProcKill(int exitStatus, int pid);
107 static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
108 static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
111 * initializes the global process table. We put it here so that
112 * the postmaster can do this initialization. (ProcFreeAllSem needs
113 * to read this table on exiting the postmaster. If we have the first
114 * backend do this, starting up and killing the postmaster without
115 * starting any backends will be a problem.)
118 InitProcGlobal(IPCKey key)
122 /* attach to the free list */
123 ProcGlobal = (PROC_HDR *)
124 ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
126 /* --------------------
127 * We're the first - initialize.
128 * --------------------
134 ProcGlobal->numProcs = 0;
135 ProcGlobal->freeProcs = INVALID_OFFSET;
136 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
137 for (i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++)
138 ProcGlobal->freeSemMap[i] = 0;
142 /* ------------------------
143 * InitProc -- create a per-process data structure for this process
144 * used by the lock manager on semaphore queues.
145 * ------------------------
148 InitProcess(IPCKey key)
153 unsigned long location, myOffset;
155 /* ------------------
156 * Routine called if deadlock timer goes off. See ProcSleep()
160 pqsignal(SIGALRM, HandleDeadLock);
161 #endif /* WIN32 we'll have to figure out how to handle this later */
163 SpinAcquire(ProcStructLock);
165 /* attach to the free list */
166 ProcGlobal = (PROC_HDR *)
167 ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
169 /* this should not happen. InitProcGlobal() is called before this. */
170 elog(WARN, "InitProcess: Proc Header uninitialized");
175 SpinRelease(ProcStructLock);
176 elog(WARN,"ProcInit: you already exist");
180 /* try to get a proc from the free list first */
182 myOffset = ProcGlobal->freeProcs;
184 if (myOffset != INVALID_OFFSET)
186 MyProc = (PROC *) MAKE_PTR(myOffset);
187 ProcGlobal->freeProcs = MyProc->links.next;
191 /* have to allocate one. We can't use the normal binding
192 * table mechanism because the proc structure is stored
193 * by PID instead of by a global name (need to look it
194 * up by PID when we cleanup dead processes).
197 MyProc = (PROC *) ShmemAlloc((unsigned)sizeof(PROC));
200 SpinRelease(ProcStructLock);
201 elog (FATAL,"cannot create new proc: out of memory");
204 /* this cannot be initialized until after the buffer pool */
205 SHMQueueInit(&(MyProc->lockQueue));
206 MyProc->procId = ProcGlobal->numProcs;
207 ProcGlobal->numProcs++;
211 * zero out the spin lock counts and set the sLocks field for
212 * ProcStructLock to 1 as we have acquired this spinlock above but
213 * didn't record it since we didn't have MyProc until now.
215 memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
216 MyProc->sLocks[ProcStructLock] = 1;
219 if (IsUnderPostmaster) {
225 ProcGetNewSemKeyAndNum(&semKey, &semNum);
227 semId = IpcSemaphoreCreate(semKey,
230 IpcSemaphoreDefaultStartValue,
234 * we might be reusing a semaphore that belongs to a dead
235 * backend. So be careful and reinitialize its value here.
237 semun.val = IpcSemaphoreDefaultStartValue;
238 semctl(semId, semNum, SETVAL, semun);
240 IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
241 MyProc->sem.semId = semId;
242 MyProc->sem.semNum = semNum;
243 MyProc->sem.semKey = semKey;
245 MyProc->sem.semId = -1;
248 /* ----------------------
250 * ----------------------
252 SpinRelease(ProcStructLock);
255 MyProc->xid = InvalidTransactionId;
261 * Start keeping spin lock stats from here on. Any botch before
262 * this initialization is forever botched
265 memset(MyProc->sLocks, 0, MAX_SPINS*sizeof(*MyProc->sLocks));
267 /* -------------------------
268 * Install ourselves in the binding table. The name to
269 * use is determined by the OS-assigned process id. That
270 * allows the cleanup process to find us after any untimely
272 * -------------------------
275 location = MAKE_OFFSET(MyProc);
276 if ((! ShmemPIDLookup(pid,&location)) || (location != MAKE_OFFSET(MyProc)))
278 elog(FATAL,"InitProc: ShmemPID table broken");
281 MyProc->errType = NO_ERROR;
282 SHMQueueElemInit(&(MyProc->links));
284 on_exitpg(ProcKill, (caddr_t)pid);
286 ProcInitialized = TRUE;
290 * ProcReleaseLocks() -- release all locks associated with this process
298 LockReleaseAll(1,&MyProc->lockQueue);
303 * used by the postmaster to clean up the global tables. This also frees
304 * up the semaphore used for the lmgr of the process. (We have to do
305 * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
306 * the process because the semaphore set is shared among backends and
307 * we don't want to remove other's semaphores on exit.)
312 SHMEM_OFFSET location;
315 location = INVALID_OFFSET;
317 location = ShmemPIDDestroy(pid);
318 if (location == INVALID_OFFSET)
320 proc = (PROC *) MAKE_PTR(location);
322 SpinAcquire(ProcStructLock);
324 ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
326 proc->links.next = ProcGlobal->freeProcs;
327 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
329 SpinRelease(ProcStructLock);
335 * ProcKill() -- Destroy the per-proc data structure for
336 * this process. Release any of its held spin locks.
339 ProcKill(int exitStatus, int pid)
342 SHMEM_OFFSET location;
344 /* --------------------
345 * If this is a FATAL exit the postmaster will have to kill all the
346 * existing backends and reinitialize shared memory. So all we don't
347 * need to do anything here.
348 * --------------------
358 ShmemPIDLookup(pid,&location);
359 if (location == INVALID_OFFSET)
362 proc = (PROC *) MAKE_PTR(location);
364 if (proc != MyProc) {
365 Assert( pid != getpid() );
370 * Assume one lock table.
373 ProcReleaseSpins(proc);
374 LockReleaseAll(1,&proc->lockQueue);
377 LockReleaseAll(0,&proc->lockQueue);
381 * get off the wait queue
385 if (proc->links.next != INVALID_OFFSET) {
386 Assert(proc->waitLock->waitProcs.size > 0);
387 SHMQueueDelete(&(proc->links));
388 --proc->waitLock->waitProcs.size;
390 SHMQueueElemInit(&(proc->links));
397 * ProcQueue package: routines for putting processes to sleep
402 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
404 * Returns: a pointer to the queue or NULL
405 * Side Effects: Initializes the queue if we allocated one
408 ProcQueueAlloc(char *name)
411 PROC_QUEUE *queue = (PROC_QUEUE *)
412 ShmemInitStruct(name,(unsigned)sizeof(PROC_QUEUE),&found);
420 ProcQueueInit(queue);
426 * ProcQueueInit -- initialize a shared memory process queue
429 ProcQueueInit(PROC_QUEUE *queue)
431 SHMQueueInit(&(queue->links));
438 * ProcSleep -- put a process to sleep
440 * P() on the semaphore should put us to sleep. The process
441 * semaphore is cleared by default, so the first time we try
442 * to acquire it, we sleep.
444 * ASSUME: that no one will fiddle with the queue until after
445 * we release the spin lock.
447 * NOTES: The process queue is now a priority queue for locking.
450 ProcSleep(PROC_QUEUE *queue,
458 #ifndef WIN32 /* figure this out later */
459 struct itimerval timeval, dummy;
462 proc = (PROC *) MAKE_PTR(queue->links.prev);
463 for (i=0;i<queue->size;i++)
465 if (proc->prio < prio)
466 proc = (PROC *) MAKE_PTR(proc->links.prev);
471 MyProc->token = token;
472 MyProc->waitLock = lock;
474 /* -------------------
475 * currently, we only need this for the ProcWakeup routines
476 * -------------------
478 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
480 /* -------------------
481 * assume that these two operations are atomic (because
483 * -------------------
485 SHMQueueInsertTL(&(proc->links),&(MyProc->links));
488 SpinRelease(spinlock);
491 * Postgres does not have any deadlock detection code and for this
492 * reason we must set a timer to wake up the process in the event of
493 * a deadlock. For now the timer is set for 1 minute and we assume that
494 * any process which sleeps for this amount of time is deadlocked and will
495 * receive a SIGALRM signal. The handler should release the processes
496 * semaphore and abort the current transaction.
498 * Need to zero out struct to set the interval and the micro seconds fields
503 memset(&timeval, 0, sizeof(struct itimerval));
504 timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
506 if (setitimer(ITIMER_REAL, &timeval, &dummy))
507 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
511 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
512 * IpcSemaphoreLock will not block. The wakeup is "saved" by
513 * the semaphore implementation.
516 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
519 * We were awoken before a timeout - now disable the timer
523 timeval.it_value.tv_sec = 0;
526 if (setitimer(ITIMER_REAL, &timeval, &dummy))
527 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
531 * We were assumed to be in a critical section when we went
535 SpinAcquire(spinlock);
537 return(MyProc->errType);
542 * ProcWakeup -- wake up a process by releasing its private semaphore.
544 * remove the process from the wait queue and set its links invalid.
545 * RETURN: the next process in the wait queue.
548 ProcWakeup(PROC *proc, int errType)
551 /* assume that spinlock has been acquired */
553 if (proc->links.prev == INVALID_OFFSET ||
554 proc->links.next == INVALID_OFFSET)
555 return((PROC *) NULL);
557 retProc = (PROC *) MAKE_PTR(proc->links.prev);
559 /* you have to update waitLock->waitProcs.size yourself */
560 SHMQueueDelete(&(proc->links));
561 SHMQueueElemInit(&(proc->links));
563 proc->errType = errType;
565 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
577 return( MyProc->procId );
581 * ProcLockWakeup -- routine for waking up processes when a lock is
585 ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
591 return(STATUS_NOT_FOUND);
593 proc = (PROC *) MAKE_PTR(queue->links.prev);
595 while ((LockResolveConflicts ((LOCKTAB *) ltable,
598 proc->xid) == STATUS_OK))
600 /* there was a waiting process, grant it the lock before waking it
601 * up. This will prevent another process from seizing the lock
602 * between the time we release the lock master (spinlock) and
603 * the time that the awoken process begins executing again.
605 GrantLock((LOCK *) lock, proc->token);
609 * ProcWakeup removes proc from the lock waiting process queue and
610 * returns the next proc in chain. If a writer just dropped
611 * its lock and there are several waiting readers, wake them all up.
613 proc = ProcWakeup(proc, NO_ERROR);
616 if (!proc || queue->size == 0)
623 /* Something is still blocking us. May have deadlocked. */
624 return(STATUS_NOT_FOUND);
628 ProcAddLock(SHM_QUEUE *elem)
630 SHMQueueInsertTL(&MyProc->lockQueue,elem);
633 /* --------------------
634 * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
635 * while waiting for a lock to be released by some other process. After
636 * the one minute deadline we assume we have a deadlock and must abort
637 * this transaction. We must also indicate that I'm no longer waiting
638 * on a lock so that other processes don't try to wake me up and screw
640 * --------------------
643 HandleDeadLock(int sig)
650 /* ---------------------
651 * Check to see if we've been awoken by anyone in the interim.
653 * If we have we can return and resume our transaction -- happy day.
654 * Before we are awoken the process releasing the lock grants it to
655 * us so we know that we don't have to wait anymore.
657 * Damn these names are LONG! -mer
658 * ---------------------
660 if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
661 IpcSemaphoreDefaultStartValue) {
667 * you would think this would be unnecessary, but...
669 * this also means we've been removed already. in some ports
670 * (e.g., sparc and aix) the semop(2) implementation is such that
671 * we can actually end up in this handler after someone has removed
672 * us from the queue and bopped the semaphore *but the test above
673 * fails to detect the semaphore update* (presumably something weird
674 * having to do with the order in which the semaphore wakeup signal
675 * and SIGALRM get handled).
677 if (MyProc->links.prev == INVALID_OFFSET ||
678 MyProc->links.next == INVALID_OFFSET) {
683 lock = MyProc->waitLock;
684 size = lock->waitProcs.size; /* so we can look at this in the core */
686 /* ------------------------
687 * Get this process off the lock's wait queue
688 * ------------------------
690 Assert(lock->waitProcs.size > 0);
691 --lock->waitProcs.size;
692 SHMQueueDelete(&(MyProc->links));
693 SHMQueueElemInit(&(MyProc->links));
695 /* ------------------
696 * Unlock my semaphore so that the count is right for next time.
697 * I was awoken by a signal, not by someone unlocking my semaphore.
700 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
703 * Set MyProc->errType to STATUS_ERROR so that we abort after
704 * returning from this handler.
707 MyProc->errType = STATUS_ERROR;
710 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
711 * table corruption ("LockReplace: xid table corrupted") due to
712 * race conditions. i don't claim to understand this...
716 elog(NOTICE, "Timeout -- possible deadlock");
721 ProcReleaseSpins(PROC *proc)
730 for (i=0; i < (int)MAX_SPINS; i++)
734 Assert(proc->sLocks[i] == 1);
740 /*****************************************************************************
742 *****************************************************************************/
745 * ProcGetNewSemKeyAndNum -
746 * scan the free semaphore bitmap and allocate a single semaphore from
747 * a semaphore set. (If the semaphore set doesn't exist yet,
748 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
752 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
755 int32 *freeSemMap = ProcGlobal->freeSemMap;
756 unsigned int fullmask;
759 * we hold ProcStructLock when entering this routine. We scan through
760 * the bitmap to look for a free semaphore.
762 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
763 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
767 if (freeSemMap[i] == fullmask)
768 continue; /* none free for this set */
770 for(j = 0; j < PROC_NSEMS_PER_SET; j++) {
771 if ((freeSemMap[i] & mask) == 0) {
773 * a free semaphore found. Mark it as allocated.
775 freeSemMap[i] |= mask;
777 *key = ProcGlobal->currKey + i;
785 /* if we reach here, all the semaphores are in use. */
786 elog(WARN, "InitProc: cannot allocate a free semaphore");
791 * free up our semaphore in the semaphore set. If we're the last one
792 * in the set, also remove the semaphore set.
795 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
799 int32 *freeSemMap = ProcGlobal->freeSemMap;
801 i = semKey - ProcGlobal->currKey;
802 mask = ~(1 << semNum);
803 freeSemMap[i] &= mask;
805 if (freeSemMap[i]==0)
806 IpcSemaphoreKill(semKey);
810 * ProcFreeAllSemaphores -
811 * on exiting the postmaster, we free up all the semaphores allocated
812 * to the lmgrs of the backends.
815 ProcFreeAllSemaphores()
818 int32 *freeSemMap = ProcGlobal->freeSemMap;
820 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
821 if (freeSemMap[i]!=0)
822 IpcSemaphoreKill(ProcGlobal->currKey + i);