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

📄 proc.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
 * to acquire it, we sleep. * * ASSUME: that no one will fiddle with the queue until after *		we release the spin lock. * * NOTES: The process queue is now a priority queue for locking. */intProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */		  LOCKMETHODCTL *lockctl,		  int token,			/* lockmode */		  LOCK *lock){	int			i;	SPINLOCK	spinlock = lockctl->masterLock;	PROC	   *proc;	int			myMask = (1 << token);	int			waitMask = lock->waitMask;	int			aheadHolders[MAX_LOCKMODES];	bool		selfConflict = (lockctl->conflictTab[token] & myMask),				prevSame = false;	bool		deadlock_checked = false;	struct itimerval timeval,				dummy;	MyProc->token = token;	MyProc->waitLock = lock;	proc = (PROC *) MAKE_PTR(waitQueue->links.prev);	/* if we don't conflict with any waiter - be first in queue */	if (!(lockctl->conflictTab[token] & waitMask))		goto ins;	for (i = 1; i < MAX_LOCKMODES; i++)		aheadHolders[i] = lock->activeHolders[i];	(aheadHolders[token])++;	for (i = 0; i < waitQueue->size; i++)	{		/* am I waiting for him ? */		if (lockctl->conflictTab[token] & proc->holdLock)		{			/* is he waiting for me ? */			if (lockctl->conflictTab[proc->token] & MyProc->holdLock)			{				MyProc->errType = STATUS_ERROR;				elog(NOTICE, DeadLockMessage);				goto rt;			}			/* being waiting for him - go past */		}		/* if he waits for me */		else if (lockctl->conflictTab[proc->token] & MyProc->holdLock)			break;		/* if conflicting locks requested */		else if (lockctl->conflictTab[proc->token] & myMask)		{			/*			 * If I request non self-conflicting lock and there are others			 * requesting the same lock just before me - stay here.			 */			if (!selfConflict && prevSame)				break;		}		/*		 * Last attempt to don't move any more: if we don't conflict with		 * rest waiters in queue.		 */		else if (!(lockctl->conflictTab[token] & waitMask))			break;		prevSame = (proc->token == token);		(aheadHolders[proc->token])++;		if (aheadHolders[proc->token] == lock->holders[proc->token])			waitMask &= ~(1 << proc->token);		proc = (PROC *) MAKE_PTR(proc->links.prev);	}ins:;	/* -------------------	 * assume that these two operations are atomic (because	 * of the spinlock).	 * -------------------	 */	SHMQueueInsertTL(&(proc->links), &(MyProc->links));	waitQueue->size++;	lock->waitMask |= myMask;	SpinRelease(spinlock);	/* --------------	 * We set this so we can wake up periodically and check for a deadlock.	 * If a deadlock is detected, the handler releases the processes	 * semaphore and aborts the current transaction.	 *	 * Need to zero out struct to set the interval and the micro seconds fields	 * to 0.	 * --------------	 */	MemSet(&timeval, 0, sizeof(struct itimerval));	timeval.it_value.tv_sec = \		(DeadlockCheckTimer ? DeadlockCheckTimer : DEADLOCK_CHECK_TIMER);	do	{		MyProc->errType = NO_ERROR;		/* reset flag after deadlock check */		if (!deadlock_checked)			if (setitimer(ITIMER_REAL, &timeval, &dummy))				elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");		deadlock_checked = true;		/* --------------		 * if someone wakes us between SpinRelease and IpcSemaphoreLock,		 * IpcSemaphoreLock will not block.  The wakeup is "saved" by		 * the semaphore implementation.		 * --------------		 */		IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum,						 IpcExclusiveLock);	} while (MyProc->errType == STATUS_NOT_FOUND);		/* sleep after deadlock														 * check */	/* ---------------	 * We were awoken before a timeout - now disable the timer	 * ---------------	 */	timeval.it_value.tv_sec = 0;	if (setitimer(ITIMER_REAL, &timeval, &dummy))		elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");	/* ----------------	 * We were assumed to be in a critical section when we went	 * to sleep.	 * ----------------	 */	SpinAcquire(spinlock);rt:;#ifdef LOCK_MGR_DEBUG	/* Just to get meaningful debug messages from DumpLocks() */	MyProc->waitLock = (LOCK *) NULL;#endif	return MyProc->errType;}/* * ProcWakeup -- wake up a process by releasing its private semaphore. * *	 remove the process from the wait queue and set its links invalid. *	 RETURN: the next process in the wait queue. */PROC *ProcWakeup(PROC *proc, int errType){	PROC	   *retProc;	/* assume that spinlock has been acquired */	if (proc->links.prev == INVALID_OFFSET ||		proc->links.next == INVALID_OFFSET)		return (PROC *) NULL;	retProc = (PROC *) MAKE_PTR(proc->links.prev);	/* you have to update waitLock->waitProcs.size yourself */	SHMQueueDelete(&(proc->links));	SHMQueueElemInit(&(proc->links));	proc->errType = errType;	IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);	return retProc;}/* * ProcLockWakeup -- routine for waking up processes when a lock is *		released. */intProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock){	PROC	   *proc;	int			count = 0;	int			trace_flag;	int			last_locktype = 0;	int			queue_size = queue->size;	Assert(queue->size >= 0);	if (!queue->size)		return STATUS_NOT_FOUND;	proc = (PROC *) MAKE_PTR(queue->links.prev);	while ((queue_size--) && (proc))	{		/*		 * This proc will conflict as the previous one did, don't even		 * try.		 */		if (proc->token == last_locktype)			continue;		/*		 * Does this proc conflict with locks held by others ?		 */		if (LockResolveConflicts(lockmethod,								 lock,								 proc->token,								 proc->xid,								 (XIDLookupEnt *) NULL) != STATUS_OK)		{			if (count != 0)				break;			last_locktype = proc->token;			continue;		}		/*		 * there was a waiting process, grant it the lock before waking it		 * up.	This will prevent another process from seizing the lock		 * between the time we release the lock master (spinlock) and the		 * time that the awoken process begins executing again.		 */		GrantLock(lock, proc->token);		/*		 * ProcWakeup removes proc from the lock waiting process queue and		 * returns the next proc in chain.		 */		count++;		queue->size--;		proc = ProcWakeup(proc, NO_ERROR);	}	Assert(queue->size >= 0);	if (count)		return STATUS_OK;	else	{		/* Something is still blocking us.	May have deadlocked. */		trace_flag = (lock->tag.lockmethod == USER_LOCKMETHOD) ? \			TRACE_USERLOCKS : TRACE_LOCKS;		TPRINTF(trace_flag,				"ProcLockWakeup: lock(%x) can't wake up any process",				MAKE_OFFSET(lock));#ifdef DEADLOCK_DEBUG		if (pg_options[trace_flag] >= 2)			DumpAllLocks();#endif		return STATUS_NOT_FOUND;	}}voidProcAddLock(SHM_QUEUE *elem){	SHMQueueInsertTL(&MyProc->lockQueue, elem);}/* -------------------- * We only get to this routine if we got SIGALRM after DEADLOCK_CHECK_TIMER * while waiting for a lock to be released by some other process.  If we have * a real deadlock, we must also indicate that I'm no longer waiting * on a lock so that other processes don't try to wake me up and screw * up my semaphore. * -------------------- */static voidHandleDeadLock(int sig){	LOCK	   *mywaitlock;	LockLockTable();	/* ---------------------	 * 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.	 *	 * Damn these names are LONG! -mer	 * ---------------------	 */	if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==		IpcSemaphoreDefaultStartValue)	{		UnlockLockTable();		return;	}	/*	 * you would think this would be unnecessary, but...	 *	 * this also means we've been removed already.  in some ports (e.g.,	 * sparc and aix) the semop(2) implementation is such that we can	 * actually end up in this handler after someone has removed us from	 * the queue and bopped the semaphore *but the test above fails to	 * detect the semaphore update* (presumably something weird having to	 * do with the order in which the semaphore wakeup signal and SIGALRM	 * get handled).	 */	if (MyProc->links.prev == INVALID_OFFSET ||		MyProc->links.next == INVALID_OFFSET)	{		UnlockLockTable();		return;	}#ifdef DEADLOCK_DEBUG	DumpAllLocks();#endif	MyProc->errType = STATUS_NOT_FOUND;	if (!DeadLockCheck(MyProc, MyProc->waitLock))	{		UnlockLockTable();		return;	}	mywaitlock = MyProc->waitLock;	/* ------------------------	 * Get this process off the lock's wait queue	 * ------------------------	 */	Assert(mywaitlock->waitProcs.size > 0);	--mywaitlock->waitProcs.size;	SHMQueueDelete(&(MyProc->links));	SHMQueueElemInit(&(MyProc->links));	/* ------------------	 * Unlock my semaphore so that the count is right for next time.	 * I was awoken by a signal, not by someone unlocking my semaphore.	 * ------------------	 */	IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum,					   IpcExclusiveLock);	/* -------------	 * Set MyProc->errType to STATUS_ERROR so that we abort after	 * returning from this handler.	 * -------------	 */	MyProc->errType = STATUS_ERROR;	/*	 * if this doesn't follow the IpcSemaphoreUnlock then we get lock	 * table corruption ("LockReplace: xid table corrupted") due to race	 * conditions.	i don't claim to understand this...	 */	UnlockLockTable();	elog(NOTICE, DeadLockMessage);	return;}voidProcReleaseSpins(PROC *proc){	int			i;	if (!proc)		proc = MyProc;	if (!proc)		return;	for (i = 0; i < (int) MAX_SPINS; i++)	{		if (proc->sLocks[i])		{			Assert(proc->sLocks[i] == 1);			SpinRelease(i);		}	}}/***************************************************************************** * *****************************************************************************//* * ProcGetNewSemKeyAndNum - *	  scan the free semaphore bitmap and allocate a single semaphore from *	  a semaphore set. (If the semaphore set doesn't exist yet, *	  IpcSemaphoreCreate will create it. Otherwise, we use the existing *	  semaphore set.) */static voidProcGetNewSemKeyAndNum(IPCKey *key, int *semNum){	int			i;	int32	   *freeSemMap = ProcGlobal->freeSemMap;	int32		fullmask = (1 << (PROC_NSEMS_PER_SET + 1)) - 1;	/*	 * we hold ProcStructLock when entering this routine. We scan through	 * the bitmap to look for a free semaphore.	 */	for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)	{		int			mask = 1;		int			j;		if (freeSemMap[i] == fullmask)			continue;			/* this set is fully allocated */		for (j = 0; j < PROC_NSEMS_PER_SET; j++)		{			if ((freeSemMap[i] & mask) == 0)			{				/*				 * a free semaphore found. Mark it as allocated. Also set				 * the bit indicating whole set is allocated.				 */				freeSemMap[i] |= mask + (1 << PROC_NSEMS_PER_SET);				*key = ProcGlobal->currKey + i;				*semNum = j;				return;			}			mask <<= 1;		}	}	/* if we reach here, all the semaphores are in use. */	elog(ERROR, "InitProc: cannot allocate a free semaphore");}/* * ProcFreeSem - *	  free up our semaphore in the semaphore set. */static voidProcFreeSem(IpcSemaphoreKey semKey, int semNum){	int			mask;	int			i;	int32	   *freeSemMap = ProcGlobal->freeSemMap;	i = semKey - ProcGlobal->currKey;	mask = ~(1 << semNum);	freeSemMap[i] &= mask;	/*	 * Formerly we'd release a semaphore set if it was now completely	 * unused, but now we keep the semaphores to ensure we won't run out	 * when starting new backends --- cf. InitProcGlobal.  Note that the	 * PROC_NSEMS_PER_SET+1'st bit of the freeSemMap entry remains set to	 * indicate it is still allocated; ProcFreeAllSemaphores() needs that.	 */}/* * ProcFreeAllSemaphores - *	  called at shmem_exit time, ie when exiting the postmaster or *	  destroying shared state for a failed set of backends. *	  Free up all the semaphores allocated to the lmgrs of the backends. */static voidProcFreeAllSemaphores(){	int			i;	int32	   *freeSemMap = ProcGlobal->freeSemMap;	for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)	{		if (freeSemMap[i] != 0)			IpcSemaphoreKill(ProcGlobal->currKey + i);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -