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.123 2002/07/18 23:06:20 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 LWLockId masterLock = lockMethodTable->masterLock;
507 PROC_QUEUE *waitQueue = &(lock->waitProcs);
508 int myHeldLocks = MyProc->heldLocks;
509 bool early_deadlock = false;
514 * Determine where to add myself in the wait queue.
516 * Normally I should go at the end of the queue. However, if I already
517 * hold locks that conflict with the request of any previous waiter,
518 * put myself in the queue just in front of the first such waiter.
519 * This is not a necessary step, since deadlock detection would move
520 * me to before that waiter anyway; but it's relatively cheap to
521 * detect such a conflict immediately, and avoid delaying till
524 * Special case: if I find I should go in front of some waiter, check to
525 * see if I conflict with already-held locks or the requests before
526 * that waiter. If not, then just grant myself the requested lock
527 * immediately. This is the same as the test for immediate grant in
528 * LockAcquire, except we are only considering the part of the wait
529 * queue before my insertion point.
531 if (myHeldLocks != 0)
533 int aheadRequests = 0;
535 proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);
536 for (i = 0; i < waitQueue->size; i++)
538 /* Must he wait for me? */
539 if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
541 /* Must I wait for him ? */
542 if (lockMethodTable->conflictTab[lockmode] & proc->heldLocks)
545 * Yes, so we have a deadlock. Easiest way to clean
546 * up correctly is to call RemoveFromWaitQueue(), but
547 * we can't do that until we are *on* the wait queue.
548 * So, set a flag to check below, and break out of
551 early_deadlock = true;
554 /* I must go before this waiter. Check special case. */
555 if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
556 LockCheckConflicts(lockMethodTable,
563 /* Skip the wait and just grant myself the lock. */
564 GrantLock(lock, holder, lockmode);
567 /* Break out of loop to put myself before him */
570 /* Nope, so advance to next waiter */
571 aheadRequests |= (1 << proc->waitLockMode);
572 proc = (PGPROC *) MAKE_PTR(proc->links.next);
576 * If we fall out of loop normally, proc points to waitQueue head,
577 * so we will insert at tail of queue as desired.
582 /* I hold no locks, so I can't push in front of anyone. */
583 proc = (PGPROC *) &(waitQueue->links);
587 * Insert self into queue, ahead of the given proc (or at tail of
590 SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
593 lock->waitMask |= (1 << lockmode);
595 /* Set up wait information in PGPROC object, too */
596 MyProc->waitLock = lock;
597 MyProc->waitHolder = holder;
598 MyProc->waitLockMode = lockmode;
600 MyProc->errType = STATUS_OK; /* initialize result for success */
603 * If we detected deadlock, give up without waiting. This must agree
604 * with CheckDeadLock's recovery code, except that we shouldn't
605 * release the semaphore since we haven't tried to lock it yet.
609 RemoveFromWaitQueue(MyProc);
610 MyProc->errType = STATUS_ERROR;
614 /* mark that we are waiting for a lock */
615 waitingForLock = true;
618 * Release the locktable's masterLock.
620 * NOTE: this may also cause us to exit critical-section state, possibly
621 * allowing a cancel/die interrupt to be accepted. This is OK because
622 * we have recorded the fact that we are waiting for a lock, and so
623 * LockWaitCancel will clean up if cancel/die happens.
625 LWLockRelease(masterLock);
628 * Set timer so we can wake up after awhile and check for a deadlock.
629 * If a deadlock is detected, the handler releases the process's
630 * semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
631 * know that we must report failure rather than success.
633 * By delaying the check until we've waited for a bit, we can avoid
634 * running the rather expensive deadlock-check code in most cases.
636 if (!enable_sig_alarm(DeadlockTimeout, false))
637 elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
640 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
641 * PGSemaphoreLock will not block. The wakeup is "saved" by the
642 * semaphore implementation. Note also that if CheckDeadLock is
643 * invoked but does not detect a deadlock, PGSemaphoreLock() will
644 * continue to wait. There used to be a loop here, but it was useless
647 * We pass interruptOK = true, which eliminates a window in which
648 * cancel/die interrupts would be held off undesirably. This is a
649 * promise that we don't mind losing control to a cancel/die interrupt
650 * here. We don't, because we have no state-change work to do after
651 * being granted the lock (the grantor did it all).
653 PGSemaphoreLock(&MyProc->sem, true);
656 * Disable the timer, if it's still running
658 if (!disable_sig_alarm(false))
659 elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
662 * Now there is nothing for LockWaitCancel to do.
664 waitingForLock = false;
667 * Re-acquire the locktable's masterLock.
669 LWLockAcquire(masterLock, LW_EXCLUSIVE);
672 * We don't have to do anything else, because the awaker did all the
673 * necessary update of the lock table and MyProc.
675 return MyProc->errType;
680 * ProcWakeup -- wake up a process by releasing its private semaphore.
682 * Also remove the process from the wait queue and set its links invalid.
683 * RETURN: the next process in the wait queue.
685 * XXX: presently, this code is only used for the "success" case, and only
686 * works correctly for that case. To clean up in failure case, would need
687 * to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
690 ProcWakeup(PGPROC *proc, int errType)
694 /* assume that masterLock has been acquired */
696 /* Proc should be sleeping ... */
697 if (proc->links.prev == INVALID_OFFSET ||
698 proc->links.next == INVALID_OFFSET)
699 return (PGPROC *) NULL;
701 /* Save next process before we zap the list link */
702 retProc = (PGPROC *) MAKE_PTR(proc->links.next);
704 /* Remove process from wait queue */
705 SHMQueueDelete(&(proc->links));
706 (proc->waitLock->waitProcs.size)--;
708 /* Clean up process' state and pass it the ok/fail signal */
709 proc->waitLock = NULL;
710 proc->waitHolder = NULL;
711 proc->errType = errType;
714 PGSemaphoreUnlock(&proc->sem);
720 * ProcLockWakeup -- routine for waking up processes when a lock is
721 * released (or a prior waiter is aborted). Scan all waiters
722 * for lock, waken any that are no longer blocked.
725 ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
727 PROC_QUEUE *waitQueue = &(lock->waitProcs);
728 int queue_size = waitQueue->size;
730 int aheadRequests = 0;
732 Assert(queue_size >= 0);
737 proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);
739 while (queue_size-- > 0)
741 LOCKMODE lockmode = proc->waitLockMode;
744 * Waken if (a) doesn't conflict with requests of earlier waiters,
745 * and (b) doesn't conflict with already-held locks.
747 if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
748 LockCheckConflicts(lockMethodTable,
756 GrantLock(lock, proc->waitHolder, lockmode);
757 proc = ProcWakeup(proc, STATUS_OK);
760 * ProcWakeup removes proc from the lock's waiting process
761 * queue and returns the next proc in chain; don't use proc's
762 * next-link, because it's been cleared.
768 * Cannot wake this guy. Remember his request for later
771 aheadRequests |= (1 << lockmode);
772 proc = (PGPROC *) MAKE_PTR(proc->links.next);
776 Assert(waitQueue->size >= 0);
779 /* --------------------
780 * We only get to this routine if we got SIGALRM after DeadlockTimeout
781 * while waiting for a lock to be released by some other process. Look
782 * to see if there's a deadlock; if not, just return and continue waiting.
783 * If we have a real deadlock, remove ourselves from the lock's wait queue
784 * and signal an error to ProcSleep.
785 * --------------------
790 int save_errno = errno;
793 * Acquire locktable lock. Note that the SIGALRM interrupt had better
794 * not be enabled anywhere that this process itself holds the
795 * locktable lock, else this will wait forever. Also note that
796 * LWLockAcquire creates a critical section, so that this routine
797 * cannot be interrupted by cancel/die interrupts.
799 LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
802 * Check to see if we've been awoken by anyone in the interim.
804 * If we have we can return and resume our transaction -- happy day.
805 * Before we are awoken the process releasing the lock grants it to us
806 * so we know that we don't have to wait anymore.
808 * We check by looking to see if we've been unlinked from the wait queue.
809 * This is quicker than checking our semaphore's state, since no
810 * kernel call is needed, and it is safe because we hold the locktable
814 if (MyProc->links.prev == INVALID_OFFSET ||
815 MyProc->links.next == INVALID_OFFSET)
817 LWLockRelease(LockMgrLock);
827 if (!DeadLockCheck(MyProc))
829 /* No deadlock, so keep waiting */
830 LWLockRelease(LockMgrLock);
836 * Oops. We have a deadlock.
838 * Get this process out of wait state.
840 RemoveFromWaitQueue(MyProc);
843 * Set MyProc->errType to STATUS_ERROR so that ProcSleep will report
844 * an error after we return from this signal handler.
846 MyProc->errType = STATUS_ERROR;
849 * Unlock my semaphore so that the interrupted ProcSleep() call can
852 PGSemaphoreUnlock(&MyProc->sem);
855 * We're done here. Transaction abort caused by the error that
856 * ProcSleep will raise will cause any other locks we hold to be
857 * released, thus allowing other processes to wake up; we don't need
858 * to do that here. NOTE: an exception is that releasing locks we hold
859 * doesn't consider the possibility of waiters that were blocked
860 * behind us on the lock we just failed to get, and might now be
861 * wakable because we're not in front of them anymore. However,
862 * RemoveFromWaitQueue took care of waking up any such processes.
864 LWLockRelease(LockMgrLock);
870 * ProcWaitForSignal - wait for a signal from another backend.
872 * This can share the semaphore normally used for waiting for locks,
873 * since a backend could never be waiting for a lock and a signal at
874 * the same time. As with locks, it's OK if the signal arrives just
875 * before we actually reach the waiting state.
878 ProcWaitForSignal(void)
880 waitingForSignal = true;
881 PGSemaphoreLock(&MyProc->sem, true);
882 waitingForSignal = false;
886 * ProcCancelWaitForSignal - clean up an aborted wait for signal
888 * We need this in case the signal arrived after we aborted waiting,
889 * or if it arrived but we never reached ProcWaitForSignal() at all.
890 * Caller should call this after resetting the signal request status.
893 ProcCancelWaitForSignal(void)
895 PGSemaphoreReset(&MyProc->sem);
896 waitingForSignal = false;
900 * ProcSendSignal - send a signal to a backend identified by BackendId
903 ProcSendSignal(BackendId procId)
905 PGPROC *proc = BackendIdGetProc(procId);
908 PGSemaphoreUnlock(&proc->sem);
912 /*****************************************************************************
913 * SIGALRM interrupt support
915 * Maybe these should be in pqsignal.c?
916 *****************************************************************************/
919 * Enable the SIGALRM interrupt to fire after the specified delay
921 * Delay is given in milliseconds. Caller should be sure a SIGALRM
922 * signal handler is installed before this is called.
924 * This code properly handles multiple alarms when the statement_timeout
925 * alarm is specified first.
927 * Returns TRUE if okay, FALSE on failure.
930 enable_sig_alarm(int delayms, bool is_statement_timeout)
933 struct itimerval timeval, remaining;
935 bigtime_t time_interval, remaining;
938 /* Don't set timer if the statement timeout scheduled before next alarm. */
939 if (alarm_is_statement_timeout &&
940 !is_statement_timeout &&
941 RemainingStatementTimeout <= delayms)
945 MemSet(&timeval, 0, sizeof(struct itimerval));
946 timeval.it_value.tv_sec = delayms / 1000;
947 timeval.it_value.tv_usec = (delayms % 1000) * 1000;
948 if (setitimer(ITIMER_REAL, &timeval, &remaining))
951 /* BeOS doesn't have setitimer, but has set_alarm */
952 time_interval = delayms * 1000; /* usecs */
953 if ((remaining = set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM)) < 0)
957 if (is_statement_timeout)
958 RemainingStatementTimeout = StatementTimeout;
961 /* Switching to non-statement-timeout alarm, get remaining time */
962 if (alarm_is_statement_timeout)
965 /* We lose precision here because we convert to milliseconds */
966 RemainingStatementTimeout = remaining.it_value.tv_sec * 1000 +
967 remaining.it_value.tv_usec / 1000;
969 RemainingStatementTimeout = remaining / 1000;
971 /* Rounding could cause a zero */
972 if (RemainingStatementTimeout == 0)
973 RemainingStatementTimeout = 1;
976 if (RemainingStatementTimeout)
978 /* Remaining timeout alarm < delayms? */
979 if (RemainingStatementTimeout <= delayms)
981 /* reinstall statement timeout alarm */
982 alarm_is_statement_timeout = true;
984 remaining.it_value.tv_sec = RemainingStatementTimeout / 1000;
985 remaining.it_value.tv_usec = (RemainingStatementTimeout % 1000) * 1000;
986 if (setitimer(ITIMER_REAL, &remaining, &timeval))
991 remaining = RemainingStatementTimeout * 1000;
992 if ((timeval = set_alarm(remaining, B_ONE_SHOT_RELATIVE_ALARM)) < 0)
999 RemainingStatementTimeout -= delayms;
1003 if (is_statement_timeout)
1004 alarm_is_statement_timeout = true;
1006 alarm_is_statement_timeout = false;
1012 * Cancel the SIGALRM timer.
1014 * This is also called if the timer has fired to reschedule
1015 * the statement_timeout timer.
1017 * Returns TRUE if okay, FALSE on failure.
1020 disable_sig_alarm(bool is_statement_timeout)
1023 struct itimerval timeval, remaining;
1024 MemSet(&timeval, 0, sizeof(struct itimerval));
1026 bigtime_t time_interval = 0;
1029 if (!is_statement_timeout && RemainingStatementTimeout)
1032 /* turn off timer and get remaining time, if any */
1033 if (setitimer(ITIMER_REAL, &timeval, &remaining))
1035 /* Add remaining time back because the timer didn't complete */
1036 RemainingStatementTimeout += remaining.it_value.tv_sec * 1000 +
1037 remaining.it_value.tv_usec / 1000;
1038 /* Prepare to set timer */
1039 timeval.it_value.tv_sec = RemainingStatementTimeout / 1000;
1040 timeval.it_value.tv_usec = (RemainingStatementTimeout % 1000) * 1000;
1042 /* BeOS doesn't have setitimer, but has set_alarm */
1043 if ((time_interval = set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM)) < 0)
1045 RemainingStatementTimeout += time_interval / 1000;
1046 time_interval = RemainingStatementTimeout * 1000;
1048 /* Restore remaining statement timeout value */
1049 alarm_is_statement_timeout = true;
1052 * Optimization: is_statement_timeout && RemainingStatementTimeout == 0
1053 * does nothing. This is for cases where no timeout was set.
1055 if (!is_statement_timeout || RemainingStatementTimeout)
1058 if (setitimer(ITIMER_REAL, &timeval, &remaining))
1063 if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
1068 if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
1074 if (is_statement_timeout)
1075 RemainingStatementTimeout = 0;
1082 * Call alarm handler, either StatementCancel or Deadlock checker.
1085 handle_sig_alarm(SIGNAL_ARGS)
1087 if (alarm_is_statement_timeout)
1089 RemainingStatementTimeout = 0;
1090 alarm_is_statement_timeout = false;
1091 kill(MyProcPid, SIGINT);
1096 /* Reactivate any statement_timeout alarm. */
1097 disable_sig_alarm(false);