PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
condition_variable.h File Reference
Include dependency graph for condition_variable.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ConditionVariable
 
union  ConditionVariableMinimallyPadded
 

Macros

#define CV_MINIMAL_SIZE   (sizeof(ConditionVariable) <= 16 ? 16 : 32)
 

Typedefs

typedef union ConditionVariableMinimallyPadded ConditionVariableMinimallyPadded
 

Functions

void ConditionVariableInit (ConditionVariable *cv)
 
void ConditionVariableSleep (ConditionVariable *cv, uint32 wait_event_info)
 
bool ConditionVariableTimedSleep (ConditionVariable *cv, long timeout, uint32 wait_event_info)
 
bool ConditionVariableCancelSleep (void)
 
void ConditionVariablePrepareToSleep (ConditionVariable *cv)
 
void ConditionVariableSignal (ConditionVariable *cv)
 
void ConditionVariableBroadcast (ConditionVariable *cv)
 

Macro Definition Documentation

◆ CV_MINIMAL_SIZE

#define CV_MINIMAL_SIZE   (sizeof(ConditionVariable) <= 16 ? 16 : 32)

Definition at line 38 of file condition_variable.h.

Typedef Documentation

◆ ConditionVariableMinimallyPadded

Function Documentation

◆ ConditionVariableBroadcast()

void ConditionVariableBroadcast ( ConditionVariable cv)

Definition at line 282 of file condition_variable.c.

283{
284 int pgprocno = MyProcNumber;
285 PGPROC *proc = NULL;
286 bool have_sentinel = false;
287
288 /*
289 * In some use-cases, it is common for awakened processes to immediately
290 * re-queue themselves. If we just naively try to reduce the wakeup list
291 * to empty, we'll get into a potentially-indefinite loop against such a
292 * process. The semantics we really want are just to be sure that we have
293 * wakened all processes that were in the list at entry. We can use our
294 * own cvWaitLink as a sentinel to detect when we've finished.
295 *
296 * A seeming flaw in this approach is that someone else might signal the
297 * CV and in doing so remove our sentinel entry. But that's fine: since
298 * CV waiters are always added and removed in order, that must mean that
299 * every previous waiter has been wakened, so we're done. We'll get an
300 * extra "set" on our latch from the someone else's signal, which is
301 * slightly inefficient but harmless.
302 *
303 * We can't insert our cvWaitLink as a sentinel if it's already in use in
304 * some other proclist. While that's not expected to be true for typical
305 * uses of this function, we can deal with it by simply canceling any
306 * prepared CV sleep. The next call to ConditionVariableSleep will take
307 * care of re-establishing the lost state.
308 */
309 if (cv_sleep_target != NULL)
311
312 /*
313 * Inspect the state of the queue. If it's empty, we have nothing to do.
314 * If there's exactly one entry, we need only remove and signal that
315 * entry. Otherwise, remove the first entry and insert our sentinel.
316 */
318 /* While we're here, let's assert we're not in the list. */
319 Assert(!proclist_contains(&cv->wakeup, pgprocno, cvWaitLink));
320
321 if (!proclist_is_empty(&cv->wakeup))
322 {
323 proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
324 if (!proclist_is_empty(&cv->wakeup))
325 {
326 proclist_push_tail(&cv->wakeup, pgprocno, cvWaitLink);
327 have_sentinel = true;
328 }
329 }
331
332 /* Awaken first waiter, if there was one. */
333 if (proc != NULL)
334 SetLatch(&proc->procLatch);
335
336 while (have_sentinel)
337 {
338 /*
339 * Each time through the loop, remove the first wakeup list entry, and
340 * signal it unless it's our sentinel. Repeat as long as the sentinel
341 * remains in the list.
342 *
343 * Notice that if someone else removes our sentinel, we will waken one
344 * additional process before exiting. That's intentional, because if
345 * someone else signals the CV, they may be intending to waken some
346 * third process that added itself to the list after we added the
347 * sentinel. Better to give a spurious wakeup (which should be
348 * harmless beyond wasting some cycles) than to lose a wakeup.
349 */
350 proc = NULL;
352 if (!proclist_is_empty(&cv->wakeup))
353 proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
354 have_sentinel = proclist_contains(&cv->wakeup, pgprocno, cvWaitLink);
356
357 if (proc != NULL && proc != MyProc)
358 SetLatch(&proc->procLatch);
359 }
360}
#define Assert(condition)
Definition: c.h:815
bool ConditionVariableCancelSleep(void)
static ConditionVariable * cv_sleep_target
ProcNumber MyProcNumber
Definition: globals.c:89
void SetLatch(Latch *latch)
Definition: latch.c:632
#define proclist_pop_head_node(list, link_member)
Definition: proclist.h:193
#define proclist_push_tail(list, procno, link_member)
Definition: proclist.h:191
#define proclist_contains(list, procno, link_member)
Definition: proclist.h:195
static bool proclist_is_empty(const proclist_head *list)
Definition: proclist.h:38
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
PGPROC * MyProc
Definition: proc.c:66
proclist_head wakeup
Definition: proc.h:162
Latch procLatch
Definition: proc.h:169

References Assert, ConditionVariableCancelSleep(), cv_sleep_target, ConditionVariable::mutex, MyProc, MyProcNumber, PGPROC::procLatch, proclist_contains, proclist_is_empty(), proclist_pop_head_node, proclist_push_tail, SetLatch(), SpinLockAcquire, SpinLockRelease, and ConditionVariable::wakeup.

Referenced by _bt_parallel_done(), BarrierArriveAndWait(), BarrierDetachImpl(), BitmapDoneInitializingSharedState(), CheckpointerMain(), CleanupProcSignalState(), injection_points_wakeup(), PhysicalWakeupLogicalWalSnd(), ProcessProcSignalBarrier(), RecordNewMultiXact(), ReplicationOriginExitCleanup(), ReplicationSlotAcquire(), ReplicationSlotCleanup(), ReplicationSlotCreate(), ReplicationSlotDropPtr(), ReplicationSlotRelease(), replorigin_session_reset(), replorigin_session_setup(), SetRecoveryPause(), ShutdownWalRcv(), TerminateBufferIO(), WalRcvDie(), WalRcvRunning(), WalRcvStreaming(), WalReceiverMain(), WalSndWakeup(), and WalSummarizerMain().

◆ ConditionVariableCancelSleep()

bool ConditionVariableCancelSleep ( void  )

Definition at line 230 of file condition_variable.c.

231{
233 bool signaled = false;
234
235 if (cv == NULL)
236 return false;
237
239 if (proclist_contains(&cv->wakeup, MyProcNumber, cvWaitLink))
240 proclist_delete(&cv->wakeup, MyProcNumber, cvWaitLink);
241 else
242 signaled = true;
244
245 cv_sleep_target = NULL;
246
247 return signaled;
248}
#define proclist_delete(list, procno, link_member)
Definition: proclist.h:187

References cv_sleep_target, ConditionVariable::mutex, MyProcNumber, proclist_contains, proclist_delete, SpinLockAcquire, SpinLockRelease, and ConditionVariable::wakeup.

Referenced by _brin_parallel_heapscan(), _bt_parallel_heapscan(), _bt_parallel_seize(), AbortSubTransaction(), AbortTransaction(), AuxiliaryProcKill(), BackgroundWriterMain(), BarrierArriveAndWait(), BitmapShouldInitializeSharedState(), CheckpointerMain(), ConditionVariableBroadcast(), ConditionVariablePrepareToSleep(), GetMultiXactIdMembers(), injection_wait(), pgarch_archiveXlog(), ProcKill(), recoveryPausesHere(), RecoveryRequiresIntParameter(), ReplicationSlotAcquire(), replorigin_state_clear(), RequestCheckpoint(), ShutdownAuxiliaryProcess(), ShutdownWalRcv(), WaitForProcSignalBarrier(), WaitForStandbyConfirmation(), WaitForWalSummarization(), WaitIO(), WalSndErrorCleanup(), WalSndWait(), WalSummarizerMain(), and WalWriterMain().

◆ ConditionVariableInit()

◆ ConditionVariablePrepareToSleep()

void ConditionVariablePrepareToSleep ( ConditionVariable cv)

Definition at line 56 of file condition_variable.c.

57{
58 int pgprocno = MyProcNumber;
59
60 /*
61 * If some other sleep is already prepared, cancel it; this is necessary
62 * because we have just one static variable tracking the prepared sleep,
63 * and also only one cvWaitLink in our PGPROC. It's okay to do this
64 * because whenever control does return to the other test-and-sleep loop,
65 * its ConditionVariableSleep call will just re-establish that sleep as
66 * the prepared one.
67 */
68 if (cv_sleep_target != NULL)
70
71 /* Record the condition variable on which we will sleep. */
72 cv_sleep_target = cv;
73
74 /* Add myself to the wait queue. */
76 proclist_push_tail(&cv->wakeup, pgprocno, cvWaitLink);
78}

References ConditionVariableCancelSleep(), cv_sleep_target, ConditionVariable::mutex, MyProcNumber, proclist_push_tail, SpinLockAcquire, SpinLockRelease, and ConditionVariable::wakeup.

Referenced by BarrierArriveAndWait(), ConditionVariableTimedSleep(), injection_wait(), InvalidatePossiblyObsoleteSlot(), ReplicationSlotAcquire(), RequestCheckpoint(), ShutdownWalRcv(), WaitForStandbyConfirmation(), WaitIO(), and WalSndWait().

◆ ConditionVariableSignal()

void ConditionVariableSignal ( ConditionVariable cv)

Definition at line 259 of file condition_variable.c.

260{
261 PGPROC *proc = NULL;
262
263 /* Remove the first process from the wakeup queue (if any). */
265 if (!proclist_is_empty(&cv->wakeup))
266 proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
268
269 /* If we found someone sleeping, set their latch to wake them up. */
270 if (proc != NULL)
271 SetLatch(&proc->procLatch);
272}

