Commit 1321509f authored by Thomas Munro's avatar Thomas Munro

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
parent b31fbe85
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "postgres.h" #include "postgres.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "portability/instr_time.h"
#include "storage/condition_variable.h" #include "storage/condition_variable.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/proc.h" #include "storage/proc.h"
...@@ -122,8 +123,24 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv) ...@@ -122,8 +123,24 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
void void
ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
{ {
WaitEvent event; (void) ConditionVariableTimedSleep(cv, -1 /* no timeout */ ,
bool done = false; 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 * 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) ...@@ -143,23 +160,37 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
if (cv_sleep_target != cv) if (cv_sleep_target != cv)
{ {
ConditionVariablePrepareToSleep(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 * Wait for latch to be set. (If we're awakened for some other
* reason, the code below will cope anyway.) * 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); wait_event_info);
/* Reset latch before examining the state of the wait list. */ /* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch); ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
/* /*
* If this process has been taken out of the wait list, then we know * If this process has been taken out of the wait list, then we know
* that it has been signaled by ConditionVariableSignal (or * that it has been signaled by ConditionVariableSignal (or
...@@ -182,7 +213,23 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) ...@@ -182,7 +213,23 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink); proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
} }
SpinLockRelease(&cv->mutex); 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); ...@@ -43,6 +43,8 @@ extern void ConditionVariableInit(ConditionVariable *cv);
* the condition variable. * the condition variable.
*/ */
extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info); extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info);
extern bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
uint32 wait_event_info);
extern void ConditionVariableCancelSleep(void); extern void ConditionVariableCancelSleep(void);
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment