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.21 1997/09/08 21:47:30 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.21 1997/09/08 21:47:30 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);
114 * initializes the global process table. We put it here so that
115 * the postmaster can do this initialization. (ProcFreeAllSem needs
116 * to read this table on exiting the postmaster. If we have the first
117 * backend do this, starting up and killing the postmaster without
118 * starting any backends will be a problem.)
121 InitProcGlobal(IPCKey key)
125 /* attach to the free list */
126 ProcGlobal = (PROC_HDR *)
127 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
129 /* --------------------
130 * We're the first - initialize.
131 * --------------------
137 ProcGlobal->numProcs = 0;
138 ProcGlobal->freeProcs = INVALID_OFFSET;
139 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
140 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
141 ProcGlobal->freeSemMap[i] = 0;
145 /* ------------------------
146 * InitProc -- create a per-process data structure for this process
147 * used by the lock manager on semaphore queues.
148 * ------------------------
151 InitProcess(IPCKey key)
156 unsigned long location,
159 /* ------------------
160 * Routine called if deadlock timer goes off. See ProcSleep()
163 pqsignal(SIGALRM, HandleDeadLock);
165 SpinAcquire(ProcStructLock);
167 /* attach to the free list */
168 ProcGlobal = (PROC_HDR *)
169 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
172 /* this should not happen. InitProcGlobal() is called before this. */
173 elog(WARN, "InitProcess: Proc Header uninitialized");
178 SpinRelease(ProcStructLock);
179 elog(WARN, "ProcInit: you already exist");
183 /* try to get a proc from the free list first */
185 myOffset = ProcGlobal->freeProcs;
187 if (myOffset != INVALID_OFFSET)
189 MyProc = (PROC *) MAKE_PTR(myOffset);
190 ProcGlobal->freeProcs = MyProc->links.next;
196 * have to allocate one. We can't use the normal binding table
197 * mechanism because the proc structure is stored by PID instead
198 * of by a global name (need to look it up by PID when we cleanup
202 MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
205 SpinRelease(ProcStructLock);
206 elog(FATAL, "cannot create new proc: out of memory");
209 /* this cannot be initialized until after the buffer pool */
210 SHMQueueInit(&(MyProc->lockQueue));
211 MyProc->procId = ProcGlobal->numProcs;
212 ProcGlobal->numProcs++;
216 * zero out the spin lock counts and set the sLocks field for
217 * ProcStructLock to 1 as we have acquired this spinlock above but
218 * didn't record it since we didn't have MyProc until now.
220 memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
221 MyProc->sLocks[ProcStructLock] = 1;
224 if (IsUnderPostmaster)
231 ProcGetNewSemKeyAndNum(&semKey, &semNum);
233 semId = IpcSemaphoreCreate(semKey,
236 IpcSemaphoreDefaultStartValue,
241 * we might be reusing a semaphore that belongs to a dead backend.
242 * So be careful and reinitialize its value here.
244 semun.val = IpcSemaphoreDefaultStartValue;
245 semctl(semId, semNum, SETVAL, semun);
247 IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
248 MyProc->sem.semId = semId;
249 MyProc->sem.semNum = semNum;
250 MyProc->sem.semKey = semKey;
254 MyProc->sem.semId = -1;
257 /* ----------------------
259 * ----------------------
261 SpinRelease(ProcStructLock);
264 MyProc->xid = InvalidTransactionId;
270 * Start keeping spin lock stats from here on. Any botch before
271 * this initialization is forever botched
274 memset(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));
276 /* -------------------------
277 * Install ourselves in the binding table. The name to
278 * use is determined by the OS-assigned process id. That
279 * allows the cleanup process to find us after any untimely
281 * -------------------------
284 location = MAKE_OFFSET(MyProc);
285 if ((!ShmemPIDLookup(pid, &location)) || (location != MAKE_OFFSET(MyProc)))
287 elog(FATAL, "InitProc: ShmemPID table broken");
290 MyProc->errType = NO_ERROR;
291 SHMQueueElemInit(&(MyProc->links));
293 on_exitpg(ProcKill, (caddr_t) pid);
295 ProcInitialized = TRUE;
299 * ProcReleaseLocks() -- release all locks associated with this process
307 LockReleaseAll(1, &MyProc->lockQueue);
312 * used by the postmaster to clean up the global tables. This also frees
313 * up the semaphore used for the lmgr of the process. (We have to do
314 * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
315 * the process because the semaphore set is shared among backends and
316 * we don't want to remove other's semaphores on exit.)
321 SHMEM_OFFSET location;
324 location = INVALID_OFFSET;
326 location = ShmemPIDDestroy(pid);
327 if (location == INVALID_OFFSET)
329 proc = (PROC *) MAKE_PTR(location);
331 SpinAcquire(ProcStructLock);
333 ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
335 proc->links.next = ProcGlobal->freeProcs;
336 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
338 SpinRelease(ProcStructLock);
344 * ProcKill() -- Destroy the per-proc data structure for
345 * this process. Release any of its held spin locks.
348 ProcKill(int exitStatus, int pid)
351 SHMEM_OFFSET location;
353 /* --------------------
354 * If this is a FATAL exit the postmaster will have to kill all the
355 * existing backends and reinitialize shared memory. So all we don't
356 * need to do anything here.
357 * --------------------
367 ShmemPIDLookup(pid, &location);
368 if (location == INVALID_OFFSET)
371 proc = (PROC *) MAKE_PTR(location);
375 Assert(pid != getpid());
381 * Assume one lock table.
384 ProcReleaseSpins(proc);
385 LockReleaseAll(1, &proc->lockQueue);
388 LockReleaseAll(0, &proc->lockQueue);
392 * get off the wait queue
396 if (proc->links.next != INVALID_OFFSET)
398 Assert(proc->waitLock->waitProcs.size > 0);
399 SHMQueueDelete(&(proc->links));
400 --proc->waitLock->waitProcs.size;
402 SHMQueueElemInit(&(proc->links));
409 * ProcQueue package: routines for putting processes to sleep
414 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
416 * Returns: a pointer to the queue or NULL
417 * Side Effects: Initializes the queue if we allocated one
421 ProcQueueAlloc(char *name)
424 PROC_QUEUE *queue = (PROC_QUEUE *)
425 ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
433 ProcQueueInit(queue);
441 * ProcQueueInit -- initialize a shared memory process queue
444 ProcQueueInit(PROC_QUEUE *queue)
446 SHMQueueInit(&(queue->links));
453 * ProcSleep -- put a process to sleep
455 * P() on the semaphore should put us to sleep. The process
456 * semaphore is cleared by default, so the first time we try
457 * to acquire it, we sleep.
459 * ASSUME: that no one will fiddle with the queue until after
460 * we release the spin lock.
462 * NOTES: The process queue is now a priority queue for locking.
465 ProcSleep(PROC_QUEUE *queue,
473 struct itimerval timeval,
476 proc = (PROC *) MAKE_PTR(queue->links.prev);
477 for (i = 0; i < queue->size; i++)
479 if (proc->prio < prio)
480 proc = (PROC *) MAKE_PTR(proc->links.prev);
486 MyProc->token = token;
487 MyProc->waitLock = lock;
489 /* -------------------
490 * currently, we only need this for the ProcWakeup routines
491 * -------------------
493 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
495 /* -------------------
496 * assume that these two operations are atomic (because
498 * -------------------
500 SHMQueueInsertTL(&(proc->links), &(MyProc->links));
503 SpinRelease(spinlock);
506 * Postgres does not have any deadlock detection code and for this
507 * reason we must set a timer to wake up the process in the event of
508 * a deadlock. For now the timer is set for 1 minute and we assume that
509 * any process which sleeps for this amount of time is deadlocked and will
510 * receive a SIGALRM signal. The handler should release the processes
511 * semaphore and abort the current transaction.
513 * Need to zero out struct to set the interval and the micro seconds fields
517 memset(&timeval, 0, sizeof(struct itimerval));
518 timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
520 if (setitimer(ITIMER_REAL, &timeval, &dummy))
521 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
524 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
525 * IpcSemaphoreLock will not block. The wakeup is "saved" by
526 * the semaphore implementation.
529 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
532 * We were awoken before a timeout - now disable the timer
535 timeval.it_value.tv_sec = 0;
538 if (setitimer(ITIMER_REAL, &timeval, &dummy))
539 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
542 * We were assumed to be in a critical section when we went
546 SpinAcquire(spinlock);
548 return (MyProc->errType);
553 * ProcWakeup -- wake up a process by releasing its private semaphore.
555 * remove the process from the wait queue and set its links invalid.
556 * RETURN: the next process in the wait queue.
559 ProcWakeup(PROC *proc, int errType)
563 /* assume that spinlock has been acquired */
565 if (proc->links.prev == INVALID_OFFSET ||
566 proc->links.next == INVALID_OFFSET)
567 return ((PROC *) NULL);
569 retProc = (PROC *) MAKE_PTR(proc->links.prev);
571 /* you have to update waitLock->waitProcs.size yourself */
572 SHMQueueDelete(&(proc->links));
573 SHMQueueElemInit(&(proc->links));
575 proc->errType = errType;
577 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
590 return (MyProc->procId);
596 * ProcLockWakeup -- routine for waking up processes when a lock is
600 ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
606 return (STATUS_NOT_FOUND);
608 proc = (PROC *) MAKE_PTR(queue->links.prev);
610 while ((LockResolveConflicts((LOCKTAB *) ltable,
613 proc->xid) == STATUS_OK))
617 * there was a waiting process, grant it the lock before waking it
618 * up. This will prevent another process from seizing the lock
619 * between the time we release the lock master (spinlock) and the
620 * time that the awoken process begins executing again.
622 GrantLock((LOCK *) lock, proc->token);
626 * ProcWakeup removes proc from the lock waiting process queue and
627 * returns the next proc in chain. If a writer just dropped its
628 * lock and there are several waiting readers, wake them all up.
630 proc = ProcWakeup(proc, NO_ERROR);
633 if (!proc || queue->size == 0)
640 /* Something is still blocking us. May have deadlocked. */
641 return (STATUS_NOT_FOUND);
645 ProcAddLock(SHM_QUEUE *elem)
647 SHMQueueInsertTL(&MyProc->lockQueue, elem);
650 /* --------------------
651 * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
652 * while waiting for a lock to be released by some other process. After
653 * the one minute deadline we assume we have a deadlock and must abort
654 * this transaction. We must also indicate that I'm no longer waiting
655 * on a lock so that other processes don't try to wake me up and screw
657 * --------------------
660 HandleDeadLock(int sig)
667 /* ---------------------
668 * Check to see if we've been awoken by anyone in the interim.
670 * If we have we can return and resume our transaction -- happy day.
671 * Before we are awoken the process releasing the lock grants it to
672 * us so we know that we don't have to wait anymore.
674 * Damn these names are LONG! -mer
675 * ---------------------
677 if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
678 IpcSemaphoreDefaultStartValue)
685 * you would think this would be unnecessary, but...
687 * this also means we've been removed already. in some ports (e.g.,
688 * sparc and aix) the semop(2) implementation is such that we can
689 * actually end up in this handler after someone has removed us from
690 * the queue and bopped the semaphore *but the test above fails to
691 * detect the semaphore update* (presumably something weird having to
692 * do with the order in which the semaphore wakeup signal and SIGALRM
695 if (MyProc->links.prev == INVALID_OFFSET ||
696 MyProc->links.next == INVALID_OFFSET)
702 lock = MyProc->waitLock;
703 size = lock->waitProcs.size;/* so we can look at this in the core */
705 #ifdef DEADLOCK_DEBUG
709 /* ------------------------
710 * Get this process off the lock's wait queue
711 * ------------------------
713 Assert(lock->waitProcs.size > 0);
714 --lock->waitProcs.size;
715 SHMQueueDelete(&(MyProc->links));
716 SHMQueueElemInit(&(MyProc->links));
718 /* ------------------
719 * Unlock my semaphore so that the count is right for next time.
720 * I was awoken by a signal, not by someone unlocking my semaphore.
723 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
726 * Set MyProc->errType to STATUS_ERROR so that we abort after
727 * returning from this handler.
730 MyProc->errType = STATUS_ERROR;
733 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
734 * table corruption ("LockReplace: xid table corrupted") due to race
735 * conditions. i don't claim to understand this...
739 elog(NOTICE, "Timeout -- possible deadlock");
744 ProcReleaseSpins(PROC *proc)
753 for (i = 0; i < (int) MAX_SPINS; i++)
757 Assert(proc->sLocks[i] == 1);
763 /*****************************************************************************
765 *****************************************************************************/
768 * ProcGetNewSemKeyAndNum -
769 * scan the free semaphore bitmap and allocate a single semaphore from
770 * a semaphore set. (If the semaphore set doesn't exist yet,
771 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
775 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
778 int32 *freeSemMap = ProcGlobal->freeSemMap;
779 unsigned int fullmask;
782 * we hold ProcStructLock when entering this routine. We scan through
783 * the bitmap to look for a free semaphore.
785 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
786 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
791 if (freeSemMap[i] == fullmask)
792 continue; /* none free for this set */
794 for (j = 0; j < PROC_NSEMS_PER_SET; j++)
796 if ((freeSemMap[i] & mask) == 0)
800 * a free semaphore found. Mark it as allocated.
802 freeSemMap[i] |= mask;
804 *key = ProcGlobal->currKey + i;
812 /* if we reach here, all the semaphores are in use. */
813 elog(WARN, "InitProc: cannot allocate a free semaphore");
818 * free up our semaphore in the semaphore set. If we're the last one
819 * in the set, also remove the semaphore set.
822 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
826 int32 *freeSemMap = ProcGlobal->freeSemMap;
828 i = semKey - ProcGlobal->currKey;
829 mask = ~(1 << semNum);
830 freeSemMap[i] &= mask;
832 if (freeSemMap[i] == 0)
833 IpcSemaphoreKill(semKey);
837 * ProcFreeAllSemaphores -
838 * on exiting the postmaster, we free up all the semaphores allocated
839 * to the lmgrs of the backends.
842 ProcFreeAllSemaphores()
845 int32 *freeSemMap = ProcGlobal->freeSemMap;
847 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
849 if (freeSemMap[i] != 0)
850 IpcSemaphoreKill(ProcGlobal->currKey + i);