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