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

📄 proc.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
			pfree(buf.data);		}	} while (myWaitStatus == STATUS_WAITING);	/*	 * Disable the timer, if it's still running	 */	if (!disable_sig_alarm(false))		elog(FATAL, "could not disable timer for process wakeup");	/*	 * Re-acquire the lock table's partition lock.  We have to do this to hold	 * off cancel/die interrupts before we can mess with lockAwaited (else we	 * might have a missed or duplicated locallock update).	 */	LWLockAcquire(partitionLock, LW_EXCLUSIVE);	/*	 * We no longer want LockWaitCancel to do anything.	 */	lockAwaited = NULL;	/*	 * If we got the lock, be sure to remember it in the locallock table.	 */	if (MyProc->waitStatus == STATUS_OK)		GrantAwaitedLock();	/*	 * We don't have to do anything else, because the awaker did all the	 * necessary update of the lock table and MyProc.	 */	return MyProc->waitStatus;}/* * ProcWakeup -- wake up a process by releasing its private semaphore. * *	 Also remove the process from the wait queue and set its links invalid. *	 RETURN: the next process in the wait queue. * * The appropriate lock partition lock must be held by caller. * * XXX: presently, this code is only used for the "success" case, and only * works correctly for that case.  To clean up in failure case, would need * to twiddle the lock's request counts too --- see RemoveFromWaitQueue. * Hence, in practice the waitStatus parameter must be STATUS_OK. */PGPROC *ProcWakeup(PGPROC *proc, int waitStatus){	PGPROC	   *retProc;	/* Proc should be sleeping ... */	if (proc->links.prev == INVALID_OFFSET ||		proc->links.next == INVALID_OFFSET)		return NULL;	Assert(proc->waitStatus == STATUS_WAITING);	/* Save next process before we zap the list link */	retProc = (PGPROC *) MAKE_PTR(proc->links.next);	/* Remove process from wait queue */	SHMQueueDelete(&(proc->links));	(proc->waitLock->waitProcs.size)--;	/* Clean up process' state and pass it the ok/fail signal */	proc->waitLock = NULL;	proc->waitProcLock = NULL;	proc->waitStatus = waitStatus;	/* 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. * * The appropriate lock partition lock must be held by caller. */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);}/* * CheckDeadLock * * 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. * (But signal ProcSleep to log a message, if log_lock_waits is true.) * If we have a real deadlock, remove ourselves from the lock's wait queue * and signal an error to ProcSleep. * * NB: this is run inside a signal handler, so be very wary about what is done * here or in called routines. */static voidCheckDeadLock(void){	int			i;	/*	 * Acquire exclusive lock on the entire shared lock data structures. Must	 * grab LWLocks in partition-number order to avoid LWLock deadlock.	 *	 * Note that the deadlock check interrupt had better not be enabled	 * anywhere that this process itself holds lock partition locks, else this	 * will wait forever.  Also note that LWLockAcquire creates a critical	 * section, so that this routine cannot be interrupted by cancel/die	 * interrupts.	 */	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)		LWLockAcquire(FirstLockMgrLock + i, 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 lock partition lock.	 */	if (MyProc->links.prev == INVALID_OFFSET ||		MyProc->links.next == INVALID_OFFSET)		goto check_done;#ifdef LOCK_DEBUG	if (Debug_deadlocks)		DumpAllLocks();#endif	/* Run the deadlock check, and set deadlock_state for use by ProcSleep */	deadlock_state = DeadLockCheck(MyProc);	if (deadlock_state == DS_HARD_DEADLOCK)	{		/*		 * Oops.  We have a deadlock.		 *		 * Get this process out of wait state. (Note: we could do this more		 * efficiently by relying on lockAwaited, but use this coding to		 * preserve the flexibility to kill some other transaction than the		 * one detecting the deadlock.)		 *		 * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so		 * ProcSleep will report an error after we return from the signal		 * handler.		 */		Assert(MyProc->waitLock != NULL);		RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));		/*		 * 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.		 */	}	else if (log_lock_waits || deadlock_state == DS_BLOCKED_BY_AUTOVACUUM)	{		/*		 * Unlock my semaphore so that the interrupted ProcSleep() call can		 * print the log message (we daren't do it here because we are inside		 * a signal handler).  It will then sleep again until someone releases		 * the lock.		 *		 * If blocked by autovacuum, this wakeup will enable ProcSleep to send		 * the cancelling signal to the autovacuum worker.		 */		PGSemaphoreUnlock(&MyProc->sem);	}	/*	 * And release locks.  We do this in reverse order for two reasons: (1)	 * Anyone else who needs more than one of the locks will be trying to lock	 * them in increasing order; we don't want to release the other process	 * until it can get all the locks it needs. (2) This avoids O(N^2)	 * behavior inside LWLockRelease.	 */check_done:	for (i = NUM_LOCK_PARTITIONS; --i >= 0;)		LWLockRelease(FirstLockMgrLock + i);}/* * 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.	Also as with locks, * it's necessary that the caller be robust against bogus wakeups: * always check that the desired state has occurred, and wait again * if not.	This copes with possible "leftover" wakeups. */voidProcWaitForSignal(void){	PGSemaphoreLock(&MyProc->sem, true);}/* * 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){	TimestampTz fin_time;	struct itimerval timeval;	if (is_statement_timeout)	{		/*		 * Begin statement-level timeout		 *		 * Note that we compute statement_fin_time with reference to the		 * statement_timestamp, but apply the specified delay without any		 * correction; that is, we ignore whatever time has elapsed since		 * statement_timestamp was set.  In the normal case only a small		 * interval will have elapsed and so this doesn't matter, but there		 * are corner cases (involving multi-statement query strings with		 * embedded COMMIT or ROLLBACK) where we might re-initialize the		 * statement timeout long after initial receipt of the message. In		 * such cases the enforcement of the statement timeout will be a bit		 * inconsistent.  This annoyance is judged not worth the cost of		 * performing an additional gettimeofday() here.		 */		Assert(!deadlock_timeout_active);		fin_time = GetCurrentStatementStartTimestamp();		fin_time = TimestampTzPlusMilliseconds(fin_time, delayms);		statement_fin_time = fin_time;		cancel_from_timeout = false;		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.		 */		timeout_start_time = GetCurrentTimestamp();		fin_time = TimestampTzPlusMilliseconds(timeout_start_time, delayms);		deadlock_timeout_active = true;		if (fin_time >= statement_fin_time)			return true;	}	else	{		/* Begin deadlock timeout with no statement-level timeout */		deadlock_timeout_active = true;		/* GetCurrentTimestamp can be expensive, so only do it if we must */		if (log_lock_waits)			timeout_start_time = GetCurrentTimestamp();	}	/* If we reach here, okay to set the timer interrupt */	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;	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)	{		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;		}	}	/* 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){	TimestampTz now;	if (!statement_timeout_active)		return true;			/* do nothing if not active */	now = GetCurrentTimestamp();	if (now >= statement_fin_time)	{		/* Time to die */		statement_timeout_active = false;		cancel_from_timeout = true;#ifdef HAVE_SETSID		/* try to signal whole process group */		kill(-MyProcPid, SIGINT);#endif		kill(MyProcPid, SIGINT);	}	else	{		/* Not time yet, so (re)schedule the interrupt */		long		secs;		int			usecs;		struct itimerval timeval;		TimestampDifference(now, statement_fin_time,							&secs, &usecs);		/*		 * It's possible that the difference is less than a microsecond;		 * ensure we don't cancel, rather than set, the interrupt.		 */		if (secs == 0 && usecs == 0)			usecs = 1;		MemSet(&timeval, 0, sizeof(struct itimerval));		timeval.it_value.tv_sec = secs;		timeval.it_value.tv_usec = usecs;		if (setitimer(ITIMER_REAL, &timeval, NULL))			return false;	}	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 + -