1 /*-------------------------------------------------------------------------
4 * routines to manage per-process shared memory data structure
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.122 2002/07/13 01:02:14 momjian Exp $
13 *-------------------------------------------------------------------------
17 * ProcSleep(), ProcWakeup(),
18 * ProcQueueAlloc() -- create a shm queue for sleeping processes
19 * ProcQueueInit() -- create a queue without allocing memory
21 * Locking and waiting for buffers can cause the backend to be
22 * put to sleep. Whoever releases the lock, etc. wakes the
23 * process up again (and gives it an error code so it knows
24 * whether it was awoken on an error condition).
28 * ProcReleaseLocks -- frees the locks associated with current transaction
30 * ProcKill -- destroys the shared memory state (and locks)
31 * associated with the process.
33 * 5/15/91 -- removed the buffer pool based lock chain in favor
34 * of a shared memory lock chain. The write-protection is
35 * more expensive if the lock chain is in the buffer pool.
36 * The only reason I kept the lock chain in the buffer pool
37 * in the first place was to allow the lock table to grow larger
38 * than available shared memory and that isn't going to work
39 * without a lot of unimplemented support anyway.
48 #include "miscadmin.h"
49 #include "access/xact.h"
50 #include "storage/ipc.h"
51 #include "storage/proc.h"
52 #include "storage/sinval.h"
53 #include "storage/spin.h"
55 int DeadlockTimeout = 1000;
56 int StatementTimeout = 0;
57 int RemainingStatementTimeout = 0;
58 bool alarm_is_statement_timeout = false;
60 PGPROC *MyProc = NULL;
63 * This spinlock protects the freelist of recycled PGPROC structures.
64 * We cannot use an LWLock because the LWLock manager depends on already
65 * having a PGPROC and a wait semaphore! But these structures are touched
66 * relatively infrequently (only at backend startup or shutdown) and not for
67 * very long, so a spinlock is okay.
69 static slock_t *ProcStructLock = NULL;
71 static PROC_HDR *ProcGlobal = NULL;
73 static PGPROC *DummyProc = NULL;
75 static bool waitingForLock = false;
76 static bool waitingForSignal = false;
78 static void ProcKill(void);
79 static void DummyProcKill(void);
83 * Report number of semaphores needed by InitProcGlobal.
86 ProcGlobalSemas(int maxBackends)
88 /* We need a sema per backend, plus one for the dummy process. */
89 return maxBackends + 1;
94 * initializes the global process table. We put it here so that
95 * the postmaster can do this initialization.
97 * We also create all the per-process semaphores we will need to support
98 * the requested number of backends. We used to allocate semaphores
99 * only when backends were actually started up, but that is bad because
100 * it lets Postgres fail under load --- a lot of Unix systems are
101 * (mis)configured with small limits on the number of semaphores, and
102 * running out when trying to start another backend is a common failure.
103 * So, now we grab enough semaphores to support the desired max number
104 * of backends immediately at initialization --- if the sysadmin has set
105 * MaxBackends higher than his kernel will support, he'll find out sooner
108 * Another reason for creating semaphores here is that the semaphore
109 * implementation typically requires us to create semaphores in the
110 * postmaster, not in backends.
113 InitProcGlobal(int maxBackends)
117 /* Create or attach to the ProcGlobal shared structure */
118 ProcGlobal = (PROC_HDR *)
119 ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
121 /* --------------------
122 * We're the first - initialize.
123 * XXX if found should ever be true, it is a sign of impending doom ...
124 * ought to complain if so?
125 * --------------------
131 ProcGlobal->freeProcs = INVALID_OFFSET;
134 * Pre-create the PGPROC structures and create a semaphore for each.
136 for (i = 0; i < maxBackends; i++)
140 proc = (PGPROC *) ShmemAlloc(sizeof(PGPROC));
142 elog(FATAL, "cannot create new proc: out of memory");
143 MemSet(proc, 0, sizeof(PGPROC));
144 PGSemaphoreCreate(&proc->sem);
145 proc->links.next = ProcGlobal->freeProcs;
146 ProcGlobal->freeProcs = MAKE_OFFSET(proc);
150 * Pre-allocate a PGPROC structure for dummy (checkpoint) processes,
151 * too. This does not get linked into the freeProcs list.
153 DummyProc = (PGPROC *) ShmemAlloc(sizeof(PGPROC));
155 elog(FATAL, "cannot create new proc: out of memory");
156 MemSet(DummyProc, 0, sizeof(PGPROC));
157 DummyProc->pid = 0; /* marks DummyProc as not in use */
158 PGSemaphoreCreate(&DummyProc->sem);
160 /* Create ProcStructLock spinlock, too */
161 ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
162 SpinLockInit(ProcStructLock);
167 * InitProcess -- initialize a per-process data structure for this backend
172 SHMEM_OFFSET myOffset;
173 /* use volatile pointer to prevent code rearrangement */
174 volatile PROC_HDR *procglobal = ProcGlobal;
177 * ProcGlobal should be set by a previous call to InitProcGlobal (if
178 * we are a backend, we inherit this by fork() from the postmaster).
180 if (procglobal == NULL)
181 elog(PANIC, "InitProcess: Proc Header uninitialized");
184 elog(ERROR, "InitProcess: you already exist");
187 * Try to get a proc struct from the free list. If this fails,
188 * we must be out of PGPROC structures (not to mention semaphores).
190 SpinLockAcquire(ProcStructLock);
192 myOffset = procglobal->freeProcs;
194 if (myOffset != INVALID_OFFSET)
196 MyProc = (PGPROC *) MAKE_PTR(myOffset);
197 procglobal->freeProcs = MyProc->links.next;
198 SpinLockRelease(ProcStructLock);
203 * If we reach here, all the PGPROCs are in use. This is one of
204 * the possible places to detect "too many backends", so give the
205 * standard error message.
207 SpinLockRelease(ProcStructLock);
208 elog(FATAL, "Sorry, too many clients already");
212 * Initialize all fields of MyProc, except for the semaphore which
213 * was prepared for us by InitProcGlobal.
215 SHMQueueElemInit(&(MyProc->links));
216 MyProc->errType = STATUS_OK;
217 MyProc->xid = InvalidTransactionId;
218 MyProc->xmin = InvalidTransactionId;
219 MyProc->pid = MyProcPid;
220 MyProc->databaseId = MyDatabaseId;
221 MyProc->logRec.xrecoff = 0;
222 MyProc->lwWaiting = false;
223 MyProc->lwExclusive = false;
224 MyProc->lwWaitLink = NULL;
225 MyProc->waitLock = NULL;
226 MyProc->waitHolder = NULL;
227 SHMQueueInit(&(MyProc->procHolders));
230 * Arrange to clean up at backend exit.
232 on_shmem_exit(ProcKill, 0);
235 * We might be reusing a semaphore that belonged to a failed process.
236 * So be careful and reinitialize its value here.
238 PGSemaphoreReset(&MyProc->sem);
241 * Now that we have a PGPROC, we could try to acquire locks, so
242 * initialize the deadlock checker.
244 InitDeadLockChecking();
248 * InitDummyProcess -- create a dummy per-process data structure
250 * This is called by checkpoint processes so that they will have a MyProc
251 * value that's real enough to let them wait for LWLocks. The PGPROC and
252 * sema that are assigned are the extra ones created during InitProcGlobal.
255 InitDummyProcess(void)
258 * ProcGlobal should be set by a previous call to InitProcGlobal (we
259 * inherit this by fork() from the postmaster).
261 if (ProcGlobal == NULL || DummyProc == NULL)
262 elog(PANIC, "InitDummyProcess: Proc Header uninitialized");
265 elog(ERROR, "InitDummyProcess: you already exist");
268 * DummyProc should not presently be in use by anyone else
270 if (DummyProc->pid != 0)
271 elog(FATAL, "InitDummyProcess: DummyProc is in use by PID %d",
276 * Initialize all fields of MyProc, except MyProc->sem which was set
277 * up by InitProcGlobal.
279 MyProc->pid = MyProcPid; /* marks DummyProc as in use by me */
280 SHMQueueElemInit(&(MyProc->links));
281 MyProc->errType = STATUS_OK;
282 MyProc->xid = InvalidTransactionId;
283 MyProc->xmin = InvalidTransactionId;
284 MyProc->databaseId = MyDatabaseId;
285 MyProc->logRec.xrecoff = 0;
286 MyProc->lwWaiting = false;
287 MyProc->lwExclusive = false;
288 MyProc->lwWaitLink = NULL;
289 MyProc->waitLock = NULL;
290 MyProc->waitHolder = NULL;
291 SHMQueueInit(&(MyProc->procHolders));
294 * Arrange to clean up at process exit.
296 on_shmem_exit(DummyProcKill, 0);
299 * We might be reusing a semaphore that belonged to a failed process.
300 * So be careful and reinitialize its value here.
302 PGSemaphoreReset(&MyProc->sem);
306 * Cancel any pending wait for lock, when aborting a transaction.
308 * Returns true if we had been waiting for a lock, else false.
310 * (Normally, this would only happen if we accept a cancel/die
311 * interrupt while waiting; but an elog(ERROR) while waiting is
312 * within the realm of possibility, too.)
317 /* Nothing to do if we weren't waiting for a lock */
321 waitingForLock = false;
323 /* Turn off the deadlock timer, if it's still running (see ProcSleep) */
324 disable_sig_alarm(false);
326 /* Unlink myself from the wait queue, if on it (might not be anymore!) */
327 LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
328 if (MyProc->links.next != INVALID_OFFSET)
329 RemoveFromWaitQueue(MyProc);
330 LWLockRelease(LockMgrLock);
333 * Reset the proc wait semaphore to zero. This is necessary in the
334 * scenario where someone else granted us the lock we wanted before we
335 * were able to remove ourselves from the wait-list. The semaphore
336 * will have been bumped to 1 by the would-be grantor, and since we
337 * are no longer going to wait on the sema, we have to force it back
338 * to zero. Otherwise, our next attempt to wait for a lock will fall
339 * through prematurely.
341 PGSemaphoreReset(&MyProc->sem);
344 * Return true even if we were kicked off the lock before we were able
345 * to remove ourselves.
352 * ProcReleaseLocks() -- release locks associated with current transaction
353 * at transaction commit or abort
355 * At commit, we release only locks tagged with the current transaction's XID,
356 * leaving those marked with XID 0 (ie, session locks) undisturbed. At abort,
357 * we release all locks including XID 0, because we need to clean up after
358 * a failure. This logic will need extension if we ever support nested
361 * Note that user locks are not released in either case.
364 ProcReleaseLocks(bool isCommit)
368 /* If waiting, get off wait queue (should only be needed after error) */
371 LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc,
372 !isCommit, GetCurrentTransactionId());
377 * ProcKill() -- Destroy the per-proc data structure for
378 * this process. Release any of its held LW locks.
383 /* use volatile pointer to prevent code rearrangement */
384 volatile PROC_HDR *procglobal = ProcGlobal;
386 Assert(MyProc != NULL);
388 /* Release any LW locks I am holding */
391 /* Abort any buffer I/O in progress */
394 /* Get off any wait queue I might be on */
397 /* Remove from the standard lock table */
398 LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, true, InvalidTransactionId);
401 /* Remove from the user lock table */
402 LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);
405 SpinLockAcquire(ProcStructLock);
407 /* Return PGPROC structure (and semaphore) to freelist */
408 MyProc->links.next = procglobal->freeProcs;
409 procglobal->freeProcs = MAKE_OFFSET(MyProc);
411 /* PGPROC struct isn't mine anymore */
414 SpinLockRelease(ProcStructLock);
418 * DummyProcKill() -- Cut-down version of ProcKill for dummy (checkpoint)
419 * processes. The PGPROC and sema are not released, only marked
425 Assert(MyProc != NULL && MyProc == DummyProc);
427 /* Release any LW locks I am holding */
430 /* Abort any buffer I/O in progress */
433 /* I can't be on regular lock queues, so needn't check */
435 /* Mark DummyProc no longer in use */
438 /* PGPROC struct isn't mine anymore */
444 * ProcQueue package: routines for putting processes to sleep
449 * ProcQueueAlloc -- alloc/attach to a shared memory process queue
451 * Returns: a pointer to the queue or NULL
452 * Side Effects: Initializes the queue if we allocated one
456 ProcQueueAlloc(char *name)
459 PROC_QUEUE *queue = (PROC_QUEUE *)
460 ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
465 ProcQueueInit(queue);
471 * ProcQueueInit -- initialize a shared memory process queue
474 ProcQueueInit(PROC_QUEUE *queue)
476 SHMQueueInit(&(queue->links));
482 * ProcSleep -- put a process to sleep
484 * Caller must have set MyProc->heldLocks to reflect locks already held
485 * on the lockable object by this process (under all XIDs).
487 * Locktable's masterLock must be held at entry, and will be held
490 * Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock).
492 * ASSUME: that no one will fiddle with the queue until after
493 * we release the masterLock.
495 * NOTES: The process queue is now a priority queue for locking.
497 * P() on the semaphore should put us to sleep. The process
498 * semaphore is normally zero, so when we try to acquire it, we sleep.
501 ProcSleep(LOCKMETHODTABLE *lockMethodTable,
506 LOCKMETHODCTL *lockctl = lockMethodTable->ctl;
507 LWLockId masterLock = lockctl->masterLock;
508 PROC_QUEUE *waitQueue = &(lock->waitProcs);
509 int myHeldLocks = MyProc->heldLocks;
510 bool early_deadlock = false;
515 * Determine where to add myself in the wait queue.
517 * Normally I should go at the end of the queue. However, if I already
518 * hold locks that conflict with the request of any previous waiter,
519 * put myself in the queue just in front of the first such waiter.
520 * This is not a necessary step, since deadlock detection would move
521 * me to before that waiter anyway; but it's relatively cheap to
522 * detect such a conflict immediately, and avoid delaying till
525 * Special case: if I find I should go in front of some waiter, check to
526 * see if I conflict with already-held locks or the requests before
527 * that waiter. If not, then just grant myself the requested lock
528 * immediately. This is the same as the test for immediate grant in
529 * LockAcquire, except we are only considering the part of the wait
530 * queue before my insertion point.
532 if (myHeldLocks != 0)
534 int aheadRequests = 0;
536 proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);
537 for (i = 0; i < waitQueue->size; i++)
539 /* Must he wait for me? */
540 if (lockctl->conflictTab[proc->waitLockMode] & myHeldLocks)
542 /* Must I wait for him ? */
543 if (lockctl->conflictTab[lockmode] & proc->heldLocks)
546 * Yes, so we have a deadlock. Easiest way to clean
547 * up correctly is to call RemoveFromWaitQueue(), but
548 * we can't do that until we are *on* the wait queue.
549 * So, set a flag to check below, and break out of
552 early_deadlock = true;
555 /* I must go before this waiter. Check special case. */
556 if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
557 LockCheckConflicts(lockMethodTable,
564 /* Skip the wait and just grant myself the lock. */
565 GrantLock(lock, holder, lockmode);
568 /* Break out of loop to put myself before him */
571 /* Nope, so advance to next waiter */
572 aheadRequests |= (1 << proc->waitLockMode);
573 proc = (PGPROC *) MAKE_PTR(proc->links.next);
577 * If we fall out of loop normally, proc points to waitQueue head,
578 * so we will insert at tail of queue as desired.
583 /* I hold no locks, so I can't push in front of anyone. */
584 proc = (PGPROC *) &(waitQueue->links);
588 * Insert self into queue, ahead of the given proc (or at tail of
591 SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
594 lock->waitMask |= (1 << lockmode);
596 /* Set up wait information in PGPROC object, too */
597 MyProc->waitLock = lock;
598 MyProc->waitHolder = holder;
599 MyProc->waitLockMode = lockmode;
601 MyProc->errType = STATUS_OK; /* initialize result for success */
604 * If we detected deadlock, give up without waiting. This must agree
605 * with CheckDeadLock's recovery code, except that we shouldn't
606 * release the semaphore since we haven't tried to lock it yet.
610 RemoveFromWaitQueue(MyProc);
611 MyProc->errType = STATUS_ERROR;
615 /* mark that we are waiting for a lock */
616 waitingForLock = true;
619 * Release the locktable's masterLock.
621 * NOTE: this may also cause us to exit critical-section state, possibly
622 * allowing a cancel/die interrupt to be accepted. This is OK because
623 * we have recorded the fact that we are waiting for a lock, and so
624 * LockWaitCancel will clean up if cancel/die happens.
626 LWLockRelease(masterLock);
629 * Set timer so we can wake up after awhile and check for a deadlock.
630 * If a deadlock is detected, the handler releases the process's
631 * semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
632 * know that we must report failure rather than success.
634 * By delaying the check until we've waited for a bit, we can avoid
635 * running the rather expensive deadlock-check code in most cases.
637 if (!enable_sig_alarm(DeadlockTimeout, false))
638 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
641 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
642 * PGSemaphoreLock will not block. The wakeup is "saved" by the
643 * semaphore implementation. Note also that if CheckDeadLock is
644 * invoked but does not detect a deadlock, PGSemaphoreLock() will
645 * continue to wait. There used to be a loop here, but it was useless
648 * We pass interruptOK = true, which eliminates a window in which
649 * cancel/die interrupts would be held off undesirably. This is a
650 * promise that we don't mind losing control to a cancel/die interrupt
651 * here. We don't, because we have no state-change work to do after
652 * being granted the lock (the grantor did it all).
654 PGSemaphoreLock(&MyProc->sem, true);
657 * Disable the timer, if it's still running
659 if (!disable_sig_alarm(false))
660 elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
663 * Now there is nothing for LockWaitCancel to do.
665 waitingForLock = false;
668 * Re-acquire the locktable's masterLock.
670 LWLockAcquire(masterLock, LW_EXCLUSIVE);
673 * We don't have to do anything else, because the awaker did all the
674 * necessary update of the lock table and MyProc.
676 return MyProc->errType;
681 * ProcWakeup -- wake up a process by releasing its private semaphore.
683 * Also remove the process from the wait queue and set its links invalid.
684 * RETURN: the next process in the wait queue.
686 * XXX: presently, this code is only used for the "success" case, and only
687 * works correctly for that case. To clean up in failure case, would need
688 * to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
691 ProcWakeup(PGPROC *proc, int errType)
695 /* assume that masterLock has been acquired */
697 /* Proc should be sleeping ... */
698 if (proc->links.prev == INVALID_OFFSET ||
699 proc->links.next == INVALID_OFFSET)
700 return (PGPROC *) NULL;
702 /* Save next process before we zap the list link */
703 retProc = (PGPROC *) MAKE_PTR(proc->links.next);
705 /* Remove process from wait queue */
706 SHMQueueDelete(&(proc->links));
707 (proc->waitLock->waitProcs.size)--;
709 /* Clean up process' state and pass it the ok/fail signal */
710 proc->waitLock = NULL;
711 proc->waitHolder = NULL;
712 proc->errType = errType;
715 PGSemaphoreUnlock(&proc->sem);
721 * ProcLockWakeup -- routine for waking up processes when a lock is
722 * released (or a prior waiter is aborted). Scan all waiters
723 * for lock, waken any that are no longer blocked.
726 ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
728 LOCKMETHODCTL *lockctl = lockMethodTable->ctl;
729 PROC_QUEUE *waitQueue = &(lock->waitProcs);
730 int queue_size = waitQueue->size;
732 int aheadRequests = 0;
734 Assert(queue_size >= 0);
739 proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);
741 while (queue_size-- > 0)
743 LOCKMODE lockmode = proc->waitLockMode;
746 * Waken if (a) doesn't conflict with requests of earlier waiters,
747 * and (b) doesn't conflict with already-held locks.
749 if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
750 LockCheckConflicts(lockMethodTable,
758 GrantLock(lock, proc->waitHolder, lockmode);
759 proc = ProcWakeup(proc, STATUS_OK);
762 * ProcWakeup removes proc from the lock's waiting process
763 * queue and returns the next proc in chain; don't use proc's
764 * next-link, because it's been cleared.
770 * Cannot wake this guy. Remember his request for later
773 aheadRequests |= (1 << lockmode);
774 proc = (PGPROC *) MAKE_PTR(proc->links.next);
778 Assert(waitQueue->size >= 0);
781 /* --------------------
782 * We only get to this routine if we got SIGALRM after DeadlockTimeout
783 * while waiting for a lock to be released by some other process. Look
784 * to see if there's a deadlock; if not, just return and continue waiting.
785 * If we have a real deadlock, remove ourselves from the lock's wait queue
786 * and signal an error to ProcSleep.
787 * --------------------
792 int save_errno = errno;
795 * Acquire locktable lock. Note that the SIGALRM interrupt had better
796 * not be enabled anywhere that this process itself holds the
797 * locktable lock, else this will wait forever. Also note that
798 * LWLockAcquire creates a critical section, so that this routine
799 * cannot be interrupted by cancel/die interrupts.
801 LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
804 * Check to see if we've been awoken by anyone in the interim.
806 * If we have we can return and resume our transaction -- happy day.
807 * Before we are awoken the process releasing the lock grants it to us
808 * so we know that we don't have to wait anymore.
810 * We check by looking to see if we've been unlinked from the wait queue.
811 * This is quicker than checking our semaphore's state, since no
812 * kernel call is needed, and it is safe because we hold the locktable
816 if (MyProc->links.prev == INVALID_OFFSET ||
817 MyProc->links.next == INVALID_OFFSET)
819 LWLockRelease(LockMgrLock);
829 if (!DeadLockCheck(MyProc))
831 /* No deadlock, so keep waiting */
832 LWLockRelease(LockMgrLock);
838 * Oops. We have a deadlock.
840 * Get this process out of wait state.
842 RemoveFromWaitQueue(MyProc);
845 * Set MyProc->errType to STATUS_ERROR so that ProcSleep will report
846 * an error after we return from this signal handler.
848 MyProc->errType = STATUS_ERROR;
851 * Unlock my semaphore so that the interrupted ProcSleep() call can
854 PGSemaphoreUnlock(&MyProc->sem);
857 * We're done here. Transaction abort caused by the error that
858 * ProcSleep will raise will cause any other locks we hold to be
859 * released, thus allowing other processes to wake up; we don't need
860 * to do that here. NOTE: an exception is that releasing locks we hold
861 * doesn't consider the possibility of waiters that were blocked
862 * behind us on the lock we just failed to get, and might now be
863 * wakable because we're not in front of them anymore. However,
864 * RemoveFromWaitQueue took care of waking up any such processes.
866 LWLockRelease(LockMgrLock);
872 * ProcWaitForSignal - wait for a signal from another backend.
874 * This can share the semaphore normally used for waiting for locks,
875 * since a backend could never be waiting for a lock and a signal at
876 * the same time. As with locks, it's OK if the signal arrives just
877 * before we actually reach the waiting state.
880 ProcWaitForSignal(void)
882 waitingForSignal = true;
883 PGSemaphoreLock(&MyProc->sem, true);
884 waitingForSignal = false;
888 * ProcCancelWaitForSignal - clean up an aborted wait for signal
890 * We need this in case the signal arrived after we aborted waiting,
891 * or if it arrived but we never reached ProcWaitForSignal() at all.
892 * Caller should call this after resetting the signal request status.
895 ProcCancelWaitForSignal(void)
897 PGSemaphoreReset(&MyProc->sem);
898 waitingForSignal = false;
902 * ProcSendSignal - send a signal to a backend identified by BackendId
905 ProcSendSignal(BackendId procId)
907 PGPROC *proc = BackendIdGetProc(procId);
910 PGSemaphoreUnlock(&proc->sem);
914 /*****************************************************************************
915 * SIGALRM interrupt support
917 * Maybe these should be in pqsignal.c?
918 *****************************************************************************/
921 * Enable the SIGALRM interrupt to fire after the specified delay
923 * Delay is given in milliseconds. Caller should be sure a SIGALRM
924 * signal handler is installed before this is called.
926 * This code properly handles multiple alarms when the statement_timeout
927 * alarm is specified first.
929 * Returns TRUE if okay, FALSE on failure.
932 enable_sig_alarm(int delayms, bool is_statement_timeout)
935 struct itimerval timeval, remaining;
937 bigtime_t time_interval, remaining;
940 /* Don't set timer if the statement timeout scheduled before next alarm. */
941 if (alarm_is_statement_timeout &&
942 !is_statement_timeout &&
943 RemainingStatementTimeout <= delayms)
947 MemSet(&timeval, 0, sizeof(struct itimerval));
948 timeval.it_value.tv_sec = delayms / 1000;
949 timeval.it_value.tv_usec = (delayms % 1000) * 1000;
950 if (setitimer(ITIMER_REAL, &timeval, &remaining))
953 /* BeOS doesn't have setitimer, but has set_alarm */
954 time_interval = delayms * 1000; /* usecs */
955 if ((remaining = set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM)) < 0)
959 if (is_statement_timeout)
960 RemainingStatementTimeout = StatementTimeout;
963 /* Switching to non-statement-timeout alarm, get remaining time */
964 if (alarm_is_statement_timeout)
967 /* We lose precision here because we convert to milliseconds */
968 RemainingStatementTimeout = remaining.it_value.tv_sec * 1000 +
969 remaining.it_value.tv_usec / 1000;
971 RemainingStatementTimeout = remaining / 1000;
973 /* Rounding could cause a zero */
974 if (RemainingStatementTimeout == 0)
975 RemainingStatementTimeout = 1;
978 if (RemainingStatementTimeout)
980 /* Remaining timeout alarm < delayms? */
981 if (RemainingStatementTimeout <= delayms)
983 /* reinstall statement timeout alarm */
984 alarm_is_statement_timeout = true;
986 remaining.it_value.tv_sec = RemainingStatementTimeout / 1000;
987 remaining.it_value.tv_usec = (RemainingStatementTimeout % 1000) * 1000;
988 if (setitimer(ITIMER_REAL, &remaining, &timeval))
993 remaining = RemainingStatementTimeout * 1000;
994 if ((timeval = set_alarm(remaining, B_ONE_SHOT_RELATIVE_ALARM)) < 0)
1001 RemainingStatementTimeout -= delayms;
1005 if (is_statement_timeout)
1006 alarm_is_statement_timeout = true;
1008 alarm_is_statement_timeout = false;
1014 * Cancel the SIGALRM timer.
1016 * This is also called if the timer has fired to reschedule
1017 * the statement_timeout timer.
1019 * Returns TRUE if okay, FALSE on failure.
1022 disable_sig_alarm(bool is_statement_timeout)
1025 struct itimerval timeval, remaining;
1026 MemSet(&timeval, 0, sizeof(struct itimerval));
1028 bigtime_t time_interval = 0;
1031 if (!is_statement_timeout && RemainingStatementTimeout)
1034 /* turn off timer and get remaining time, if any */
1035 if (setitimer(ITIMER_REAL, &timeval, &remaining))
1037 /* Add remaining time back because the timer didn't complete */
1038 RemainingStatementTimeout += remaining.it_value.tv_sec * 1000 +
1039 remaining.it_value.tv_usec / 1000;
1040 /* Prepare to set timer */
1041 timeval.it_value.tv_sec = RemainingStatementTimeout / 1000;
1042 timeval.it_value.tv_usec = (RemainingStatementTimeout % 1000) * 1000;
1044 /* BeOS doesn't have setitimer, but has set_alarm */
1045 if ((time_interval = set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM)) < 0)
1047 RemainingStatementTimeout += time_interval / 1000;
1048 time_interval = RemainingStatementTimeout * 1000;
1050 /* Restore remaining statement timeout value */
1051 alarm_is_statement_timeout = true;
1054 * Optimization: is_statement_timeout && RemainingStatementTimeout == 0
1055 * does nothing. This is for cases where no timeout was set.
1057 if (!is_statement_timeout || RemainingStatementTimeout)
1060 if (setitimer(ITIMER_REAL, &timeval, &remaining))
1065 if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
1070 if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
1076 if (is_statement_timeout)
1077 RemainingStatementTimeout = 0;
1084 * Call alarm handler, either StatementCancel or Deadlock checker.
1087 handle_sig_alarm(SIGNAL_ARGS)
1089 if (alarm_is_statement_timeout)
1091 RemainingStatementTimeout = 0;
1092 alarm_is_statement_timeout = false;
1093 kill(MyProcPid, SIGINT);
1098 /* Reactivate any statement_timeout alarm. */
1099 disable_sig_alarm(false);