⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proc.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* And awaken it */	PGSemaphoreUnlock(&proc->sem);	return retProc;}/* * ProcLockWakeup -- routine for waking up processes when a lock is *		released (or a prior waiter is aborted).  Scan all waiters *		for lock, waken any that are no longer blocked. */voidProcLockWakeup(LockMethod lockMethodTable, LOCK *lock){	PROC_QUEUE *waitQueue = &(lock->waitProcs);	int			queue_size = waitQueue->size;	PGPROC	   *proc;	LOCKMASK	aheadRequests = 0;	Assert(queue_size >= 0);	if (queue_size == 0)		return;	proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);	while (queue_size-- > 0)	{		LOCKMODE	lockmode = proc->waitLockMode;		/*		 * Waken if (a) doesn't conflict with requests of earlier waiters, and		 * (b) doesn't conflict with already-held locks.		 */		if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&			LockCheckConflicts(lockMethodTable,							   lockmode,							   lock,							   proc->waitProcLock,							   proc) == STATUS_OK)		{			/* OK to waken */			GrantLock(lock, proc->waitProcLock, lockmode);			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 |= LOCKBIT_ON(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->waitStatus to STATUS_ERROR so that ProcSleep will report an	 * error after we return from the signal handler.	 */	MyProc->waitStatus = 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){	PGSemaphoreLock(&MyProc->sem, true);}/* * 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);}/* * ProcSendSignal - send a signal to a backend identified by PID */voidProcSendSignal(int pid){	PGPROC	   *proc = BackendPidGetProc(pid);	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){	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;		cancel_from_timeout = false;	}	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	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){	/*	 * 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 = false;			cancel_from_timeout = false;			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 = false;			cancel_from_timeout = false;			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;		cancel_from_timeout = false;	}	else if (statement_timeout_active)	{		if (!CheckStatementTimeout())			return false;	}	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;		cancel_from_timeout = true;		kill(MyProcPid, SIGINT);	}	else	{		/* Not time yet, so (re)schedule the interrupt */#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	}	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 + -