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.9 1996/11/08 05:58:59 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.9 1996/11/08 05:58:59 momjian Exp $
57 #include <sys/types.h>
61 #if defined(sparc_solaris)
67 #include "miscadmin.h"
68 #include "libpq/pqsignal.h" /* substitute for <signal.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 signal(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);
260 * Start keeping spin lock stats from here on. Any botch before
261 * this initialization is forever botched
264 memset(MyProc->sLocks, 0, MAX_SPINS*sizeof(*MyProc->sLocks));
266 /* -------------------------
267 * Install ourselves in the binding table. The name to
268 * use is determined by the OS-assigned process id. That
269 * allows the cleanup process to find us after any untimely
271 * -------------------------
274 location = MAKE_OFFSET(MyProc);
275 if ((! ShmemPIDLookup(pid,&location)) || (location != MAKE_OFFSET(MyProc)))
277 elog(FATAL,"InitProc: ShmemPID table broken");
280 MyProc->errType = NO_ERROR;
281 SHMQueueElemInit(&(MyProc->links));
283 on_exitpg(ProcKill, (caddr_t)pid);
285 ProcInitialized = TRUE;
289 * ProcReleaseLocks() -- release all locks associated with this process
297 LockReleaseAll(1,&MyProc->lockQueue);
302 * used by the postmaster to clean up the global tables. This also frees
303 * up the semaphore used for the lmgr of the process. (We have to do
304 * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
305 * the process because the semaphore set is shared among backends and
306 * we don't want to remove other's semaphores on exit.)
311 SHMEM_OFFSET location;
314 location = INVALID_OFFSET;
316 location = ShmemPIDDestroy(pid);
317 if (location == INVALID_OFFSET)
319 proc = (PROC *) MAKE_PTR(location);
321 SpinAcquire(ProcStructLock);
323 ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
325 proc->links.next = ProcGlobal->freeProcs;
326 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
328 SpinRelease(ProcStructLock);
334 * ProcKill() -- Destroy the per-proc data structure for
335 * this process. Release any of its held spin locks.
338 ProcKill(int exitStatus, int pid)
341 SHMEM_OFFSET location;
343 /* --------------------
344 * If this is a FATAL exit the postmaster will have to kill all the
345 * existing backends and reinitialize shared memory. So all we don't
346 * need to do anything here.
347 * --------------------
357 ShmemPIDLookup(pid,&location);
358 if (location == INVALID_OFFSET)
361 proc = (PROC *) MAKE_PTR(location);
363 if (proc != MyProc) {
364 Assert( pid != getpid() );
369 * Assume one lock table.
372 ProcReleaseSpins(proc);
373 LockReleaseAll(1,&proc->lockQueue);
376 LockReleaseAll(0,&proc->lockQueue);
380 * get off the wait queue
384 if (proc->links.next != INVALID_OFFSET) {
385 Assert(proc->waitLock->waitProcs.size > 0);
386 SHMQueueDelete(&(proc->links));
387 --proc->waitLock->waitProcs.size;
389 SHMQueueElemInit(&(proc->links));
396 * ProcQueue package: routines for putting processes to sleep
401 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
403 * Returns: a pointer to the queue or NULL
404 * Side Effects: Initializes the queue if we allocated one
407 ProcQueueAlloc(char *name)
410 PROC_QUEUE *queue = (PROC_QUEUE *)
411 ShmemInitStruct(name,(unsigned)sizeof(PROC_QUEUE),&found);
419 ProcQueueInit(queue);
425 * ProcQueueInit -- initialize a shared memory process queue
428 ProcQueueInit(PROC_QUEUE *queue)
430 SHMQueueInit(&(queue->links));
437 * ProcSleep -- put a process to sleep
439 * P() on the semaphore should put us to sleep. The process
440 * semaphore is cleared by default, so the first time we try
441 * to acquire it, we sleep.
443 * ASSUME: that no one will fiddle with the queue until after
444 * we release the spin lock.
446 * NOTES: The process queue is now a priority queue for locking.
449 ProcSleep(PROC_QUEUE *queue,
457 #ifndef WIN32 /* figure this out later */
458 struct itimerval timeval, dummy;
461 proc = (PROC *) MAKE_PTR(queue->links.prev);
462 for (i=0;i<queue->size;i++)
464 if (proc->prio < prio)
465 proc = (PROC *) MAKE_PTR(proc->links.prev);
470 MyProc->token = token;
471 MyProc->waitLock = lock;
473 /* -------------------
474 * currently, we only need this for the ProcWakeup routines
475 * -------------------
477 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
479 /* -------------------
480 * assume that these two operations are atomic (because
482 * -------------------
484 SHMQueueInsertTL(&(proc->links),&(MyProc->links));
487 SpinRelease(spinlock);
490 * Postgres does not have any deadlock detection code and for this
491 * reason we must set a timer to wake up the process in the event of
492 * a deadlock. For now the timer is set for 1 minute and we assume that
493 * any process which sleeps for this amount of time is deadlocked and will
494 * receive a SIGALRM signal. The handler should release the processes
495 * semaphore and abort the current transaction.
497 * Need to zero out struct to set the interval and the micro seconds fields
502 memset(&timeval, 0, sizeof(struct itimerval));
503 timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
505 if (setitimer(ITIMER_REAL, &timeval, &dummy))
506 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
522 timeval.it_value.tv_sec = 0;
525 if (setitimer(ITIMER_REAL, &timeval, &dummy))
526 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
530 * We were assumed to be in a critical section when we went
534 SpinAcquire(spinlock);
536 return(MyProc->errType);
541 * ProcWakeup -- wake up a process by releasing its private semaphore.
543 * remove the process from the wait queue and set its links invalid.
544 * RETURN: the next process in the wait queue.
547 ProcWakeup(PROC *proc, int errType)
550 /* assume that spinlock has been acquired */
552 if (proc->links.prev == INVALID_OFFSET ||
553 proc->links.next == INVALID_OFFSET)
554 return((PROC *) NULL);
556 retProc = (PROC *) MAKE_PTR(proc->links.prev);
558 /* you have to update waitLock->waitProcs.size yourself */
559 SHMQueueDelete(&(proc->links));
560 SHMQueueElemInit(&(proc->links));
562 proc->errType = errType;
564 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
576 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 /* ------------------------
686 * Get this process off the lock's wait queue
687 * ------------------------
689 Assert(lock->waitProcs.size > 0);
690 --lock->waitProcs.size;
691 SHMQueueDelete(&(MyProc->links));
692 SHMQueueElemInit(&(MyProc->links));
694 /* ------------------
695 * Unlock my semaphore so that the count is right for next time.
696 * I was awoken by a signal, not by someone unlocking my semaphore.
699 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
702 * Set MyProc->errType to STATUS_ERROR so that we abort after
703 * returning from this handler.
706 MyProc->errType = STATUS_ERROR;
709 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
710 * table corruption ("LockReplace: xid table corrupted") due to
711 * race conditions. i don't claim to understand this...
715 elog(NOTICE, "Timeout -- possible deadlock");
720 ProcReleaseSpins(PROC *proc)
729 for (i=0; i < (int)MAX_SPINS; i++)
733 Assert(proc->sLocks[i] == 1);
739 /*****************************************************************************
741 *****************************************************************************/
744 * ProcGetNewSemKeyAndNum -
745 * scan the free semaphore bitmap and allocate a single semaphore from
746 * a semaphore set. (If the semaphore set doesn't exist yet,
747 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
751 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
754 int32 *freeSemMap = ProcGlobal->freeSemMap;
755 unsigned int fullmask;
758 * we hold ProcStructLock when entering this routine. We scan through
759 * the bitmap to look for a free semaphore.
761 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
762 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
766 if (freeSemMap[i] == fullmask)
767 continue; /* none free for this set */
769 for(j = 0; j < PROC_NSEMS_PER_SET; j++) {
770 if ((freeSemMap[i] & mask) == 0) {
772 * a free semaphore found. Mark it as allocated.
774 freeSemMap[i] |= mask;
776 *key = ProcGlobal->currKey + i;
784 /* if we reach here, all the semaphores are in use. */
785 elog(WARN, "InitProc: cannot allocate a free semaphore");
790 * free up our semaphore in the semaphore set. If we're the last one
791 * in the set, also remove the semaphore set.
794 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
798 int32 *freeSemMap = ProcGlobal->freeSemMap;
800 i = semKey - ProcGlobal->currKey;
801 mask = ~(1 << semNum);
802 freeSemMap[i] &= mask;
804 if (freeSemMap[i]==0)
805 IpcSemaphoreKill(semKey);
809 * ProcFreeAllSemaphores -
810 * on exiting the postmaster, we free up all the semaphores allocated
811 * to the lmgrs of the backends.
814 ProcFreeAllSemaphores()
817 int32 *freeSemMap = ProcGlobal->freeSemMap;
819 for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
820 if (freeSemMap[i]!=0)
821 IpcSemaphoreKill(ProcGlobal->currKey + i);