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.23 1997/10/30 17:23: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.23 1997/10/30 17:23:59 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);
82 /* --------------------
83 * Spin lock for manipulating the shared process data structure:
84 * ProcGlobal.... Adding an extra spin lock seemed like the smallest
85 * hack to get around reading and updating this structure in shared
86 * memory. -mer 17 July 1991
87 * --------------------
89 SPINLOCK ProcStructLock;
92 * For cleanup routines. Don't cleanup if the initialization
95 static bool ProcInitialized = FALSE;
97 static PROC_HDR *ProcGlobal = NULL;
101 static void ProcKill(int exitStatus, int pid);
102 static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
103 static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
107 * initializes the global process table. We put it here so that
108 * the postmaster can do this initialization. (ProcFreeAllSem needs
109 * to read this table on exiting the postmaster. If we have the first
110 * backend do this, starting up and killing the postmaster without
111 * starting any backends will be a problem.)
114 InitProcGlobal(IPCKey key)
118 /* attach to the free list */
119 ProcGlobal = (PROC_HDR *)
120 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
122 /* --------------------
123 * We're the first - initialize.
124 * --------------------
130 ProcGlobal->numProcs = 0;
131 ProcGlobal->freeProcs = INVALID_OFFSET;
132 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
133 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
134 ProcGlobal->freeSemMap[i] = 0;
138 /* ------------------------
139 * InitProc -- create a per-process data structure for this process
140 * used by the lock manager on semaphore queues.
141 * ------------------------
144 InitProcess(IPCKey key)
149 unsigned long location,
152 /* ------------------
153 * Routine called if deadlock timer goes off. See ProcSleep()
156 pqsignal(SIGALRM, HandleDeadLock);
158 SpinAcquire(ProcStructLock);
160 /* attach to the free list */
161 ProcGlobal = (PROC_HDR *)
162 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
165 /* this should not happen. InitProcGlobal() is called before this. */
166 elog(WARN, "InitProcess: Proc Header uninitialized");
171 SpinRelease(ProcStructLock);
172 elog(WARN, "ProcInit: you already exist");
176 /* try to get a proc from the free list first */
178 myOffset = ProcGlobal->freeProcs;
180 if (myOffset != INVALID_OFFSET)
182 MyProc = (PROC *) MAKE_PTR(myOffset);
183 ProcGlobal->freeProcs = MyProc->links.next;
189 * have to allocate one. We can't use the normal binding table
190 * mechanism because the proc structure is stored by PID instead
191 * of by a global name (need to look it up by PID when we cleanup
195 MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
198 SpinRelease(ProcStructLock);
199 elog(FATAL, "cannot create new proc: out of memory");
202 /* this cannot be initialized until after the buffer pool */
203 SHMQueueInit(&(MyProc->lockQueue));
204 MyProc->procId = ProcGlobal->numProcs;
205 ProcGlobal->numProcs++;
209 * zero out the spin lock counts and set the sLocks field for
210 * ProcStructLock to 1 as we have acquired this spinlock above but
211 * didn't record it since we didn't have MyProc until now.
213 MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
214 MyProc->sLocks[ProcStructLock] = 1;
217 if (IsUnderPostmaster)
224 ProcGetNewSemKeyAndNum(&semKey, &semNum);
226 semId = IpcSemaphoreCreate(semKey,
229 IpcSemaphoreDefaultStartValue,
234 * we might be reusing a semaphore that belongs to a dead backend.
235 * 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;
247 MyProc->sem.semId = -1;
250 /* ----------------------
252 * ----------------------
254 SpinRelease(ProcStructLock);
257 MyProc->xid = InvalidTransactionId;
263 * Start keeping spin lock stats from here on. Any botch before
264 * this initialization is forever botched
267 MemSet(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));
269 /* -------------------------
270 * Install ourselves in the binding table. The name to
271 * use is determined by the OS-assigned process id. That
272 * allows the cleanup process to find us after any untimely
274 * -------------------------
277 location = MAKE_OFFSET(MyProc);
278 if ((!ShmemPIDLookup(pid, &location)) || (location != MAKE_OFFSET(MyProc)))
280 elog(FATAL, "InitProc: ShmemPID table broken");
283 MyProc->errType = NO_ERROR;
284 SHMQueueElemInit(&(MyProc->links));
286 on_exitpg(ProcKill, (caddr_t) pid);
288 ProcInitialized = TRUE;
292 * ProcReleaseLocks() -- release all locks associated with this process
300 LockReleaseAll(1, &MyProc->lockQueue);
305 * used by the postmaster to clean up the global tables. This also frees
306 * up the semaphore used for the lmgr of the process. (We have to do
307 * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
308 * the process because the semaphore set is shared among backends and
309 * we don't want to remove other's semaphores on exit.)
314 SHMEM_OFFSET location;
317 location = INVALID_OFFSET;
319 location = ShmemPIDDestroy(pid);
320 if (location == INVALID_OFFSET)
322 proc = (PROC *) MAKE_PTR(location);
324 SpinAcquire(ProcStructLock);
326 ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
328 proc->links.next = ProcGlobal->freeProcs;
329 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
331 SpinRelease(ProcStructLock);
337 * ProcKill() -- Destroy the per-proc data structure for
338 * this process. Release any of its held spin locks.
341 ProcKill(int exitStatus, int pid)
344 SHMEM_OFFSET location;
346 /* --------------------
347 * If this is a FATAL exit the postmaster will have to kill all the
348 * existing backends and reinitialize shared memory. So all we don't
349 * need to do anything here.
350 * --------------------
360 ShmemPIDLookup(pid, &location);
361 if (location == INVALID_OFFSET)
364 proc = (PROC *) MAKE_PTR(location);
368 Assert(pid != getpid());
374 * Assume one lock table.
377 ProcReleaseSpins(proc);
378 LockReleaseAll(1, &proc->lockQueue);
381 LockReleaseAll(0, &proc->lockQueue);
385 * get off the wait queue
389 if (proc->links.next != INVALID_OFFSET)
391 Assert(proc->waitLock->waitProcs.size > 0);
392 SHMQueueDelete(&(proc->links));
393 --proc->waitLock->waitProcs.size;
395 SHMQueueElemInit(&(proc->links));
402 * ProcQueue package: routines for putting processes to sleep
407 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
409 * Returns: a pointer to the queue or NULL
410 * Side Effects: Initializes the queue if we allocated one
414 ProcQueueAlloc(char *name)
417 PROC_QUEUE *queue = (PROC_QUEUE *)
418 ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
426 ProcQueueInit(queue);
434 * ProcQueueInit -- initialize a shared memory process queue
437 ProcQueueInit(PROC_QUEUE *queue)
439 SHMQueueInit(&(queue->links));
446 * ProcSleep -- put a process to sleep
448 * P() on the semaphore should put us to sleep. The process
449 * semaphore is cleared by default, so the first time we try
450 * to acquire it, we sleep.
452 * ASSUME: that no one will fiddle with the queue until after
453 * we release the spin lock.
455 * NOTES: The process queue is now a priority queue for locking.
458 ProcSleep(PROC_QUEUE *queue,
466 struct itimerval timeval,
469 proc = (PROC *) MAKE_PTR(queue->links.prev);
470 for (i = 0; i < queue->size; i++)
472 if (proc->prio < prio)
473 proc = (PROC *) MAKE_PTR(proc->links.prev);
479 MyProc->token = token;
480 MyProc->waitLock = lock;
482 /* -------------------
483 * currently, we only need this for the ProcWakeup routines
484 * -------------------
486 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
488 /* -------------------
489 * assume that these two operations are atomic (because
491 * -------------------
493 SHMQueueInsertTL(&(proc->links), &(MyProc->links));
496 SpinRelease(spinlock);
499 * Postgres does not have any deadlock detection code and for this
500 * reason we must set a timer to wake up the process in the event of
501 * a deadlock. For now the timer is set for 1 minute and we assume that
502 * any process which sleeps for this amount of time is deadlocked and will
503 * receive a SIGALRM signal. The handler should release the processes
504 * semaphore and abort the current transaction.
506 * Need to zero out struct to set the interval and the micro seconds fields
510 MemSet(&timeval, 0, sizeof(struct itimerval));
511 timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
513 if (setitimer(ITIMER_REAL, &timeval, &dummy))
514 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
517 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
518 * IpcSemaphoreLock will not block. The wakeup is "saved" by
519 * the semaphore implementation.
522 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
525 * We were awoken before a timeout - now disable the timer
528 timeval.it_value.tv_sec = 0;
531 if (setitimer(ITIMER_REAL, &timeval, &dummy))
532 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
535 * We were assumed to be in a critical section when we went
539 SpinAcquire(spinlock);
541 return (MyProc->errType);
546 * ProcWakeup -- wake up a process by releasing its private semaphore.
548 * remove the process from the wait queue and set its links invalid.
549 * RETURN: the next process in the wait queue.
552 ProcWakeup(PROC *proc, int errType)
556 /* assume that spinlock has been acquired */
558 if (proc->links.prev == INVALID_OFFSET ||
559 proc->links.next == INVALID_OFFSET)
560 return ((PROC *) NULL);
562 retProc = (PROC *) MAKE_PTR(proc->links.prev);
564 /* you have to update waitLock->waitProcs.size yourself */
565 SHMQueueDelete(&(proc->links));
566 SHMQueueElemInit(&(proc->links));
568 proc->errType = errType;
570 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
583 return (MyProc->procId);
589 * ProcLockWakeup -- routine for waking up processes when a lock is
593 ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
599 return (STATUS_NOT_FOUND);
601 proc = (PROC *) MAKE_PTR(queue->links.prev);
603 while ((LockResolveConflicts((LOCKTAB *) ltable,
606 proc->xid) == STATUS_OK))
610 * there was a waiting process, grant it the lock before waking it
611 * up. This will prevent another process from seizing the lock
612 * between the time we release the lock master (spinlock) and the
613 * time that the awoken process begins executing again.
615 GrantLock((LOCK *) lock, proc->token);
619 * ProcWakeup removes proc from the lock waiting process queue and
620 * returns the next proc in chain. If a writer just dropped its
621 * lock and there are several waiting readers, wake them all up.
623 proc = ProcWakeup(proc, NO_ERROR);
626 if (!proc || queue->size == 0)
633 /* Something is still blocking us. May have deadlocked. */
634 return (STATUS_NOT_FOUND);
638 ProcAddLock(SHM_QUEUE *elem)
640 SHMQueueInsertTL(&MyProc->lockQueue, elem);
643 /* --------------------
644 * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
645 * while waiting for a lock to be released by some other process. After
646 * the one minute deadline we assume we have a deadlock and must abort
647 * this transaction. We must also indicate that I'm no longer waiting
648 * on a lock so that other processes don't try to wake me up and screw
650 * --------------------
653 HandleDeadLock(int sig)
660 /* ---------------------
661 * Check to see if we've been awoken by anyone in the interim.
663 * If we have we can return and resume our transaction -- happy day.
664 * Before we are awoken the process releasing the lock grants it to
665 * us so we know that we don't have to wait anymore.
667 * Damn these names are LONG! -mer
668 * ---------------------
670 if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
671 IpcSemaphoreDefaultStartValue)
678 * you would think this would be unnecessary, but...
680 * this also means we've been removed already. in some ports (e.g.,
681 * sparc and aix) the semop(2) implementation is such that we can
682 * actually end up in this handler after someone has removed us from
683 * the queue and bopped the semaphore *but the test above fails to
684 * detect the semaphore update* (presumably something weird having to
685 * do with the order in which the semaphore wakeup signal and SIGALRM
688 if (MyProc->links.prev == INVALID_OFFSET ||
689 MyProc->links.next == INVALID_OFFSET)
695 lock = MyProc->waitLock;
696 size = lock->waitProcs.size;/* so we can look at this in the core */
698 #ifdef DEADLOCK_DEBUG
702 /* ------------------------
703 * Get this process off the lock's wait queue
704 * ------------------------
706 Assert(lock->waitProcs.size > 0);
707 --lock->waitProcs.size;
708 SHMQueueDelete(&(MyProc->links));
709 SHMQueueElemInit(&(MyProc->links));
711 /* ------------------
712 * Unlock my semaphore so that the count is right for next time.
713 * I was awoken by a signal, not by someone unlocking my semaphore.
716 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
719 * Set MyProc->errType to STATUS_ERROR so that we abort after
720 * returning from this handler.
723 MyProc->errType = STATUS_ERROR;
726 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
727 * table corruption ("LockReplace: xid table corrupted") due to race
728 * conditions. i don't claim to understand this...
732 elog(NOTICE, "Timeout -- possible deadlock");
737 ProcReleaseSpins(PROC *proc)
746 for (i = 0; i < (int) MAX_SPINS; i++)
750 Assert(proc->sLocks[i] == 1);
756 /*****************************************************************************
758 *****************************************************************************/
761 * ProcGetNewSemKeyAndNum -
762 * scan the free semaphore bitmap and allocate a single semaphore from
763 * a semaphore set. (If the semaphore set doesn't exist yet,
764 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
768 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
771 int32 *freeSemMap = ProcGlobal->freeSemMap;
772 unsigned int fullmask;
775 * we hold ProcStructLock when entering this routine. We scan through
776 * the bitmap to look for a free semaphore.
778 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
779 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
784 if (freeSemMap[i] == fullmask)
785 continue; /* none free for this set */
787 for (j = 0; j < PROC_NSEMS_PER_SET; j++)
789 if ((freeSemMap[i] & mask) == 0)
793 * a free semaphore found. Mark it as allocated.
795 freeSemMap[i] |= mask;
797 *key = ProcGlobal->currKey + i;
805 /* if we reach here, all the semaphores are in use. */
806 elog(WARN, "InitProc: cannot allocate a free semaphore");
811 * free up our semaphore in the semaphore set. If we're the last one
812 * in the set, also remove the semaphore set.
815 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
819 int32 *freeSemMap = ProcGlobal->freeSemMap;
821 i = semKey - ProcGlobal->currKey;
822 mask = ~(1 << semNum);
823 freeSemMap[i] &= mask;
825 if (freeSemMap[i] == 0)
826 IpcSemaphoreKill(semKey);
830 * ProcFreeAllSemaphores -
831 * on exiting the postmaster, we free up all the semaphores allocated
832 * to the lmgrs of the backends.
835 ProcFreeAllSemaphores()
838 int32 *freeSemMap = ProcGlobal->freeSemMap;
840 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
842 if (freeSemMap[i] != 0)
843 IpcSemaphoreKill(ProcGlobal->currKey + i);