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

📄 lwlock.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* If retrying, allow LWLockRelease to release waiters again */		if (retry)			lock->releaseOK = true;		/* If I can get the lock, do so quickly. */		if (mode == LW_EXCLUSIVE)		{			if (lock->exclusive == 0 && lock->shared == 0)			{				lock->exclusive++;				mustwait = false;			}			else				mustwait = true;		}		else		{			if (lock->exclusive == 0)			{				lock->shared++;				mustwait = false;			}			else				mustwait = true;		}		if (!mustwait)			break;				/* got the lock */		/*		 * Add myself to wait queue.		 *		 * If we don't have a PGPROC structure, there's no way to wait. This		 * should never occur, since MyProc should only be null during shared		 * memory initialization.		 */		if (proc == NULL)			elog(FATAL, "cannot wait without a PGPROC structure");		proc->lwWaiting = true;		proc->lwExclusive = (mode == LW_EXCLUSIVE);		proc->lwWaitLink = NULL;		if (lock->head == NULL)			lock->head = proc;		else			lock->tail->lwWaitLink = proc;		lock->tail = proc;		/* Can release the mutex now */		SpinLockRelease_NoHoldoff(&lock->mutex);		/*		 * Wait until awakened.		 *		 * Since we share the process wait semaphore with the regular lock		 * manager and ProcWaitForSignal, and we may need to acquire an LWLock		 * while one of those is pending, it is possible that we get awakened		 * for a reason other than being signaled by LWLockRelease. If so,		 * loop back and wait again.  Once we've gotten the LWLock,		 * re-increment the sema by the number of additional signals received,		 * so that the lock manager or signal manager will see the received		 * signal when it next waits.		 */		LOG_LWDEBUG("LWLockAcquire", lockid, "waiting");		for (;;)		{			/* "false" means cannot accept cancel/die interrupt here. */			PGSemaphoreLock(&proc->sem, false);			if (!proc->lwWaiting)				break;			extraWaits++;		}		LOG_LWDEBUG("LWLockAcquire", lockid, "awakened");		/* Now loop back and try to acquire lock again. */		retry = true;	}	/* We are done updating shared state of the lock itself. */	SpinLockRelease_NoHoldoff(&lock->mutex);	/* Add lock to list of locks held by this backend */	held_lwlocks[num_held_lwlocks++] = lockid;	/*	 * Fix the process wait semaphore's count for any absorbed wakeups.	 */	while (extraWaits-- > 0)		PGSemaphoreUnlock(&proc->sem);}/* * LWLockConditionalAcquire - acquire a lightweight lock in the specified mode * * If the lock is not available, return FALSE with no side-effects. * * If successful, cancel/die interrupts are held off until lock release. */boolLWLockConditionalAcquire(LWLockId lockid, LWLockMode mode){	volatile LWLock *lock = &(LWLockArray[lockid].lock);	bool		mustwait;	PRINT_LWDEBUG("LWLockConditionalAcquire", lockid, lock);	/* Ensure we will have room to remember the lock */	if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)		elog(ERROR, "too many LWLocks taken");	/*	 * Lock out cancel/die interrupts until we exit the code section protected	 * by the LWLock.  This ensures that interrupts will not interfere with	 * manipulations of data structures in shared memory.	 */	HOLD_INTERRUPTS();	/* Acquire mutex.  Time spent holding mutex should be short! */	SpinLockAcquire_NoHoldoff(&lock->mutex);	/* If I can get the lock, do so quickly. */	if (mode == LW_EXCLUSIVE)	{		if (lock->exclusive == 0 && lock->shared == 0)		{			lock->exclusive++;			mustwait = false;		}		else			mustwait = true;	}	else	{		if (lock->exclusive == 0)		{			lock->shared++;			mustwait = false;		}		else			mustwait = true;	}	/* We are done updating shared state of the lock itself. */	SpinLockRelease_NoHoldoff(&lock->mutex);	if (mustwait)	{		/* Failed to get lock, so release interrupt holdoff */		RESUME_INTERRUPTS();		LOG_LWDEBUG("LWLockConditionalAcquire", lockid, "failed");	}	else	{		/* Add lock to list of locks held by this backend */		held_lwlocks[num_held_lwlocks++] = lockid;	}	return !mustwait;}/* * LWLockRelease - release a previously acquired lock */voidLWLockRelease(LWLockId lockid){	volatile LWLock *lock = &(LWLockArray[lockid].lock);	PGPROC	   *head;	PGPROC	   *proc;	int			i;	PRINT_LWDEBUG("LWLockRelease", lockid, lock);	/*	 * Remove lock from list of locks held.  Usually, but not always, it will	 * be the latest-acquired lock; so search array backwards.	 */	for (i = num_held_lwlocks; --i >= 0;)	{		if (lockid == held_lwlocks[i])			break;	}	if (i < 0)		elog(ERROR, "lock %d is not held", (int) lockid);	num_held_lwlocks--;	for (; i < num_held_lwlocks; i++)		held_lwlocks[i] = held_lwlocks[i + 1];	/* Acquire mutex.  Time spent holding mutex should be short! */	SpinLockAcquire_NoHoldoff(&lock->mutex);	/* Release my hold on lock */	if (lock->exclusive > 0)		lock->exclusive--;	else	{		Assert(lock->shared > 0);		lock->shared--;	}	/*	 * See if I need to awaken any waiters.  If I released a non-last shared	 * hold, there cannot be anything to do.  Also, do not awaken any waiters	 * if someone has already awakened waiters that haven't yet acquired the	 * lock.	 */	head = lock->head;	if (head != NULL)	{		if (lock->exclusive == 0 && lock->shared == 0 && lock->releaseOK)		{			/*			 * Remove the to-be-awakened PGPROCs from the queue.  If the front			 * waiter wants exclusive lock, awaken him only. Otherwise awaken			 * as many waiters as want shared access.			 */			proc = head;			if (!proc->lwExclusive)			{				while (proc->lwWaitLink != NULL &&					   !proc->lwWaitLink->lwExclusive)					proc = proc->lwWaitLink;			}			/* proc is now the last PGPROC to be released */			lock->head = proc->lwWaitLink;			proc->lwWaitLink = NULL;			/* prevent additional wakeups until retryer gets to run */			lock->releaseOK = false;		}		else		{			/* lock is still held, can't awaken anything */			head = NULL;		}	}	/* We are done updating shared state of the lock itself. */	SpinLockRelease_NoHoldoff(&lock->mutex);	/*	 * Awaken any waiters I removed from the queue.	 */	while (head != NULL)	{		LOG_LWDEBUG("LWLockRelease", lockid, "release waiter");		proc = head;		head = proc->lwWaitLink;		proc->lwWaitLink = NULL;		proc->lwWaiting = false;		PGSemaphoreUnlock(&proc->sem);	}	/*	 * Now okay to allow cancel/die interrupts.	 */	RESUME_INTERRUPTS();}/* * LWLockReleaseAll - release all currently-held locks * * Used to clean up after ereport(ERROR). An important difference between this * function and retail LWLockRelease calls is that InterruptHoldoffCount is * unchanged by this operation.  This is necessary since InterruptHoldoffCount * has been set to an appropriate level earlier in error recovery. We could * decrement it below zero if we allow it to drop for each released lock! */voidLWLockReleaseAll(void){	while (num_held_lwlocks > 0)	{		HOLD_INTERRUPTS();		/* match the upcoming RESUME_INTERRUPTS */		LWLockRelease(held_lwlocks[num_held_lwlocks - 1]);	}}/* * LWLockHeldByMe - test whether my process currently holds a lock * * This is meant as debug support only.  We do not distinguish whether the * lock is held shared or exclusive. */boolLWLockHeldByMe(LWLockId lockid){	int			i;	for (i = 0; i < num_held_lwlocks; i++)	{		if (held_lwlocks[i] == lockid)			return true;	}	return false;}

⌨️ 快捷键说明

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