📄 proc.c
字号:
proc = ProcWakeup(proc, STATUS_OK); /* * ProcWakeup removes proc from the lock's waiting process * queue and returns the next proc in chain; don't use proc's * next-link, because it's been cleared. */ } else { /* * Cannot wake this guy. Remember his request for later * checks. */ aheadRequests |= (1 << lockmode); proc = (PGPROC *) MAKE_PTR(proc->links.next); } } Assert(waitQueue->size >= 0);}/* -------------------- * We only get to this routine if we got SIGALRM after DeadlockTimeout * while waiting for a lock to be released by some other process. Look * to see if there's a deadlock; if not, just return and continue waiting. * If we have a real deadlock, remove ourselves from the lock's wait queue * and signal an error to ProcSleep. * -------------------- */static voidCheckDeadLock(void){ /* * Acquire locktable lock. Note that the deadlock check interrupt had * better not be enabled anywhere that this process itself holds the * locktable lock, else this will wait forever. Also note that * LWLockAcquire creates a critical section, so that this routine * cannot be interrupted by cancel/die interrupts. */ LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); /* * Check to see if we've been awoken by anyone in the interim. * * If we have we can return and resume our transaction -- happy day. * Before we are awoken the process releasing the lock grants it to us * so we know that we don't have to wait anymore. * * We check by looking to see if we've been unlinked from the wait queue. * This is quicker than checking our semaphore's state, since no * kernel call is needed, and it is safe because we hold the locktable * lock. */ if (MyProc->links.prev == INVALID_OFFSET || MyProc->links.next == INVALID_OFFSET) { LWLockRelease(LockMgrLock); return; }#ifdef LOCK_DEBUG if (Debug_deadlocks) DumpAllLocks();#endif if (!DeadLockCheck(MyProc)) { /* No deadlock, so keep waiting */ LWLockRelease(LockMgrLock); return; } /* * Oops. We have a deadlock. * * Get this process out of wait state. */ RemoveFromWaitQueue(MyProc); /* * Set MyProc->errType to STATUS_ERROR so that ProcSleep will report * an error after we return from the signal handler. */ MyProc->errType = STATUS_ERROR; /* * Unlock my semaphore so that the interrupted ProcSleep() call can * finish. */ PGSemaphoreUnlock(&MyProc->sem); /* * We're done here. Transaction abort caused by the error that * ProcSleep will raise will cause any other locks we hold to be * released, thus allowing other processes to wake up; we don't need * to do that here. NOTE: an exception is that releasing locks we hold * doesn't consider the possibility of waiters that were blocked * behind us on the lock we just failed to get, and might now be * wakable because we're not in front of them anymore. However, * RemoveFromWaitQueue took care of waking up any such processes. */ LWLockRelease(LockMgrLock);}/* * ProcWaitForSignal - wait for a signal from another backend. * * This can share the semaphore normally used for waiting for locks, * since a backend could never be waiting for a lock and a signal at * the same time. As with locks, it's OK if the signal arrives just * before we actually reach the waiting state. */voidProcWaitForSignal(void){ waitingForSignal = true; PGSemaphoreLock(&MyProc->sem, true); waitingForSignal = false;}/* * ProcCancelWaitForSignal - clean up an aborted wait for signal * * We need this in case the signal arrived after we aborted waiting, * or if it arrived but we never reached ProcWaitForSignal() at all. * Caller should call this after resetting the signal request status. */voidProcCancelWaitForSignal(void){ PGSemaphoreReset(&MyProc->sem); waitingForSignal = false;}/* * ProcSendSignal - send a signal to a backend identified by BackendId */voidProcSendSignal(BackendId procId){ PGPROC *proc = BackendIdGetProc(procId); if (proc != NULL) PGSemaphoreUnlock(&proc->sem);}/***************************************************************************** * SIGALRM interrupt support * * Maybe these should be in pqsignal.c? *****************************************************************************//* * Enable the SIGALRM interrupt to fire after the specified delay * * Delay is given in milliseconds. Caller should be sure a SIGALRM * signal handler is installed before this is called. * * This code properly handles nesting of deadlock timeout alarms within * statement timeout alarms. * * Returns TRUE if okay, FALSE on failure. */boolenable_sig_alarm(int delayms, bool is_statement_timeout){#ifdef WIN32#warning add Win32 timer#else struct timeval fin_time;#ifndef __BEOS__ struct itimerval timeval;#else bigtime_t time_interval;#endif /* Compute target timeout time if we will need it */ if (is_statement_timeout || statement_timeout_active) { gettimeofday(&fin_time, NULL); fin_time.tv_sec += delayms / 1000; fin_time.tv_usec += (delayms % 1000) * 1000; if (fin_time.tv_usec >= 1000000) { fin_time.tv_sec++; fin_time.tv_usec -= 1000000; } } if (is_statement_timeout) { /* Begin statement-level timeout */ Assert(!deadlock_timeout_active); statement_fin_time = fin_time; statement_timeout_active = true; } else if (statement_timeout_active) { /* * Begin deadlock timeout with statement-level timeout active * * Here, we want to interrupt at the closer of the two timeout times. * If fin_time >= statement_fin_time then we need not touch the * existing timer setting; else set up to interrupt at the * deadlock timeout time. * * NOTE: in this case it is possible that this routine will be * interrupted by the previously-set timer alarm. This is okay * because the signal handler will do only what it should do * according to the state variables. The deadlock checker may get * run earlier than normal, but that does no harm. */ deadlock_timeout_active = true; if (fin_time.tv_sec > statement_fin_time.tv_sec || (fin_time.tv_sec == statement_fin_time.tv_sec && fin_time.tv_usec >= statement_fin_time.tv_usec)) return true; } else { /* Begin deadlock timeout with no statement-level timeout */ deadlock_timeout_active = true; } /* If we reach here, okay to set the timer interrupt */#ifndef __BEOS__ MemSet(&timeval, 0, sizeof(struct itimerval)); timeval.it_value.tv_sec = delayms / 1000; timeval.it_value.tv_usec = (delayms % 1000) * 1000; if (setitimer(ITIMER_REAL, &timeval, NULL)) return false;#else /* BeOS doesn't have setitimer, but has set_alarm */ time_interval = delayms * 1000; /* usecs */ if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0) return false;#endif#endif return true;}/* * Cancel the SIGALRM timer, either for a deadlock timeout or a statement * timeout. If a deadlock timeout is canceled, any active statement timeout * remains in force. * * Returns TRUE if okay, FALSE on failure. */booldisable_sig_alarm(bool is_statement_timeout){#ifdef WIN32#warning add Win32 timer#else /* * Always disable the interrupt if it is active; this avoids being * interrupted by the signal handler and thereby possibly getting * confused. * * We will re-enable the interrupt if necessary in CheckStatementTimeout. */ if (statement_timeout_active || deadlock_timeout_active) {#ifndef __BEOS__ struct itimerval timeval; MemSet(&timeval, 0, sizeof(struct itimerval)); if (setitimer(ITIMER_REAL, &timeval, NULL)) { statement_timeout_active = deadlock_timeout_active = false; return false; }#else /* BeOS doesn't have setitimer, but has set_alarm */ if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0) { statement_timeout_active = deadlock_timeout_active = false; return false; }#endif } /* Always cancel deadlock timeout, in case this is error cleanup */ deadlock_timeout_active = false; /* Cancel or reschedule statement timeout */ if (is_statement_timeout) statement_timeout_active = false; else if (statement_timeout_active) { if (!CheckStatementTimeout()) return false; }#endif return true;}/* * Check for statement timeout. If the timeout time has come, * trigger a query-cancel interrupt; if not, reschedule the SIGALRM * interrupt to occur at the right time. * * Returns true if okay, false if failed to set the interrupt. */static boolCheckStatementTimeout(void){ struct timeval now; if (!statement_timeout_active) return true; /* do nothing if not active */ gettimeofday(&now, NULL); if (now.tv_sec > statement_fin_time.tv_sec || (now.tv_sec == statement_fin_time.tv_sec && now.tv_usec >= statement_fin_time.tv_usec)) { /* Time to die */ statement_timeout_active = false; kill(MyProcPid, SIGINT); } else { /* Not time yet, so (re)schedule the interrupt */#ifdef WIN32#warning add win32 timer#else#ifndef __BEOS__ struct itimerval timeval; MemSet(&timeval, 0, sizeof(struct itimerval)); timeval.it_value.tv_sec = statement_fin_time.tv_sec - now.tv_sec; timeval.it_value.tv_usec = statement_fin_time.tv_usec - now.tv_usec; if (timeval.it_value.tv_usec < 0) { timeval.it_value.tv_sec--; timeval.it_value.tv_usec += 1000000; } if (setitimer(ITIMER_REAL, &timeval, NULL)) return false;#else /* BeOS doesn't have setitimer, but has set_alarm */ bigtime_t time_interval; time_interval = (statement_fin_time.tv_sec - now.tv_sec) * 1000000 + (statement_fin_time.tv_usec - now.tv_usec); if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0) return false;#endif#endif } return true;}/* * Signal handler for SIGALRM * * Process deadlock check and/or statement timeout check, as needed. * To avoid various edge cases, we must be careful to do nothing * when there is nothing to be done. We also need to be able to * reschedule the timer interrupt if called before end of statement. */voidhandle_sig_alarm(SIGNAL_ARGS){ int save_errno = errno; if (deadlock_timeout_active) { deadlock_timeout_active = false; CheckDeadLock(); } if (statement_timeout_active) (void) CheckStatementTimeout(); errno = save_errno;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -