mirror of
https://github.com/postgres/postgres.git
synced 2026-02-17 01:31:07 -05:00
The original coding here insisted that callers manually cancel any prepared
sleep for one condition variable before starting a sleep on another one.
While that's not a huge burden today, it seems like a gotcha that will bite
us in future if the use of condition variables increases; anything we can
do to make the use of this API simpler and more robust is attractive.
Hence, allow these functions to automatically switch their attention to
a different CV when required. This is safe for the same reason it was OK
for commit aced5a92b to let a broadcast operation cancel any prepared CV
sleep: whenever we return to the other test-and-sleep loop, we will
automatically re-prepare that CV, paying at most an extra test of that
loop's exit condition.
Back-patch to v10 where condition variables were introduced. Ordinarily
we would probably not back-patch a change like this, but since it does not
invalidate any coding pattern that was legal before, it seems safe enough.
Furthermore, there's an open bug in replorigin_drop() for which the
simplest fix requires this. Even if we chose to fix that in some more
complicated way, the hazard would remain that we might back-patch some
other bug fix that requires this behavior.
Patch by me, reviewed by Thomas Munro.
Discussion: https://postgr.es/m/2437.1515368316@sss.pgh.pa.us
60 lines
2.5 KiB
C
60 lines
2.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* condition_variable.h
|
|
* Condition variables
|
|
*
|
|
* A condition variable is a method of waiting until a certain condition
|
|
* becomes true. Conventionally, a condition variable supports three
|
|
* operations: (1) sleep; (2) signal, which wakes up one process sleeping
|
|
* on the condition variable; and (3) broadcast, which wakes up every
|
|
* process sleeping on the condition variable. In our implementation,
|
|
* condition variables put a process into an interruptible sleep (so it
|
|
* can be cancelled prior to the fulfillment of the condition) and do not
|
|
* use pointers internally (so that they are safe to use within DSMs).
|
|
*
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/storage/condition_variable.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef CONDITION_VARIABLE_H
|
|
#define CONDITION_VARIABLE_H
|
|
|
|
#include "storage/s_lock.h"
|
|
#include "storage/proclist_types.h"
|
|
|
|
typedef struct
|
|
{
|
|
slock_t mutex; /* spinlock protecting the wakeup list */
|
|
proclist_head wakeup; /* list of wake-able processes */
|
|
} ConditionVariable;
|
|
|
|
/* Initialize a condition variable. */
|
|
extern void ConditionVariableInit(ConditionVariable *cv);
|
|
|
|
/*
|
|
* To sleep on a condition variable, a process should use a loop which first
|
|
* checks the condition, exiting the loop if it is met, and then calls
|
|
* ConditionVariableSleep. Spurious wakeups are possible, but should be
|
|
* infrequent. After exiting the loop, ConditionVariableCancelSleep must
|
|
* be called to ensure that the process is no longer in the wait list for
|
|
* the condition variable.
|
|
*/
|
|
extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info);
|
|
extern void ConditionVariableCancelSleep(void);
|
|
|
|
/*
|
|
* Optionally, ConditionVariablePrepareToSleep can be called before entering
|
|
* the test-and-sleep loop described above. Doing so is more efficient if
|
|
* at least one sleep is needed, whereas not doing so is more efficient when
|
|
* no sleep is needed because the test condition is true the first time.
|
|
*/
|
|
extern void ConditionVariablePrepareToSleep(ConditionVariable *cv);
|
|
|
|
/* Wake up a single waiter (via signal) or all waiters (via broadcast). */
|
|
extern void ConditionVariableSignal(ConditionVariable *cv);
|
|
extern void ConditionVariableBroadcast(ConditionVariable *cv);
|
|
|
|
#endif /* CONDITION_VARIABLE_H */
|