]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/proc.c
Rearrange handling of MAXBACKENDS a little bit. The default setting
[postgresql] / src / backend / storage / lmgr / proc.c
1 /*-------------------------------------------------------------------------
2  *
3  * proc.c
4  *        routines to manage per-process shared memory data structure
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.51 1999/02/21 01:41:45 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  *      Each postgres backend gets one of these.  We'll use it to
16  *      clean up after the process should the process suddenly die.
17  *
18  *
19  * Interface (a):
20  *              ProcSleep(), ProcWakeup(), ProcWakeupNext(),
21  *              ProcQueueAlloc() -- create a shm queue for sleeping processes
22  *              ProcQueueInit() -- create a queue without allocing memory
23  *
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).
28  *
29  * Interface (b):
30  *
31  * ProcReleaseLocks -- frees the locks associated with this process,
32  * ProcKill -- destroys the shared memory state (and locks)
33  *              associated with the process.
34  *
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.
42  *
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
48  *
49  * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.51 1999/02/21 01:41:45 tgl Exp $
50  */
51 #include <sys/time.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <signal.h>
55 #include <sys/types.h>
56
57 #if defined(solaris_sparc)
58 #include <sys/ipc.h>
59 #include <sys/sem.h>
60 #endif
61
62 #include "postgres.h"
63 #include "miscadmin.h"
64 #include "libpq/pqsignal.h"
65
66 #include "access/xact.h"
67 #include "utils/hsearch.h"
68
69 #include "storage/ipc.h"
70 /* In Ultrix, sem.h must be included after ipc.h */
71 #include <sys/sem.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"
78 #include "utils/trace.h"
79
80 static void HandleDeadLock(int sig);
81 static PROC *ProcWakeup(PROC *proc, int errType);
82 static void ProcFreeAllSemaphores(void);
83
84 #define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]
85
86 /* --------------------
87  * Spin lock for manipulating the shared process data structure:
88  * ProcGlobal.... Adding an extra spin lock seemed like the smallest
89  * hack to get around reading and updating this structure in shared
90  * memory. -mer 17 July 1991
91  * --------------------
92  */
93 SPINLOCK        ProcStructLock;
94
95 /*
96  * For cleanup routines.  Don't cleanup if the initialization
97  * has not happened.
98  */
99 static bool ProcInitialized = FALSE;
100
101 static PROC_HDR *ProcGlobal = NULL;
102
103 PROC       *MyProc = NULL;
104
105 static void ProcKill(int exitStatus, int pid);
106 static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
107 static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
108
109 /*
110  * InitProcGlobal -
111  *        initializes the global process table. We put it here so that
112  *        the postmaster can do this initialization. (ProcFreeAllSemaphores 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.)
116  *
117  *        We also allocate all the per-process semaphores we will need to support
118  *        the requested number of backends.  We used to allocate semaphores
119  *        only when backends were actually started up, but that is bad because
120  *        it lets Postgres fail under load --- a lot of Unix systems are
121  *        (mis)configured with small limits on the number of semaphores, and
122  *        running out when trying to start another backend is a common failure.
123  *        So, now we grab enough semaphores to support the desired max number
124  *        of backends immediately at initialization --- if the sysadmin has set
125  *        MaxBackends higher than his kernel will support, he'll find out sooner
126  *        rather than later.
127  */
128 void
129 InitProcGlobal(IPCKey key, int maxBackends)
130 {
131         bool            found = false;
132
133         /* attach to the free list */
134         ProcGlobal = (PROC_HDR *)
135                 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
136
137         /* --------------------
138          * We're the first - initialize.
139          * XXX if found should ever be true, it is a sign of impending doom ...
140          * ought to complain if so?
141          * --------------------
142          */
143         if (!found)
144         {
145                 int                     i;
146
147                 ProcGlobal->freeProcs = INVALID_OFFSET;
148                 ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
149                 for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
150                         ProcGlobal->freeSemMap[i] = 0;
151
152                 /* Arrange to delete semas on exit --- set this up now so that
153                  * we will clean up if pre-allocation fails...
154                  */
155                 on_shmem_exit(ProcFreeAllSemaphores, NULL);
156
157                 /* Pre-create the semaphores for the first maxBackends processes,
158                  * unless we are running as a standalone backend.
159                  */
160                 if (key != PrivateIPCKey)
161                 {
162                         for (i = 0;
163                                  i < (maxBackends+PROC_NSEMS_PER_SET-1) / PROC_NSEMS_PER_SET;
164                                  i++)
165                         {
166                                 IPCKey          semKey = ProcGlobal->currKey + i;
167                                 int                     semId;
168                                 int                     semstat;
169
170                                 semId = IpcSemaphoreCreate(semKey,
171                                                                                    PROC_NSEMS_PER_SET,
172                                                                                    IPCProtection,
173                                                                                    IpcSemaphoreDefaultStartValue,
174                                                                                    0,
175                                                                                    &semstat);
176                                 /* mark this sema set allocated */
177                                 ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
178                         }
179                 }
180         }
181 }
182
183 /* ------------------------
184  * InitProc -- create a per-process data structure for this process
185  * used by the lock manager on semaphore queues.
186  * ------------------------
187  */
188 void
189 InitProcess(IPCKey key)
190 {
191         bool            found = false;
192         int                     semstat;
193         unsigned long location,
194                                 myOffset;
195
196         /* ------------------
197          * Routine called if deadlock timer goes off. See ProcSleep()
198          * ------------------
199          */
200         pqsignal(SIGALRM, HandleDeadLock);
201
202         SpinAcquire(ProcStructLock);
203
204         /* attach to the free list */
205         ProcGlobal = (PROC_HDR *)
206                 ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
207         if (!found)
208         {
209                 /* this should not happen. InitProcGlobal() is called before this. */
210                 elog(ERROR, "InitProcess: Proc Header uninitialized");
211         }
212
213         if (MyProc != NULL)
214         {
215                 SpinRelease(ProcStructLock);
216                 elog(ERROR, "ProcInit: you already exist");
217                 return;
218         }
219
220         /* try to get a proc from the free list first */
221
222         myOffset = ProcGlobal->freeProcs;
223
224         if (myOffset != INVALID_OFFSET)
225         {
226                 MyProc = (PROC *) MAKE_PTR(myOffset);
227                 ProcGlobal->freeProcs = MyProc->links.next;
228         }
229         else
230         {
231
232                 /*
233                  * have to allocate one.  We can't use the normal shmem index
234                  * table mechanism because the proc structure is stored by PID
235                  * instead of by a global name (need to look it up by PID when we
236                  * cleanup dead processes).
237                  */
238
239                 MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
240                 if (!MyProc)
241                 {
242                         SpinRelease(ProcStructLock);
243                         elog(FATAL, "cannot create new proc: out of memory");
244                 }
245
246                 /* this cannot be initialized until after the buffer pool */
247                 SHMQueueInit(&(MyProc->lockQueue));
248         }
249
250         /*
251          * zero out the spin lock counts and set the sLocks field for
252          * ProcStructLock to 1 as we have acquired this spinlock above but
253          * didn't record it since we didn't have MyProc until now.
254          */
255         MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
256         MyProc->sLocks[ProcStructLock] = 1;
257
258
259         if (IsUnderPostmaster)
260         {
261                 IPCKey          semKey;
262                 int                     semNum;
263                 int                     semId;
264                 union semun semun;
265
266                 ProcGetNewSemKeyAndNum(&semKey, &semNum);
267
268                 /* Note: because of the pre-allocation done in InitProcGlobal,
269                  * this call should always attach to an existing semaphore.
270                  * It will (try to) create a new group of semaphores only if
271                  * the postmaster tries to start more backends than it said it would.
272                  */
273                 semId = IpcSemaphoreCreate(semKey,
274                                                                    PROC_NSEMS_PER_SET,
275                                                                    IPCProtection,
276                                                                    IpcSemaphoreDefaultStartValue,
277                                                                    0,
278                                                                    &semstat);
279
280                 /*
281                  * we might be reusing a semaphore that belongs to a dead backend.
282                  * So be careful and reinitialize its value here.
283                  */
284                 semun.val = IpcSemaphoreDefaultStartValue;
285                 semctl(semId, semNum, SETVAL, semun);
286
287                 IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
288                 MyProc->sem.semId = semId;
289                 MyProc->sem.semNum = semNum;
290                 MyProc->sem.semKey = semKey;
291         }
292         else
293                 MyProc->sem.semId = -1;
294
295         /* ----------------------
296          * Release the lock.
297          * ----------------------
298          */
299         SpinRelease(ProcStructLock);
300
301         MyProc->pid = MyProcPid;
302         MyProc->xid = InvalidTransactionId;
303 #ifdef LowLevelLocking
304         MyProc->xmin = InvalidTransactionId;
305 #endif
306
307         /* ----------------
308          * Start keeping spin lock stats from here on.  Any botch before
309          * this initialization is forever botched
310          * ----------------
311          */
312         MemSet(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));
313
314         /* -------------------------
315          * Install ourselves in the shmem index table.  The name to
316          * use is determined by the OS-assigned process id.  That
317          * allows the cleanup process to find us after any untimely
318          * exit.
319          * -------------------------
320          */
321         location = MAKE_OFFSET(MyProc);
322         if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
323                 elog(FATAL, "InitProc: ShmemPID table broken");
324
325         MyProc->errType = NO_ERROR;
326         SHMQueueElemInit(&(MyProc->links));
327
328         on_shmem_exit(ProcKill, (caddr_t) MyProcPid);
329
330         ProcInitialized = TRUE;
331 }
332
333 /*
334  * ProcReleaseLocks() -- release all locks associated with this process
335  *
336  */
337 void
338 ProcReleaseLocks()
339 {
340         if (!MyProc)
341                 return;
342         LockReleaseAll(1, &MyProc->lockQueue);
343 }
344
345 /*
346  * ProcRemove -
347  *        used by the postmaster to clean up the global tables. This also frees
348  *        up the semaphore used for the lmgr of the process. (We have to do
349  *        this is the postmaster instead of doing a IpcSemaphoreKill on exiting
350  *        the process because the semaphore set is shared among backends and
351  *        we don't want to remove other's semaphores on exit.)
352  */
353 bool
354 ProcRemove(int pid)
355 {
356         SHMEM_OFFSET location;
357         PROC       *proc;
358
359         location = INVALID_OFFSET;
360
361         location = ShmemPIDDestroy(pid);
362         if (location == INVALID_OFFSET)
363                 return FALSE;
364         proc = (PROC *) MAKE_PTR(location);
365
366         SpinAcquire(ProcStructLock);
367
368         ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
369
370         proc->links.next = ProcGlobal->freeProcs;
371         ProcGlobal->freeProcs = MAKE_OFFSET(proc);
372
373         SpinRelease(ProcStructLock);
374
375         return TRUE;
376 }
377
378 /*
379  * ProcKill() -- Destroy the per-proc data structure for
380  *              this process. Release any of its held spin locks.
381  */
382 static void
383 ProcKill(int exitStatus, int pid)
384 {
385         PROC       *proc;
386         SHMEM_OFFSET location;
387
388         /* --------------------
389          * If this is a FATAL exit the postmaster will have to kill all the
390          * existing backends and reinitialize shared memory.  So all we don't
391          * need to do anything here.
392          * --------------------
393          */
394         if (exitStatus != 0)
395                 return;
396
397         ShmemPIDLookup(MyProcPid, &location);
398         if (location == INVALID_OFFSET)
399                 return;
400
401         proc = (PROC *) MAKE_PTR(location);
402
403         Assert(proc == MyProc || pid != MyProcPid);
404
405         MyProc = NULL;
406
407         /* ---------------
408          * Assume one lock table.
409          * ---------------
410          */
411         ProcReleaseSpins(proc);
412         LockReleaseAll(DEFAULT_LOCKMETHOD, &proc->lockQueue);
413
414 #ifdef USER_LOCKS
415
416         /*
417          * Assume we have a second lock table.
418          */
419         LockReleaseAll(USER_LOCKMETHOD, &proc->lockQueue);
420 #endif
421
422         /* ----------------
423          * get off the wait queue
424          * ----------------
425          */
426         LockLockTable();
427         if (proc->links.next != INVALID_OFFSET)
428         {
429                 Assert(proc->waitLock->waitProcs.size > 0);
430                 SHMQueueDelete(&(proc->links));
431                 --proc->waitLock->waitProcs.size;
432         }
433         SHMQueueElemInit(&(proc->links));
434         UnlockLockTable();
435
436         return;
437 }
438
439 /*
440  * ProcQueue package: routines for putting processes to sleep
441  *              and  waking them up
442  */
443
444 /*
445  * ProcQueueAlloc -- alloc/attach to a shared memory process queue
446  *
447  * Returns: a pointer to the queue or NULL
448  * Side Effects: Initializes the queue if we allocated one
449  */
450 #ifdef NOT_USED
451 PROC_QUEUE *
452 ProcQueueAlloc(char *name)
453 {
454         bool            found;
455         PROC_QUEUE *queue = (PROC_QUEUE *)
456         ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
457
458         if (!queue)
459                 return NULL;
460         if (!found)
461                 ProcQueueInit(queue);
462         return queue;
463 }
464
465 #endif
466
467 /*
468  * ProcQueueInit -- initialize a shared memory process queue
469  */
470 void
471 ProcQueueInit(PROC_QUEUE *queue)
472 {
473         SHMQueueInit(&(queue->links));
474         queue->size = 0;
475 }
476
477
478
479 /*
480  * ProcSleep -- put a process to sleep
481  *
482  * P() on the semaphore should put us to sleep.  The process
483  * semaphore is cleared by default, so the first time we try
484  * to acquire it, we sleep.
485  *
486  * ASSUME: that no one will fiddle with the queue until after
487  *              we release the spin lock.
488  *
489  * NOTES: The process queue is now a priority queue for locking.
490  */
491 int
492 ProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */
493                   SPINLOCK spinlock,
494                   int token,                    /* lockmode */
495                   int prio,
496                   LOCK *lock,
497                   TransactionId xid)    /* needed by user locks, see below */
498 {
499         int                     i;
500         PROC       *proc;
501         bool            deadlock_checked = false;
502         struct itimerval timeval,
503                                 dummy;
504
505         /*
506          * If the first entries in the waitQueue have a greater priority than
507          * we have, we must be a reader, and they must be a writers, and we
508          * must be here because the current holder is a writer or a reader but
509          * we don't share shared locks if a writer is waiting. We put
510          * ourselves after the writers.  This way, we have a FIFO, but keep
511          * the readers together to give them decent priority, and no one
512          * starves.  Because we group all readers together, a non-empty queue
513          * only has a few possible configurations:
514          *
515          * [readers] [writers] [readers][writers] [writers][readers]
516          * [writers][readers][writers]
517          *
518          * In a full queue, we would have a reader holding a lock, then a writer
519          * gets the lock, then a bunch of readers, made up of readers who
520          * could not share the first readlock because a writer was waiting,
521          * and new readers arriving while the writer had the lock.
522          *
523          */
524         proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
525
526         /* If we are a reader, and they are writers, skip past them */
527         for (i = 0; i < waitQueue->size && proc->prio > prio; i++)
528                 proc = (PROC *) MAKE_PTR(proc->links.prev);
529
530         /* The rest of the queue is FIFO, with readers first, writers last */
531         for (; i < waitQueue->size && proc->prio <= prio; i++)
532                 proc = (PROC *) MAKE_PTR(proc->links.prev);
533
534         MyProc->prio = prio;
535         MyProc->token = token;
536         MyProc->waitLock = lock;
537
538 #ifdef USER_LOCKS
539         /* -------------------
540          * Currently, we only need this for the ProcWakeup routines.
541          * This must be 0 for user lock, so we can't just use the value
542          * from GetCurrentTransactionId().
543          * -------------------
544          */
545         TransactionIdStore(xid, &MyProc->xid);
546 #else
547 #ifndef LowLevelLocking
548         /* -------------------
549          * currently, we only need this for the ProcWakeup routines
550          * -------------------
551          */
552         TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
553 #endif
554 #endif
555
556         /* -------------------
557          * assume that these two operations are atomic (because
558          * of the spinlock).
559          * -------------------
560          */
561         SHMQueueInsertTL(&(proc->links), &(MyProc->links));
562         waitQueue->size++;
563
564         SpinRelease(spinlock);
565
566         /* --------------
567          * We set this so we can wake up periodically and check for a deadlock.
568          * If a deadlock is detected, the handler releases the processes
569          * semaphore and aborts the current transaction.
570          *
571          * Need to zero out struct to set the interval and the micro seconds fields
572          * to 0.
573          * --------------
574          */
575         MemSet(&timeval, 0, sizeof(struct itimerval));
576         timeval.it_value.tv_sec = \
577                 (DeadlockCheckTimer ? DeadlockCheckTimer : DEADLOCK_CHECK_TIMER);
578
579         do
580         {
581                 MyProc->errType = NO_ERROR;             /* reset flag after deadlock check */
582
583                 if (!deadlock_checked)
584                         if (setitimer(ITIMER_REAL, &timeval, &dummy))
585                                 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
586                 deadlock_checked = true;
587
588                 /* --------------
589                  * if someone wakes us between SpinRelease and IpcSemaphoreLock,
590                  * IpcSemaphoreLock will not block.  The wakeup is "saved" by
591                  * the semaphore implementation.
592                  * --------------
593                  */
594                 IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum,
595                                                  IpcExclusiveLock);
596         } while (MyProc->errType == STATUS_NOT_FOUND);          /* sleep after deadlock
597                                                                                                                  * check */
598
599         /* ---------------
600          * We were awoken before a timeout - now disable the timer
601          * ---------------
602          */
603         timeval.it_value.tv_sec = 0;
604         if (setitimer(ITIMER_REAL, &timeval, &dummy))
605                 elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
606
607         /* ----------------
608          * We were assumed to be in a critical section when we went
609          * to sleep.
610          * ----------------
611          */
612         SpinAcquire(spinlock);
613
614 #ifdef LOCK_MGR_DEBUG
615         /* Just to get meaningful debug messages from DumpLocks() */
616         MyProc->waitLock = (LOCK *) NULL;
617 #endif
618
619         return MyProc->errType;
620 }
621
622
623 /*
624  * ProcWakeup -- wake up a process by releasing its private semaphore.
625  *
626  *       remove the process from the wait queue and set its links invalid.
627  *       RETURN: the next process in the wait queue.
628  */
629 static PROC *
630 ProcWakeup(PROC *proc, int errType)
631 {
632         PROC       *retProc;
633
634         /* assume that spinlock has been acquired */
635
636         if (proc->links.prev == INVALID_OFFSET ||
637                 proc->links.next == INVALID_OFFSET)
638                 return (PROC *) NULL;
639
640         retProc = (PROC *) MAKE_PTR(proc->links.prev);
641
642         /* you have to update waitLock->waitProcs.size yourself */
643         SHMQueueDelete(&(proc->links));
644         SHMQueueElemInit(&(proc->links));
645
646         proc->errType = errType;
647
648         IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
649
650         return retProc;
651 }
652
653 /*
654  * ProcLockWakeup -- routine for waking up processes when a lock is
655  *              released.
656  */
657 int
658 ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock)
659 {
660         PROC       *proc;
661         int                     count;
662         int                     trace_flag;
663         int                     last_locktype = -1;
664         int                     queue_size = queue->size;
665
666         Assert(queue->size >= 0);
667
668         if (!queue->size)
669                 return STATUS_NOT_FOUND;
670
671         proc = (PROC *) MAKE_PTR(queue->links.prev);
672         count = 0;
673         while ((queue_size--) && (proc))
674         {
675
676                 /*
677                  * This proc will conflict as the previous one did, don't even
678                  * try.
679                  */
680                 if (proc->token == last_locktype)
681                         continue;
682
683                 /*
684                  * This proc conflicts with locks held by others, ignored.
685                  */
686                 if (LockResolveConflicts(lockmethod,
687                                                                  lock,
688                                                                  proc->token,
689                                                                  proc->xid,
690                                                                  (XIDLookupEnt *) NULL) != STATUS_OK)
691                 {
692                         last_locktype = proc->token;
693                         continue;
694                 }
695
696                 /*
697                  * there was a waiting process, grant it the lock before waking it
698                  * up.  This will prevent another process from seizing the lock
699                  * between the time we release the lock master (spinlock) and the
700                  * time that the awoken process begins executing again.
701                  */
702                 GrantLock(lock, proc->token);
703
704                 /*
705                  * ProcWakeup removes proc from the lock waiting process queue and
706                  * returns the next proc in chain.
707                  */
708
709                 count++;
710                 queue->size--;
711                 proc = ProcWakeup(proc, NO_ERROR);
712         }
713
714         Assert(queue->size >= 0);
715
716         if (count)
717                 return STATUS_OK;
718         else
719         {
720                 /* Something is still blocking us.      May have deadlocked. */
721                 trace_flag = (lock->tag.lockmethod == USER_LOCKMETHOD) ? \
722                         TRACE_USERLOCKS : TRACE_LOCKS;
723                 TPRINTF(trace_flag,
724                                 "ProcLockWakeup: lock(%x) can't wake up any process",
725                                 MAKE_OFFSET(lock));
726 #ifdef DEADLOCK_DEBUG
727                 if (pg_options[trace_flag] >= 2)
728                         DumpAllLocks();
729 #endif
730                 return STATUS_NOT_FOUND;
731         }
732 }
733
734 void
735 ProcAddLock(SHM_QUEUE *elem)
736 {
737         SHMQueueInsertTL(&MyProc->lockQueue, elem);
738 }
739
740 /* --------------------
741  * We only get to this routine if we got SIGALRM after DEADLOCK_CHECK_TIMER
742  * while waiting for a lock to be released by some other process.  If we have
743  * a real deadlock, we must also indicate that I'm no longer waiting
744  * on a lock so that other processes don't try to wake me up and screw
745  * up my semaphore.
746  * --------------------
747  */
748 static void
749 HandleDeadLock(int sig)
750 {
751         LOCK       *mywaitlock;
752
753         LockLockTable();
754
755         /* ---------------------
756          * Check to see if we've been awoken by anyone in the interim.
757          *
758          * If we have we can return and resume our transaction -- happy day.
759          * Before we are awoken the process releasing the lock grants it to
760          * us so we know that we don't have to wait anymore.
761          *
762          * Damn these names are LONG! -mer
763          * ---------------------
764          */
765         if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
766                 IpcSemaphoreDefaultStartValue)
767         {
768                 UnlockLockTable();
769                 return;
770         }
771
772         /*
773          * you would think this would be unnecessary, but...
774          *
775          * this also means we've been removed already.  in some ports (e.g.,
776          * sparc and aix) the semop(2) implementation is such that we can
777          * actually end up in this handler after someone has removed us from
778          * the queue and bopped the semaphore *but the test above fails to
779          * detect the semaphore update* (presumably something weird having to
780          * do with the order in which the semaphore wakeup signal and SIGALRM
781          * get handled).
782          */
783         if (MyProc->links.prev == INVALID_OFFSET ||
784                 MyProc->links.next == INVALID_OFFSET)
785         {
786                 UnlockLockTable();
787                 return;
788         }
789
790 #ifdef DEADLOCK_DEBUG
791         DumpAllLocks();
792 #endif
793
794         if (!DeadLockCheck(&(MyProc->lockQueue), MyProc->waitLock, true))
795         {
796                 UnlockLockTable();
797                 MyProc->errType = STATUS_NOT_FOUND;
798                 return;
799         }
800
801         mywaitlock = MyProc->waitLock;
802
803         /* ------------------------
804          * Get this process off the lock's wait queue
805          * ------------------------
806          */
807         Assert(mywaitlock->waitProcs.size > 0);
808         --mywaitlock->waitProcs.size;
809         SHMQueueDelete(&(MyProc->links));
810         SHMQueueElemInit(&(MyProc->links));
811
812         /* ------------------
813          * Unlock my semaphore so that the count is right for next time.
814          * I was awoken by a signal, not by someone unlocking my semaphore.
815          * ------------------
816          */
817         IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum,
818                                            IpcExclusiveLock);
819
820         /* -------------
821          * Set MyProc->errType to STATUS_ERROR so that we abort after
822          * returning from this handler.
823          * -------------
824          */
825         MyProc->errType = STATUS_ERROR;
826
827         /*
828          * if this doesn't follow the IpcSemaphoreUnlock then we get lock
829          * table corruption ("LockReplace: xid table corrupted") due to race
830          * conditions.  i don't claim to understand this...
831          */
832         UnlockLockTable();
833
834         elog(NOTICE, "Deadlock detected -- See the lock(l) manual page for a possible cause.");
835         return;
836 }
837
838 void
839 ProcReleaseSpins(PROC *proc)
840 {
841         int                     i;
842
843         if (!proc)
844                 proc = MyProc;
845
846         if (!proc)
847                 return;
848         for (i = 0; i < (int) MAX_SPINS; i++)
849         {
850                 if (proc->sLocks[i])
851                 {
852                         Assert(proc->sLocks[i] == 1);
853                         SpinRelease(i);
854                 }
855         }
856 }
857
858 /*****************************************************************************
859  *
860  *****************************************************************************/
861
862 /*
863  * ProcGetNewSemKeyAndNum -
864  *        scan the free semaphore bitmap and allocate a single semaphore from
865  *        a semaphore set. (If the semaphore set doesn't exist yet,
866  *        IpcSemaphoreCreate will create it. Otherwise, we use the existing
867  *        semaphore set.)
868  */
869 static void
870 ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
871 {
872         int                     i;
873         int32      *freeSemMap = ProcGlobal->freeSemMap;
874         int32           fullmask = (1 << (PROC_NSEMS_PER_SET+1)) - 1;
875
876         /*
877          * we hold ProcStructLock when entering this routine. We scan through
878          * the bitmap to look for a free semaphore.
879          */
880
881         for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
882         {
883                 int                     mask = 1;
884                 int                     j;
885
886                 if (freeSemMap[i] == fullmask)
887                         continue;                       /* this set is fully allocated */
888
889                 for (j = 0; j < PROC_NSEMS_PER_SET; j++)
890                 {
891                         if ((freeSemMap[i] & mask) == 0)
892                         {
893
894                                 /*
895                                  * a free semaphore found. Mark it as allocated.
896                                  * Also set the bit indicating whole set is allocated.
897                                  */
898                                 freeSemMap[i] |= mask + (1 << PROC_NSEMS_PER_SET);
899
900                                 *key = ProcGlobal->currKey + i;
901                                 *semNum = j;
902                                 return;
903                         }
904                         mask <<= 1;
905                 }
906         }
907
908         /* if we reach here, all the semaphores are in use. */
909         elog(ERROR, "InitProc: cannot allocate a free semaphore");
910 }
911
912 /*
913  * ProcFreeSem -
914  *        free up our semaphore in the semaphore set.
915  */
916 static void
917 ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
918 {
919         int                     mask;
920         int                     i;
921         int32      *freeSemMap = ProcGlobal->freeSemMap;
922
923         i = semKey - ProcGlobal->currKey;
924         mask = ~(1 << semNum);
925         freeSemMap[i] &= mask;
926
927         /* Formerly we'd release a semaphore set if it was now completely unused,
928          * but now we keep the semaphores to ensure we won't run out when
929          * starting new backends --- cf. InitProcGlobal.  Note that the
930          * PROC_NSEMS_PER_SET+1'st bit of the freeSemMap entry remains set to
931          * indicate it is still allocated; ProcFreeAllSemaphores() needs that.
932          */
933 }
934
935 /*
936  * ProcFreeAllSemaphores -
937  *        called at shmem_exit time, ie when exiting the postmaster or
938  *        destroying shared state for a failed set of backends.
939  *        Free up all the semaphores allocated to the lmgrs of the backends.
940  */
941 static void
942 ProcFreeAllSemaphores()
943 {
944         int                     i;
945         int32      *freeSemMap = ProcGlobal->freeSemMap;
946
947         for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
948         {
949                 if (freeSemMap[i] != 0)
950                         IpcSemaphoreKill(ProcGlobal->currKey + i);
951         }
952 }