References ConditionVariable::mutex, PGPROC::procLatch, proclist_is_empty(), proclist_pop_head_node, SetLatch(), SpinLockAcquire, SpinLockRelease, and ConditionVariable::wakeup.

Referenced by _brin_parallel_scan_and_build(), _bt_parallel_release(), and _bt_parallel_scan_and_sort().

◆ ConditionVariableSleep()

void ConditionVariableSleep ( ConditionVariable cv,
uint32  wait_event_info 
)

◆ ConditionVariableTimedSleep()

bool ConditionVariableTimedSleep ( ConditionVariable cv,
long  timeout,
uint32  wait_event_info 
)

Definition at line 112 of file condition_variable.c.

114{
115 long cur_timeout = -1;
117 instr_time cur_time;
118 int wait_events;
119
120 /*
121 * If the caller didn't prepare to sleep explicitly, then do so now and
122 * return immediately. The caller's predicate loop should immediately
123 * call again if its exit condition is not yet met. This will result in
124 * the exit condition being tested twice before we first sleep. The extra
125 * test can be prevented by calling ConditionVariablePrepareToSleep(cv)
126 * first. Whether it's worth doing that depends on whether you expect the
127 * exit condition to be met initially, in which case skipping the prepare
128 * is recommended because it avoids manipulations of the wait list, or not
129 * met initially, in which case preparing first is better because it
130 * avoids one extra test of the exit condition.
131 *
132 * If we are currently prepared to sleep on some other CV, we just cancel
133 * that and prepare this one; see ConditionVariablePrepareToSleep.
134 */
135 if (cv_sleep_target != cv)
136 {
138 return false;
139 }
140
141 /*
142 * Record the current time so that we can calculate the remaining timeout
143 * if we are woken up spuriously.
144 */
145 if (timeout >= 0)
146 {
148 Assert(timeout >= 0 && timeout <= INT_MAX);
149 cur_timeout = timeout;
151 }
152 else
153 wait_events = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH;
154
155 while (true)
156 {
157 bool done = false;
158
159 /*
160 * Wait for latch to be set. (If we're awakened for some other
161 * reason, the code below will cope anyway.)
162 */
163 (void) WaitLatch(MyLatch, wait_events, cur_timeout, wait_event_info);
164
165 /* Reset latch before examining the state of the wait list. */
167
168 /*
169 * If this process has been taken out of the wait list, then we know
170 * that it has been signaled by ConditionVariableSignal (or
171 * ConditionVariableBroadcast), so we should return to the caller. But
172 * that doesn't guarantee that the exit condition is met, only that we
173 * ought to check it. So we must put the process back into the wait
174 * list, to ensure we don't miss any additional wakeup occurring while
175 * the caller checks its exit condition. We can take ourselves out of
176 * the wait list only when the caller calls
177 * ConditionVariableCancelSleep.
178 *
179 * If we're still in the wait list, then the latch must have been set
180 * by something other than ConditionVariableSignal; though we don't
181 * guarantee not to return spuriously, we'll avoid this obvious case.
182 */
184 if (!proclist_contains(&cv->wakeup, MyProcNumber, cvWaitLink))
185 {
186 done = true;
187 proclist_push_tail(&cv->wakeup, MyProcNumber, cvWaitLink);
188 }
190
191 /*
192 * Check for interrupts, and return spuriously if that caused the
193 * current sleep target to change (meaning that interrupt handler code
194 * waited for a different condition variable).
195 */
197 if (cv != cv_sleep_target)
198 done = true;
199
200 /* We were signaled, so return */
201 if (done)
202 return false;
203
204 /* If we're not done, update cur_timeout for next iteration */
205 if (timeout >= 0)
206 {
207 INSTR_TIME_SET_CURRENT(cur_time);
209 cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
210
211 /* Have we crossed the timeout threshold? */
212 if (cur_timeout <= 0)
213 return true;
214 }
215 }
216}
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
struct Latch * MyLatch
Definition: globals.c:62
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:191
void ResetLatch(Latch *latch)
Definition: latch.c:724
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:517
#define WL_TIMEOUT
Definition: latch.h:130
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:132
#define WL_LATCH_SET
Definition: latch.h:127
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static time_t start_time
Definition: pg_ctl.c:95

References Assert, CHECK_FOR_INTERRUPTS, ConditionVariablePrepareToSleep(), cv_sleep_target, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, ConditionVariable::mutex, MyLatch, MyProcNumber, proclist_contains, proclist_push_tail, ResetLatch(), SpinLockAcquire, SpinLockRelease, start_time, WaitLatch(), ConditionVariable::wakeup, WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

Referenced by ConditionVariableSleep(), recoveryPausesHere(), RecoveryRequiresIntParameter(), WaitForProcSignalBarrier(), WaitForStandbyConfirmation(), and WaitForWalSummarization().