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

📄 proc.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ProcKill() -- Destroy the per-proc data structure for *		this process. Release any of its held LW locks. */static voidProcKill(void){	/* use volatile pointer to prevent code rearrangement */	volatile PROC_HDR *procglobal = ProcGlobal;	Assert(MyProc != NULL);	/* Release any LW locks I am holding */	LWLockReleaseAll();	/*	 * Make real sure we release any buffer locks and pins we might be	 * holding, too.  It is pretty ugly to do this here and not in a	 * shutdown callback registered by the bufmgr ... but we must do this	 * *after* LWLockReleaseAll and *before* zapping MyProc.	 */	AbortBufferIO();	UnlockBuffers();	AtEOXact_Buffers(false);	/* Get off any wait queue I might be on */	LockWaitCancel();	/* Remove from the standard lock table */	LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, true, InvalidTransactionId);#ifdef USER_LOCKS	/* Remove from the user lock table */	LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);#endif	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;	SpinLockRelease(ProcStructLock);}/* * DummyProcKill() -- Cut-down version of ProcKill for dummy (checkpoint) *		processes.	The PGPROC and sema are not released, only marked *		as not-in-use. */static voidDummyProcKill(void){	Assert(MyProc != NULL && MyProc == DummyProc);	/* Release any LW locks I am holding */	LWLockReleaseAll();	/* Release buffer locks and pins, too */	AbortBufferIO();	UnlockBuffers();	AtEOXact_Buffers(false);	/* I can't be on regular lock queues, so needn't check */	/* Mark DummyProc no longer in use */	MyProc->pid = 0;	/* PGPROC struct isn't mine anymore */	MyProc = NULL;}/* * 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(LOCKMETHODTABLE *lockMethodTable,		  LOCKMODE lockmode,		  LOCK *lock,		  PROCLOCK *proclock){	LWLockId	masterLock = lockMethodTable->masterLock;	PROC_QUEUE *waitQueue = &(lock->waitProcs);	int			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)	{		int			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,									   NULL) == STATUS_OK)				{					/* Skip the wait and just grant myself the lock. */					GrantLock(lock, proclock, lockmode);					return STATUS_OK;				}				/* Break out of loop to put myself before him */				break;			}			/* Nope, so advance to next waiter */			aheadRequests |= (1 << 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 |= (1 << lockmode);	/* Set up wait information in PGPROC object, too */	MyProc->waitLock = lock;	MyProc->waitHolder = proclock;	MyProc->waitLockMode = lockmode;	MyProc->errType = STATUS_OK;	/* initialize result for success */	/*	 * 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);		MyProc->errType = STATUS_ERROR;		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->errType = 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 state-change work to do after	 * being granted the lock (the grantor did it all).	 */	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");	/*	 * Now there is nothing for LockWaitCancel to do.	 */	waitingForLock = false;	/*	 * Re-acquire the locktable's masterLock.	 */	LWLockAcquire(masterLock, LW_EXCLUSIVE);	/*	 * We don't have to do anything else, because the awaker did all the	 * necessary update of the lock table and MyProc.	 */	return MyProc->errType;}/* * 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 errType){	PGPROC	   *retProc;	/* assume that masterLock has been acquired */	/* Proc should be sleeping ... */	if (proc->links.prev == INVALID_OFFSET ||		proc->links.next == INVALID_OFFSET)		return (PGPROC *) 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->waitHolder = NULL;	proc->errType = errType;	/* 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(LOCKMETHODTABLE *lockMethodTable, LOCK *lock){	PROC_QUEUE *waitQueue = &(lock->waitProcs);	int			queue_size = waitQueue->size;	PGPROC	   *proc;	int			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->waitHolder,							   proc,							   NULL) == STATUS_OK)		{			/* OK to waken */			GrantLock(lock, proc->waitHolder, lockmode);

⌨️ 快捷键说明

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