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.18 1997/08/19 21:33:29 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.18 1997/08/19 21:33:29 momjian Exp $
55 #include <sys/types.h>
57 #if defined(sparc_solaris)
63 #include "miscadmin.h"
64 #include "libpq/pqsignal.h"
66 #include "access/xact.h"
67 #include "utils/hsearch.h"
69 #include "storage/ipc.h"
70 /* In Ultrix, sem.h must be included after ipc.h */
72 #include "storage/buf.h"
73 #include "storage/lock.h"
74 #include "storage/lmgr.h"
75 #include "storage/shmem.h"
76 #include "storage/spin.h"
77 #include "storage/proc.h"
79 static void HandleDeadLock(int sig);
80 static PROC *ProcWakeup(PROC *proc, int errType);
83 * timeout (in seconds) for resolving possible deadlock
85 #ifndef DEADLOCK_TIMEOUT
86 #define DEADLOCK_TIMEOUT 60
89 /* --------------------
90 * Spin lock for manipulating the shared process data structure:
91 * ProcGlobal.... Adding an extra spin lock seemed like the smallest
92 * hack to get around reading and updating this structure in shared
93 * memory. -mer 17 July 1991
94 * --------------------
96 SPINLOCK ProcStructLock;
99 * For cleanup routines. Don't cleanup if the initialization
102 static bool ProcInitialized = FALSE;
104 static PROC_HDR *ProcGlobal = NULL;
108 static void ProcKill(int exitStatus, int pid);
109 static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
110 static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
113 * initializes the global process table. We put it here so that
114 * the postmaster can do this initialization. (ProcFreeAllSem needs
115 * to read this table on exiting the postmaster. If we have the first
116 * backend do this, starting up and killing the postmaster without
117 * starting any backends will be a problem.)
120 InitProcGlobal(IPCKey key)
124 /* attach to the free list */
125 ProcGlobal = (PROC_HDR *)
126 ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
128 /* --------------------
129 * We're the first - initialize.
130 * --------------------
136 ProcGlobal->numProcs = 0;
137 ProcGlobal->freeProcs = INVALID_OFFSET;
138 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
139 for (i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++)
140 ProcGlobal->freeSemMap[i] = 0;
144 /* ------------------------
145 * InitProc -- create a per-process data structure for this process
146 * used by the lock manager on semaphore queues.
147 * ------------------------
150 InitProcess(IPCKey key)
155 unsigned long location, myOffset;
157 /* ------------------
158 * Routine called if deadlock timer goes off. See ProcSleep()
161 pqsignal(SIGALRM, HandleDeadLock);
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
409 ProcQueueAlloc(char *name)
412 PROC_QUEUE *queue = (PROC_QUEUE *)
413 ShmemInitStruct(name,(unsigned)sizeof(PROC_QUEUE),&found);
421 ProcQueueInit(queue);
428 * ProcQueueInit -- initialize a shared memory process queue
431 ProcQueueInit(PROC_QUEUE *queue)
433 SHMQueueInit(&(queue->links));
440 * ProcSleep -- put a process to sleep
442 * P() on the semaphore should put us to sleep. The process
443 * semaphore is cleared by default, so the first time we try
444 * to acquire it, we sleep.
446 * ASSUME: that no one will fiddle with the queue until after
447 * we release the spin lock.
449 * NOTES: The process queue is now a priority queue for locking.
452 ProcSleep(PROC_QUEUE *queue,
460 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);
472 MyProc->token = token;
473 MyProc->waitLock = lock;
475 /* -------------------
476 * currently, we only need this for the ProcWakeup routines
477 * -------------------
479 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
481 /* -------------------
482 * assume that these two operations are atomic (because
484 * -------------------
486 SHMQueueInsertTL(&(proc->links),&(MyProc->links));
489 SpinRelease(spinlock);
492 * Postgres does not have any deadlock detection code and for this
493 * reason we must set a timer to wake up the process in the event of
494 * a deadlock. For now the timer is set for 1 minute and we assume that
495 * any process which sleeps for this amount of time is deadlocked and will
496 * receive a SIGALRM signal. The handler should release the processes
497 * semaphore and abort the current transaction.
499 * 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");
510 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
511 * IpcSemaphoreLock will not block. The wakeup is "saved" by
512 * the semaphore implementation.
515 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
518 * We were awoken before a timeout - now disable the timer
521 timeval.it_value.tv_sec = 0;
524 if (setitimer(ITIMER_REAL, &timeval, &dummy))
525 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
528 * We were assumed to be in a critical section when we went
532 SpinAcquire(spinlock);
534 return(MyProc->errType);
539 * ProcWakeup -- wake up a process by releasing its private semaphore.
541 * remove the process from the wait queue and set its links invalid.
542 * RETURN: the next process in the wait queue.
545 ProcWakeup(PROC *proc, int errType)
548 /* assume that spinlock has been acquired */
550 if (proc->links.prev == INVALID_OFFSET ||
551 proc->links.next == INVALID_OFFSET)
552 return((PROC *) NULL);
554 retProc = (PROC *) MAKE_PTR(proc->links.prev);
556 /* you have to update waitLock->waitProcs.size yourself */
557 SHMQueueDelete(&(proc->links));
558 SHMQueueElemInit(&(proc->links));
560 proc->errType = errType;
562 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
575 return( MyProc->procId );
580 * ProcLockWakeup -- routine for waking up processes when a lock is
584 ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
590 return(STATUS_NOT_FOUND);
592 proc = (PROC *) MAKE_PTR(queue->links.prev);
594 while ((LockResolveConflicts ((LOCKTAB *) ltable,
597 proc->xid) == STATUS_OK))
599 /* there was a waiting process, grant it the lock before waking it
600 * up. This will prevent another process from seizing the lock
601 * between the time we release the lock master (spinlock) and
602 * the time that the awoken process begins executing again.
604 GrantLock((LOCK *) lock, proc->token);
608 * ProcWakeup removes proc from the lock waiting process queue and
609 * returns the next proc in chain. If a writer just dropped
610 * its lock and there are several waiting readers, wake them all up.
612 proc = ProcWakeup(proc, NO_ERROR);
615 if (!proc || queue->size == 0)
622 /* Something is still blocking us. May have deadlocked. */
623 return(STATUS_NOT_FOUND);
627 ProcAddLock(SHM_QUEUE *elem)
629 SHMQueueInsertTL(&MyProc->lockQueue,elem);
632 /* --------------------
633 * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
634 * while waiting for a lock to be released by some other process. After
635 * the one minute deadline we assume we have a deadlock and must abort
636 * this transaction. We must also indicate that I'm no longer waiting
637 * on a lock so that other processes don't try to wake me up and screw
639 * --------------------
642 HandleDeadLock(int sig)
649 /* ---------------------
650 * Check to see if we've been awoken by anyone in the interim.
652 * If we have we can return and resume our transaction -- happy day.
653 * Before we are awoken the process releasing the lock grants it to
654 * us so we know that we don't have to wait anymore.
656 * Damn these names are LONG! -mer
657 * ---------------------
659 if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
660 IpcSemaphoreDefaultStartValue) {
666 * you would think this would be unnecessary, but...
668 * this also means we've been removed already. in some ports
669 * (e.g., sparc and aix) the semop(2) implementation is such that
670 * we can actually end up in this handler after someone has removed
671 * us from the queue and bopped the semaphore *but the test above
672 * fails to detect the semaphore update* (presumably something weird
673 * having to do with the order in which the semaphore wakeup signal
674 * and SIGALRM get handled).
676 if (MyProc->links.prev == INVALID_OFFSET ||
677 MyProc->links.next == INVALID_OFFSET) {
682 lock = MyProc->waitLock;
683 size = lock->waitProcs.size; /* so we can look at this in the core */
685 #ifdef DEADLOCK_DEBUG
689 /* ------------------------
690 * Get this process off the lock's wait queue
691 * ------------------------
693 Assert(lock->waitProcs.size > 0);
694 --lock->waitProcs.size;
695 SHMQueueDelete(&(MyProc->links));
696 SHMQueueElemInit(&(MyProc->links));
698 /* ------------------
699 * Unlock my semaphore so that the count is right for next time.
700 * I was awoken by a signal, not by someone unlocking my semaphore.
703 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
706 * Set MyProc->errType to STATUS_ERROR so that we abort after
707 * returning from this handler.
710 MyProc->errType = STATUS_ERROR;
713 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
714 * table corruption ("LockReplace: xid table corrupted") due to
715 * race conditions. i don't claim to understand this...
719 elog(NOTICE, "Timeout -- possible deadlock");
724 ProcReleaseSpins(PROC *proc)
733 for (i=0; i < (int)MAX_SPINS; i++)
737 Assert(proc->sLocks[i] == 1);
743 /*****************************************************************************
745 *****************************************************************************/
748 * ProcGetNewSemKeyAndNum -
749 * scan the free semaphore bitmap and allocate a single semaphore from
750 * a semaphore set. (If the semaphore set doesn't exist yet,
751 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
755 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
758 int32 *freeSemMap = ProcGlobal->freeSemMap;
759 unsigned int fullmask;
762 * we hold ProcStructLock when entering this routine. We scan through
763 * the bitmap to look for a free semaphore.
765 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
766 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
770 if (freeSemMap[i] == fullmask)
771 continue; /* none free for this set */
773 for(j = 0; j < PROC_NSEMS_PER_SET; j++) {
774 if ((freeSemMap[i] & mask) == 0) {
776 * a free semaphore found. Mark it as allocated.
778 freeSemMap[i] |= mask;
780 *key = ProcGlobal->currKey + i;
788 /* if we reach here, all the semaphores are in use. */
789 elog(WARN, "InitProc: cannot allocate a free semaphore");
794 * free up our semaphore in the semaphore set. If we're the last one
795 * in the set, also remove the semaphore set.
798 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
802 int32 *freeSemMap = ProcGlobal->freeSemMap;
804 i = semKey - ProcGlobal->currKey;
805 mask = ~(1 << semNum);
806 freeSemMap[i] &= mask;
808 if (freeSemMap[i]==0)
809 IpcSemaphoreKill(semKey);
813 * ProcFreeAllSemaphores -
814 * on exiting the postmaster, we free up all the semaphores allocated
815 * to the lmgrs of the backends.
818 ProcFreeAllSemaphores()
821 int32 *freeSemMap = ProcGlobal->freeSemMap;
823 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
824 if (freeSemMap[i]!=0)
825 IpcSemaphoreKill(ProcGlobal->currKey + i);