mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Introduce timed waits for condition variables.
Provide ConditionVariableTimedSleep(), like ConditionVariableSleep() but with a timeout argument. Author: Shawn Debnath Reviewed-by: Kyotaro Horiguchi, Thomas Munro Discussion: https://postgr.es/m/eeb06007ccfe46e399df6af18bfcd15a@EX13D05UWC002.ant.amazon.com
This commit is contained in:
		
							parent
							
								
									b31fbe852c
								
							
						
					
					
						commit
						1321509fa4
					
				@ -19,6 +19,7 @@
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
 | 
			
		||||
#include "miscadmin.h"
 | 
			
		||||
#include "portability/instr_time.h"
 | 
			
		||||
#include "storage/condition_variable.h"
 | 
			
		||||
#include "storage/ipc.h"
 | 
			
		||||
#include "storage/proc.h"
 | 
			
		||||
@ -122,8 +123,24 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
 | 
			
		||||
void
 | 
			
		||||
ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
 | 
			
		||||
{
 | 
			
		||||
	WaitEvent	event;
 | 
			
		||||
	bool		done = false;
 | 
			
		||||
	(void) ConditionVariableTimedSleep(cv, -1 /* no timeout */ ,
 | 
			
		||||
									   wait_event_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Wait for a condition variable to be signaled or a timeout to be reached.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns true when timeout expires, otherwise returns false.
 | 
			
		||||
 *
 | 
			
		||||
 * See ConditionVariableSleep() for general usage.
 | 
			
		||||
 */
 | 
			
		||||
bool
 | 
			
		||||
ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 | 
			
		||||
							uint32 wait_event_info)
 | 
			
		||||
{
 | 
			
		||||
	long		cur_timeout = -1;
 | 
			
		||||
	instr_time	start_time;
 | 
			
		||||
	instr_time	cur_time;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the caller didn't prepare to sleep explicitly, then do so now and
 | 
			
		||||
@ -143,23 +160,37 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
 | 
			
		||||
	if (cv_sleep_target != cv)
 | 
			
		||||
	{
 | 
			
		||||
		ConditionVariablePrepareToSleep(cv);
 | 
			
		||||
		return;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do
 | 
			
		||||
	/*
 | 
			
		||||
	 * Record the current time so that we can calculate the remaining timeout
 | 
			
		||||
	 * if we are woken up spuriously.
 | 
			
		||||
	 */
 | 
			
		||||
	if (timeout >= 0)
 | 
			
		||||
	{
 | 
			
		||||
		CHECK_FOR_INTERRUPTS();
 | 
			
		||||
		INSTR_TIME_SET_CURRENT(start_time);
 | 
			
		||||
		Assert(timeout >= 0 && timeout <= INT_MAX);
 | 
			
		||||
		cur_timeout = timeout;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		WaitEvent	event;
 | 
			
		||||
		bool		done = false;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Wait for latch to be set.  (If we're awakened for some other
 | 
			
		||||
		 * reason, the code below will cope anyway.)
 | 
			
		||||
		 */
 | 
			
		||||
		(void) WaitEventSetWait(cv_wait_event_set, -1, &event, 1,
 | 
			
		||||
		(void) WaitEventSetWait(cv_wait_event_set, cur_timeout, &event, 1,
 | 
			
		||||
								wait_event_info);
 | 
			
		||||
 | 
			
		||||
		/* Reset latch before examining the state of the wait list. */
 | 
			
		||||
		ResetLatch(MyLatch);
 | 
			
		||||
 | 
			
		||||
		CHECK_FOR_INTERRUPTS();
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If this process has been taken out of the wait list, then we know
 | 
			
		||||
		 * that it has been signaled by ConditionVariableSignal (or
 | 
			
		||||
@ -182,7 +213,23 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
 | 
			
		||||
			proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
 | 
			
		||||
		}
 | 
			
		||||
		SpinLockRelease(&cv->mutex);
 | 
			
		||||
	} while (!done);
 | 
			
		||||
 | 
			
		||||
		/* We were signaled, so return */
 | 
			
		||||
		if (done)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		/* If we're not done, update cur_timeout for next iteration */
 | 
			
		||||
		if (timeout >= 0)
 | 
			
		||||
		{
 | 
			
		||||
			INSTR_TIME_SET_CURRENT(cur_time);
 | 
			
		||||
			INSTR_TIME_SUBTRACT(cur_time, start_time);
 | 
			
		||||
			cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
 | 
			
		||||
 | 
			
		||||
			/* Have we crossed the timeout threshold? */
 | 
			
		||||
			if (cur_timeout <= 0)
 | 
			
		||||
				return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,8 @@ extern void ConditionVariableInit(ConditionVariable *cv);
 | 
			
		||||
 * the condition variable.
 | 
			
		||||
 */
 | 
			
		||||
extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info);
 | 
			
		||||
extern bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 | 
			
		||||
										uint32 wait_event_info);
 | 
			
		||||
extern void ConditionVariableCancelSleep(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user