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

📄 proc.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	disable_sig_alarm(false);	/* Unlink myself from the wait queue, if on it (might not be anymore!) */	LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);	if (MyProc->links.next != INVALID_OFFSET)	{		/* We could not have been granted the lock yet */		Assert(MyProc->waitStatus == STATUS_ERROR);		RemoveFromWaitQueue(MyProc);	}	else	{		/*		 * Somebody kicked us off the lock queue already.  Perhaps they		 * granted us the lock, or perhaps they detected a deadlock. If they		 * did grant us the lock, we'd better remember it in our local lock		 * table.		 */		if (MyProc->waitStatus == STATUS_OK)			GrantAwaitedLock();	}	waitingForLock = false;	LWLockRelease(LockMgrLock);	/*	 * Reset the proc wait semaphore to zero.  This is necessary in the	 * scenario where someone else granted us the lock we wanted before we	 * were able to remove ourselves from the wait-list.  The semaphore will	 * have been bumped to 1 by the would-be grantor, and since we are no	 * longer going to wait on the sema, we have to force it back to zero.	 * Otherwise, our next attempt to wait for a lock will fall through	 * prematurely.	 */	PGSemaphoreReset(&MyProc->sem);	/*	 * Return true even if we were kicked off the lock before we were able to	 * remove ourselves.	 */	return true;}/* * ProcReleaseLocks() -- release locks associated with current transaction *			at main transaction commit or abort * * At main transaction commit, we release all locks except session locks. * At main transaction abort, we release all locks including session locks; * this lets us clean up after a VACUUM FULL failure. * * At subtransaction commit, we don't release any locks (so this func is not * needed at all); we will defer the releasing to the parent transaction. * At subtransaction abort, we release all locks held by the subtransaction; * this is implemented by retail releasing of the locks under control of * the ResourceOwner mechanism. * * Note that user locks are not released in any case. */voidProcReleaseLocks(bool isCommit){	if (!MyProc)		return;	/* If waiting, get off wait queue (should only be needed after error) */	LockWaitCancel();	/* Release locks */	LockReleaseAll(DEFAULT_LOCKMETHOD, !isCommit);}/* * ProcKill() -- Destroy the per-proc data structure for *		this process. Release any of its held LW locks. */static voidProcKill(int code, Datum arg){	/* use volatile pointer to prevent code rearrangement */	volatile PROC_HDR *procglobal = ProcGlobal;	Assert(MyProc != NULL);	/*	 * Release any LW locks I am holding.  There really shouldn't be any, but	 * it's cheap to check again before we cut the knees off the LWLock	 * facility by releasing our PGPROC ...	 */	LWLockReleaseAll();	/* Remove our PGPROC from the PGPROC array in shared memory */	ProcArrayRemove(MyProc);	SpinLockAcquire(ProcStructLock);	/* Return PGPROC structure (and semaphore) to freelist */	MyProc->links.next = procglobal->freeProcs;	procglobal->freeProcs = MAKE_OFFSET(MyProc);	/* PGPROC struct isn't mine anymore */	MyProc = NULL;	/* Update shared estimate of spins_per_delay */	procglobal->spins_per_delay = update_spins_per_delay(procglobal->spins_per_delay);	SpinLockRelease(ProcStructLock);}/* * DummyProcKill() -- Cut-down version of ProcKill for dummy (bgwriter) *		processes.	The PGPROC and sema are not released, only marked *		as not-in-use. */static voidDummyProcKill(int code, Datum arg){	int			proctype = DatumGetInt32(arg);	PGPROC	   *dummyproc;	Assert(proctype >= 0 && proctype < NUM_DUMMY_PROCS);	dummyproc = &DummyProcs[proctype];	Assert(MyProc == dummyproc);	/* Release any LW locks I am holding (see notes above) */	LWLockReleaseAll();	SpinLockAcquire(ProcStructLock);	/* Mark dummy proc no longer in use */	MyProc->pid = 0;	/* PGPROC struct isn't mine anymore */	MyProc = NULL;	/* Update shared estimate of spins_per_delay */	ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay);	SpinLockRelease(ProcStructLock);}/* * ProcQueue package: routines for putting processes to sleep *		and  waking them up *//* * ProcQueueAlloc -- alloc/attach to a shared memory process queue * * Returns: a pointer to the queue or NULL * Side Effects: Initializes the queue if we allocated one */#ifdef NOT_USEDPROC_QUEUE *ProcQueueAlloc(char *name){	bool		found;	PROC_QUEUE *queue = (PROC_QUEUE *)	ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);	if (!queue)		return NULL;	if (!found)		ProcQueueInit(queue);	return queue;}#endif/* * ProcQueueInit -- initialize a shared memory process queue */voidProcQueueInit(PROC_QUEUE *queue){	SHMQueueInit(&(queue->links));	queue->size = 0;}/* * ProcSleep -- put a process to sleep * * Caller must have set MyProc->heldLocks to reflect locks already held * on the lockable object by this process (under all XIDs). * * Locktable's masterLock must be held at entry, and will be held * at exit. * * Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock). * * ASSUME: that no one will fiddle with the queue until after *		we release the masterLock. * * NOTES: The process queue is now a priority queue for locking. * * P() on the semaphore should put us to sleep.  The process * semaphore is normally zero, so when we try to acquire it, we sleep. */intProcSleep(LockMethod lockMethodTable,		  LOCKMODE lockmode,		  LOCK *lock,		  PROCLOCK *proclock){	LWLockId	masterLock = lockMethodTable->masterLock;	PROC_QUEUE *waitQueue = &(lock->waitProcs);	LOCKMASK	myHeldLocks = MyProc->heldLocks;	bool		early_deadlock = false;	PGPROC	   *proc;	int			i;	/*	 * Determine where to add myself in the wait queue.	 *	 * Normally I should go at the end of the queue.  However, if I already	 * hold locks that conflict with the request of any previous waiter, put	 * myself in the queue just in front of the first such waiter. This is not	 * a necessary step, since deadlock detection would move me to before that	 * waiter anyway; but it's relatively cheap to detect such a conflict	 * immediately, and avoid delaying till deadlock timeout.	 *	 * Special case: if I find I should go in front of some waiter, check to	 * see if I conflict with already-held locks or the requests before that	 * waiter.	If not, then just grant myself the requested lock immediately.	 * This is the same as the test for immediate grant in LockAcquire, except	 * we are only considering the part of the wait queue before my insertion	 * point.	 */	if (myHeldLocks != 0)	{		LOCKMASK	aheadRequests = 0;		proc = (PGPROC *) MAKE_PTR(waitQueue->links.next);		for (i = 0; i < waitQueue->size; i++)		{			/* Must he wait for me? */			if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)			{				/* Must I wait for him ? */				if (lockMethodTable->conflictTab[lockmode] & proc->heldLocks)				{					/*					 * Yes, so we have a deadlock.	Easiest way to clean up					 * correctly is to call RemoveFromWaitQueue(), but we					 * can't do that until we are *on* the wait queue. So, set					 * a flag to check below, and break out of loop.  Also,					 * record deadlock info for later message.					 */					RememberSimpleDeadLock(MyProc, lockmode, lock, proc);					early_deadlock = true;					break;				}				/* I must go before this waiter.  Check special case. */				if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&					LockCheckConflicts(lockMethodTable,									   lockmode,									   lock,									   proclock,									   MyProc) == STATUS_OK)				{					/* Skip the wait and just grant myself the lock. */					GrantLock(lock, proclock, lockmode);					GrantAwaitedLock();					return STATUS_OK;				}				/* Break out of loop to put myself before him */				break;			}			/* Nope, so advance to next waiter */			aheadRequests |= LOCKBIT_ON(proc->waitLockMode);			proc = (PGPROC *) MAKE_PTR(proc->links.next);		}		/*		 * If we fall out of loop normally, proc points to waitQueue head, so		 * we will insert at tail of queue as desired.		 */	}	else	{		/* I hold no locks, so I can't push in front of anyone. */		proc = (PGPROC *) &(waitQueue->links);	}	/*	 * Insert self into queue, ahead of the given proc (or at tail of queue).	 */	SHMQueueInsertBefore(&(proc->links), &(MyProc->links));	waitQueue->size++;	lock->waitMask |= LOCKBIT_ON(lockmode);	/* Set up wait information in PGPROC object, too */	MyProc->waitLock = lock;	MyProc->waitProcLock = proclock;	MyProc->waitLockMode = lockmode;	MyProc->waitStatus = STATUS_ERROR;	/* initialize result for error */	/*	 * If we detected deadlock, give up without waiting.  This must agree with	 * CheckDeadLock's recovery code, except that we shouldn't release the	 * semaphore since we haven't tried to lock it yet.	 */	if (early_deadlock)	{		RemoveFromWaitQueue(MyProc);		return STATUS_ERROR;	}	/* mark that we are waiting for a lock */	waitingForLock = true;	/*	 * Release the locktable's masterLock.	 *	 * NOTE: this may also cause us to exit critical-section state, possibly	 * allowing a cancel/die interrupt to be accepted. This is OK because we	 * have recorded the fact that we are waiting for a lock, and so	 * LockWaitCancel will clean up if cancel/die happens.	 */	LWLockRelease(masterLock);	/*	 * Set timer so we can wake up after awhile and check for a deadlock. If a	 * deadlock is detected, the handler releases the process's semaphore and	 * sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we	 * must report failure rather than success.	 *	 * By delaying the check until we've waited for a bit, we can avoid	 * running the rather expensive deadlock-check code in most cases.	 */	if (!enable_sig_alarm(DeadlockTimeout, false))		elog(FATAL, "could not set timer for process wakeup");	/*	 * If someone wakes us between LWLockRelease and PGSemaphoreLock,	 * PGSemaphoreLock will not block.	The wakeup is "saved" by the semaphore	 * implementation.	Note also that if CheckDeadLock is invoked but does	 * not detect a deadlock, PGSemaphoreLock() will continue to wait.	There	 * used to be a loop here, but it was useless code...	 *	 * We pass interruptOK = true, which eliminates a window in which	 * cancel/die interrupts would be held off undesirably.  This is a promise	 * that we don't mind losing control to a cancel/die interrupt here.  We	 * don't, because we have no shared-state-change work to do after being	 * granted the lock (the grantor did it all).  We do have to worry about	 * updating the locallock table, but if we lose control to an error,	 * LockWaitCancel will fix that up.	 */	PGSemaphoreLock(&MyProc->sem, true);	/*	 * 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 locktable's masterLock.  We have to do this to hold off	 * cancel/die interrupts before we can mess with waitingForLock (else we	 * might have a missed or duplicated locallock update).	 */	LWLockAcquire(masterLock, LW_EXCLUSIVE);	/*	 * We no longer want LockWaitCancel to do anything.	 */	waitingForLock = false;	/*	 * 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. * * 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. */PGPROC *ProcWakeup(PGPROC *proc, int waitStatus){	PGPROC	   *retProc;	/* assume that masterLock has been acquired */	/* Proc should be sleeping ... */	if (proc->links.prev == INVALID_OFFSET ||		proc->links.next == INVALID_OFFSET)		return NULL;	/* 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;

⌨️ 快捷键说明

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