|
|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|