@@ -43,11 +43,22 @@ ConditionVariableInit(ConditionVariable *cv)
4343}
4444
4545/*
46- * Prepare to wait on a given condition variable. This can optionally be
47- * called before entering a test/sleep loop. Alternatively, the call to
48- * ConditionVariablePrepareToSleep can be omitted. The only advantage of
49- * calling ConditionVariablePrepareToSleep is that it avoids an initial
50- * double-test of the user's predicate in the case that we need to wait.
46+ * Prepare to wait on a given condition variable.
47+ *
48+ * This can optionally be called before entering a test/sleep loop.
49+ * Doing so is more efficient if we'll need to sleep at least once.
50+ * However, if the first test of the exit condition is likely to succeed,
51+ * it's more efficient to omit the ConditionVariablePrepareToSleep call.
52+ * See comments in ConditionVariableSleep for more detail.
53+ *
54+ * Caution: "before entering the loop" means you *must* test the exit
55+ * condition between calling ConditionVariablePrepareToSleep and calling
56+ * ConditionVariableSleep. If that is inconvenient, omit calling
57+ * ConditionVariablePrepareToSleep.
58+ *
59+ * Only one condition variable can be used at a time, ie,
60+ * ConditionVariableCancelSleep must be called before any attempt is made
61+ * to sleep on a different condition variable.
5162 */
5263void
5364ConditionVariablePrepareToSleep (ConditionVariable * cv )
@@ -79,8 +90,8 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
7990 cv_sleep_target = cv ;
8091
8192 /*
82- * Reset my latch before adding myself to the queue and before entering
83- * the caller's predicate loop .
93+ * Reset my latch before adding myself to the queue, to ensure that we
94+ * don't miss a wakeup that occurs immediately .
8495 */
8596 ResetLatch (MyLatch );
8697
@@ -90,20 +101,21 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
90101 SpinLockRelease (& cv -> mutex );
91102}
92103
93- /*--------------------------------------------------------------------------
94- * Wait for the given condition variable to be signaled. This should be
95- * called in a predicate loop that tests for a specific exit condition and
96- * otherwise sleeps, like so:
104+ /*
105+ * Wait for the given condition variable to be signaled.
106+ *
107+ * This should be called in a predicate loop that tests for a specific exit
108+ * condition and otherwise sleeps, like so:
97109 *
98- * ConditionVariablePrepareToSleep(cv); [ optional]
110+ * ConditionVariablePrepareToSleep(cv); // optional
99111 * while (condition for which we are waiting is not true)
100112 * ConditionVariableSleep(cv, wait_event_info);
101113 * ConditionVariableCancelSleep();
102114 *
103- * Supply a value from one of the WaitEventXXX enums defined in pgstat.h to
104- * control the contents of pg_stat_activity's wait_event_type and wait_event
105- * columns while waiting.
106- *-------------------------------------------------------------------------* /
115+ * wait_event_info should be a value from one of the WaitEventXXX enums
116+ * defined in pgstat.h. This controls the contents of pg_stat_activity's
117+ * wait_event_type and wait_event columns while waiting.
118+ */
107119void
108120ConditionVariableSleep (ConditionVariable * cv , uint32 wait_event_info )
109121{
@@ -113,13 +125,14 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
113125 /*
114126 * If the caller didn't prepare to sleep explicitly, then do so now and
115127 * return immediately. The caller's predicate loop should immediately
116- * call again if its exit condition is not yet met. This initial spurious
117- * return can be avoided by calling ConditionVariablePrepareToSleep(cv)
128+ * call again if its exit condition is not yet met. This will result in
129+ * the exit condition being tested twice before we first sleep. The extra
130+ * test can be prevented by calling ConditionVariablePrepareToSleep(cv)
118131 * first. Whether it's worth doing that depends on whether you expect the
119- * condition to be met initially, in which case skipping the prepare
120- * allows you to skip manipulation of the wait list, or not met initially,
121- * in which case preparing first allows you to skip a spurious test of the
122- * caller's exit condition.
132+ * exit condition to be met initially, in which case skipping the prepare
133+ * is recommended because it avoids manipulations of the wait list, or not
134+ * met initially, in which case preparing first is better because it
135+ * avoids one extra test of the exit condition.
123136 */
124137 if (cv_sleep_target == NULL )
125138 {
@@ -130,7 +143,7 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
130143 /* Any earlier condition variable sleep must have been canceled. */
131144 Assert (cv_sleep_target == cv );
132145
133- while (! done )
146+ do
134147 {
135148 CHECK_FOR_INTERRUPTS ();
136149
@@ -140,18 +153,23 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
140153 */
141154 WaitEventSetWait (cv_wait_event_set , -1 , & event , 1 , wait_event_info );
142155
143- /* Reset latch before testing whether we can return . */
156+ /* Reset latch before examining the state of the wait list . */
144157 ResetLatch (MyLatch );
145158
146159 /*
147160 * If this process has been taken out of the wait list, then we know
148- * that is has been signaled by ConditionVariableSignal. We put it
149- * back into the wait list, so we don't miss any further signals while
150- * the caller's loop checks its condition. If it hasn't been taken
151- * out of the wait list, then the latch must have been set by
152- * something other than ConditionVariableSignal; though we don't
153- * guarantee not to return spuriously, we'll avoid these obvious
154- * cases.
161+ * that it has been signaled by ConditionVariableSignal (or
162+ * ConditionVariableBroadcast), so we should return to the caller. But
163+ * that doesn't guarantee that the exit condition is met, only that we
164+ * ought to check it. So we must put the process back into the wait
165+ * list, to ensure we don't miss any additional wakeup occurring while
166+ * the caller checks its exit condition. We can take ourselves out of
167+ * the wait list only when the caller calls
168+ * ConditionVariableCancelSleep.
169+ *
170+ * If we're still in the wait list, then the latch must have been set
171+ * by something other than ConditionVariableSignal; though we don't
172+ * guarantee not to return spuriously, we'll avoid this obvious case.
155173 */
156174 SpinLockAcquire (& cv -> mutex );
157175 if (!proclist_contains (& cv -> wakeup , MyProc -> pgprocno , cvWaitLink ))
@@ -160,13 +178,17 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
160178 proclist_push_tail (& cv -> wakeup , MyProc -> pgprocno , cvWaitLink );
161179 }
162180 SpinLockRelease (& cv -> mutex );
163- }
181+ } while (! done );
164182}
165183
166184/*
167- * Cancel any pending sleep operation. We just need to remove ourselves
168- * from the wait queue of any condition variable for which we have previously
169- * prepared a sleep.
185+ * Cancel any pending sleep operation.
186+ *
187+ * We just need to remove ourselves from the wait queue of any condition
188+ * variable for which we have previously prepared a sleep.
189+ *
190+ * Do nothing if nothing is pending; this allows this function to be called
191+ * during transaction abort to clean up any unfinished CV sleep.
170192 */
171193void
172194ConditionVariableCancelSleep (void )
0 commit comments