mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-23 19:39:53 +08: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…
Reference in New Issue
Block a user