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.34 1998/02/26 04:36:12 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.34 1998/02/26 04:36:12 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->freeProcs = INVALID_OFFSET;
131 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
132 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
133 ProcGlobal->freeSemMap[i] = 0;
137 /* ------------------------
138 * InitProc -- create a per-process data structure for this process
139 * used by the lock manager on semaphore queues.
140 * ------------------------
143 InitProcess(IPCKey key)
147 unsigned long location,
150 /* ------------------
151 * Routine called if deadlock timer goes off. See ProcSleep()
154 pqsignal(SIGALRM, HandleDeadLock);
156 SpinAcquire(ProcStructLock);
158 /* attach to the free list */
159 ProcGlobal = (PROC_HDR *)
160 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
163 /* this should not happen. InitProcGlobal() is called before this. */
164 elog(ERROR, "InitProcess: Proc Header uninitialized");
169 SpinRelease(ProcStructLock);
170 elog(ERROR, "ProcInit: you already exist");
174 /* try to get a proc from the free list first */
176 myOffset = ProcGlobal->freeProcs;
178 if (myOffset != INVALID_OFFSET)
180 MyProc = (PROC *) MAKE_PTR(myOffset);
181 ProcGlobal->freeProcs = MyProc->links.next;
187 * have to allocate one. We can't use the normal binding table
188 * mechanism because the proc structure is stored by PID instead
189 * of by a global name (need to look it up by PID when we cleanup
193 MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
196 SpinRelease(ProcStructLock);
197 elog(FATAL, "cannot create new proc: out of memory");
200 /* this cannot be initialized until after the buffer pool */
201 SHMQueueInit(&(MyProc->lockQueue));
205 * zero out the spin lock counts and set the sLocks field for
206 * ProcStructLock to 1 as we have acquired this spinlock above but
207 * didn't record it since we didn't have MyProc until now.
209 MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
210 MyProc->sLocks[ProcStructLock] = 1;
213 if (IsUnderPostmaster)
220 ProcGetNewSemKeyAndNum(&semKey, &semNum);
222 semId = IpcSemaphoreCreate(semKey,
225 IpcSemaphoreDefaultStartValue,
230 * we might be reusing a semaphore that belongs to a dead backend.
231 * So be careful and reinitialize its value here.
233 semun.val = IpcSemaphoreDefaultStartValue;
234 semctl(semId, semNum, SETVAL, semun);
236 IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
237 MyProc->sem.semId = semId;
238 MyProc->sem.semNum = semNum;
239 MyProc->sem.semKey = semKey;
243 MyProc->sem.semId = -1;
246 /* ----------------------
248 * ----------------------
250 SpinRelease(ProcStructLock);
254 MyProc->pid = MyProcPid;
256 MyProc->xid = InvalidTransactionId;
259 * Start keeping spin lock stats from here on. Any botch before
260 * this initialization is forever botched
263 MemSet(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));
265 /* -------------------------
266 * Install ourselves in the binding table. The name to
267 * use is determined by the OS-assigned process id. That
268 * allows the cleanup process to find us after any untimely
270 * -------------------------
272 location = MAKE_OFFSET(MyProc);
273 if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
275 elog(FATAL, "InitProc: ShmemPID table broken");
278 MyProc->errType = NO_ERROR;
279 SHMQueueElemInit(&(MyProc->links));
281 on_exitpg(ProcKill, (caddr_t) MyProcPid);
283 ProcInitialized = TRUE;
287 * ProcReleaseLocks() -- release all locks associated with this process
295 LockReleaseAll(1, &MyProc->lockQueue);
300 * used by the postmaster to clean up the global tables. This also frees
301 * up the semaphore used for the lmgr of the process. (We have to do
302 * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
303 * the process because the semaphore set is shared among backends and
304 * we don't want to remove other's semaphores on exit.)
309 SHMEM_OFFSET location;
312 location = INVALID_OFFSET;
314 location = ShmemPIDDestroy(pid);
315 if (location == INVALID_OFFSET)
317 proc = (PROC *) MAKE_PTR(location);
319 SpinAcquire(ProcStructLock);
321 ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
323 proc->links.next = ProcGlobal->freeProcs;
324 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
326 SpinRelease(ProcStructLock);
332 * ProcKill() -- Destroy the per-proc data structure for
333 * this process. Release any of its held spin locks.
336 ProcKill(int exitStatus, int pid)
339 SHMEM_OFFSET location;
341 /* --------------------
342 * If this is a FATAL exit the postmaster will have to kill all the
343 * existing backends and reinitialize shared memory. So all we don't
344 * need to do anything here.
345 * --------------------
350 ShmemPIDLookup(MyProcPid, &location);
351 if (location == INVALID_OFFSET)
354 proc = (PROC *) MAKE_PTR(location);
358 Assert(pid != MyProcPid);
364 * Assume one lock table.
367 ProcReleaseSpins(proc);
368 LockReleaseAll(1, &proc->lockQueue);
371 LockReleaseAll(0, &proc->lockQueue);
375 * get off the wait queue
379 if (proc->links.next != INVALID_OFFSET)
381 Assert(proc->waitLock->waitProcs.size > 0);
382 SHMQueueDelete(&(proc->links));
383 --proc->waitLock->waitProcs.size;
385 SHMQueueElemInit(&(proc->links));
392 * ProcQueue package: routines for putting processes to sleep
397 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
399 * Returns: a pointer to the queue or NULL
400 * Side Effects: Initializes the queue if we allocated one
404 ProcQueueAlloc(char *name)
407 PROC_QUEUE *queue = (PROC_QUEUE *)
408 ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
416 ProcQueueInit(queue);
424 * ProcQueueInit -- initialize a shared memory process queue
427 ProcQueueInit(PROC_QUEUE *queue)
429 SHMQueueInit(&(queue->links));
436 * ProcSleep -- put a process to sleep
438 * P() on the semaphore should put us to sleep. The process
439 * semaphore is cleared by default, so the first time we try
440 * to acquire it, we sleep.
442 * ASSUME: that no one will fiddle with the queue until after
443 * we release the spin lock.
445 * NOTES: The process queue is now a priority queue for locking.
448 ProcSleep(PROC_QUEUE *waitQueue,
456 struct itimerval timeval,
460 * If the first entries in the waitQueue have a greater priority than
461 * we have, we must be a reader, and they must be a writers, and we
462 * must be here because the current holder is a writer or a reader but
463 * we don't share shared locks if a writer is waiting. We put
464 * ourselves after the writers. This way, we have a FIFO, but keep
465 * the readers together to give them decent priority, and no one
466 * starves. Because we group all readers together, a non-empty queue
467 * only has a few possible configurations:
469 * [readers] [writers] [readers][writers] [writers][readers]
470 * [writers][readers][writers]
472 * In a full queue, we would have a reader holding a lock, then a writer
473 * gets the lock, then a bunch of readers, made up of readers who
474 * could not share the first readlock because a writer was waiting,
475 * and new readers arriving while the writer had the lock.
478 proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
480 /* If we are a reader, and they are writers, skip past them */
482 for (i = 0; i < waitQueue->size && proc->prio > prio; i++)
483 proc = (PROC *) MAKE_PTR(proc->links.prev);
485 /* The rest of the queue is FIFO, with readers first, writers last */
486 for (; i < waitQueue->size && proc->prio <= prio; i++)
487 proc = (PROC *) MAKE_PTR(proc->links.prev);
490 MyProc->token = token;
491 MyProc->waitLock = lock;
493 /* -------------------
494 * currently, we only need this for the ProcWakeup routines
495 * -------------------
497 TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
499 /* -------------------
500 * assume that these two operations are atomic (because
502 * -------------------
504 SHMQueueInsertTL(&(proc->links), &(MyProc->links));
507 SpinRelease(spinlock);
510 * We set this so we can wake up periodically and check for a deadlock.
511 * If a deadlock is detected, the handler releases the processes
512 * semaphore and aborts the current transaction.
514 * Need to zero out struct to set the interval and the micro seconds fields
518 MemSet(&timeval, 0, sizeof(struct itimerval));
519 timeval.it_value.tv_sec = DEADLOCK_CHECK_TIMER;
523 MyProc->errType = NO_ERROR; /* reset flag after deadlock check */
525 if (setitimer(ITIMER_REAL, &timeval, &dummy))
526 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
529 * if someone wakes us between SpinRelease and IpcSemaphoreLock,
530 * IpcSemaphoreLock will not block. The wakeup is "saved" by
531 * the semaphore implementation.
534 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
535 } while (MyProc->errType == STATUS_NOT_FOUND); /* sleep after deadlock
539 * We were awoken before a timeout - now disable the timer
542 timeval.it_value.tv_sec = 0;
545 if (setitimer(ITIMER_REAL, &timeval, &dummy))
546 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
549 * We were assumed to be in a critical section when we went
553 SpinAcquire(spinlock);
555 return (MyProc->errType);
560 * ProcWakeup -- wake up a process by releasing its private semaphore.
562 * remove the process from the wait queue and set its links invalid.
563 * RETURN: the next process in the wait queue.
566 ProcWakeup(PROC *proc, int errType)
570 /* assume that spinlock has been acquired */
572 if (proc->links.prev == INVALID_OFFSET ||
573 proc->links.next == INVALID_OFFSET)
574 return ((PROC *) NULL);
576 retProc = (PROC *) MAKE_PTR(proc->links.prev);
578 /* you have to update waitLock->waitProcs.size yourself */
579 SHMQueueDelete(&(proc->links));
580 SHMQueueElemInit(&(proc->links));
582 proc->errType = errType;
584 IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
590 * ProcLockWakeup -- routine for waking up processes when a lock is
594 ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
600 return (STATUS_NOT_FOUND);
602 proc = (PROC *) MAKE_PTR(queue->links.prev);
604 while ((LockResolveConflicts((LOCKTAB *) ltable,
607 proc->xid) == STATUS_OK))
611 * there was a waiting process, grant it the lock before waking it
612 * up. This will prevent another process from seizing the lock
613 * between the time we release the lock master (spinlock) and the
614 * time that the awoken process begins executing again.
616 GrantLock((LOCK *) lock, proc->token);
620 * ProcWakeup removes proc from the lock waiting process queue and
621 * returns the next proc in chain.
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_CHECK_TIMER
645 * while waiting for a lock to be released by some other process. If we have
646 * a real deadlock, we must also indicate that I'm no longer waiting
647 * on a lock so that other processes don't try to wake me up and screw
649 * --------------------
652 HandleDeadLock(int sig)
658 /* ---------------------
659 * Check to see if we've been awoken by anyone in the interim.
661 * If we have we can return and resume our transaction -- happy day.
662 * Before we are awoken the process releasing the lock grants it to
663 * us so we know that we don't have to wait anymore.
665 * Damn these names are LONG! -mer
666 * ---------------------
668 if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
669 IpcSemaphoreDefaultStartValue)
676 * you would think this would be unnecessary, but...
678 * this also means we've been removed already. in some ports (e.g.,
679 * sparc and aix) the semop(2) implementation is such that we can
680 * actually end up in this handler after someone has removed us from
681 * the queue and bopped the semaphore *but the test above fails to
682 * detect the semaphore update* (presumably something weird having to
683 * do with the order in which the semaphore wakeup signal and SIGALRM
686 if (MyProc->links.prev == INVALID_OFFSET ||
687 MyProc->links.next == INVALID_OFFSET)
693 #ifdef DEADLOCK_DEBUG
697 if (!DeadLockCheck(&(MyProc->lockQueue), MyProc->waitLock, true))
700 MyProc->errType = STATUS_NOT_FOUND;
704 mywaitlock = MyProc->waitLock;
706 /* ------------------------
707 * Get this process off the lock's wait queue
708 * ------------------------
710 Assert(mywaitlock->waitProcs.size > 0);
711 --mywaitlock->waitProcs.size;
712 SHMQueueDelete(&(MyProc->links));
713 SHMQueueElemInit(&(MyProc->links));
715 /* ------------------
716 * Unlock my semaphore so that the count is right for next time.
717 * I was awoken by a signal, not by someone unlocking my semaphore.
720 IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
723 * Set MyProc->errType to STATUS_ERROR so that we abort after
724 * returning from this handler.
727 MyProc->errType = STATUS_ERROR;
730 * if this doesn't follow the IpcSemaphoreUnlock then we get lock
731 * table corruption ("LockReplace: xid table corrupted") due to race
732 * conditions. i don't claim to understand this...
736 elog(NOTICE, "Deadlock detected -- See the lock(l) manual page for a possible cause.");
741 ProcReleaseSpins(PROC *proc)
750 for (i = 0; i < (int) MAX_SPINS; i++)
754 Assert(proc->sLocks[i] == 1);
760 /*****************************************************************************
762 *****************************************************************************/
765 * ProcGetNewSemKeyAndNum -
766 * scan the free semaphore bitmap and allocate a single semaphore from
767 * a semaphore set. (If the semaphore set doesn't exist yet,
768 * IpcSemaphoreCreate will create it. Otherwise, we use the existing
772 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
775 int32 *freeSemMap = ProcGlobal->freeSemMap;
776 unsigned int fullmask;
779 * we hold ProcStructLock when entering this routine. We scan through
780 * the bitmap to look for a free semaphore.
782 fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
783 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
788 if (freeSemMap[i] == fullmask)
789 continue; /* none free for this set */
791 for (j = 0; j < PROC_NSEMS_PER_SET; j++)
793 if ((freeSemMap[i] & mask) == 0)
797 * a free semaphore found. Mark it as allocated.
799 freeSemMap[i] |= mask;
801 *key = ProcGlobal->currKey + i;
809 /* if we reach here, all the semaphores are in use. */
810 elog(ERROR, "InitProc: cannot allocate a free semaphore");
815 * free up our semaphore in the semaphore set. If we're the last one
816 * in the set, also remove the semaphore set.
819 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
823 int32 *freeSemMap = ProcGlobal->freeSemMap;
825 i = semKey - ProcGlobal->currKey;
826 mask = ~(1 << semNum);
827 freeSemMap[i] &= mask;
829 if (freeSemMap[i] == 0)
830 IpcSemaphoreKill(semKey);
834 * ProcFreeAllSemaphores -
835 * on exiting the postmaster, we free up all the semaphores allocated
836 * to the lmgrs of the backends.
839 ProcFreeAllSemaphores()
842 int32 *freeSemMap = ProcGlobal->freeSemMap;
844 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
846 if (freeSemMap[i] != 0)
847 IpcSemaphoreKill(ProcGlobal->currKey + i);