PostgreSQL Source Code  git master
condition_variable.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * condition_variable.c
4  * Implementation of condition variables. Condition variables provide
5  * a way for one process to wait until a specific condition occurs,
6  * without needing to know the specific identity of the process for
7  * which they are waiting. Waits for condition variables can be
8  * interrupted, unlike LWLock waits. Condition variables are safe
9  * to use within dynamic shared memory segments.
10  *
11  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  * src/backend/storage/lmgr/condition_variable.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 
19 #include "postgres.h"
20 
21 #include "miscadmin.h"
22 #include "portability/instr_time.h"
24 #include "storage/ipc.h"
25 #include "storage/proc.h"
26 #include "storage/proclist.h"
27 #include "storage/spin.h"
28 #include "utils/memutils.h"
29 
30 /* Initially, we are not prepared to sleep on any condition variable. */
32 
33 /* Reusable WaitEventSet. */
35 
36 /*
37  * Initialize a condition variable.
38  */
39 void
41 {
42  SpinLockInit(&cv->mutex);
43  proclist_init(&cv->wakeup);
44 }
45 
46 /*
47  * Prepare to wait on a given condition variable.
48  *
49  * This can optionally be called before entering a test/sleep loop.
50  * Doing so is more efficient if we'll need to sleep at least once.
51  * However, if the first test of the exit condition is likely to succeed,
52  * it's more efficient to omit the ConditionVariablePrepareToSleep call.
53  * See comments in ConditionVariableSleep for more detail.
54  *
55  * Caution: "before entering the loop" means you *must* test the exit
56  * condition between calling ConditionVariablePrepareToSleep and calling
57  * ConditionVariableSleep. If that is inconvenient, omit calling
58  * ConditionVariablePrepareToSleep.
59  */
60 void
62 {
63  int pgprocno = MyProc->pgprocno;
64 
65  /*
66  * If first time through in this process, create a WaitEventSet, which
67  * we'll reuse for all condition variable sleeps.
68  */
69  if (cv_wait_event_set == NULL)
70  {
71  WaitEventSet *new_event_set;
72 
73  new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
75  MyLatch, NULL);
77  NULL, NULL);
78  /* Don't set cv_wait_event_set until we have a correct WES. */
79  cv_wait_event_set = new_event_set;
80  }
81 
82  /*
83  * If some other sleep is already prepared, cancel it; this is necessary
84  * because we have just one static variable tracking the prepared sleep,
85  * and also only one cvWaitLink in our PGPROC. It's okay to do this
86  * because whenever control does return to the other test-and-sleep loop,
87  * its ConditionVariableSleep call will just re-establish that sleep as
88  * the prepared one.
89  */
90  if (cv_sleep_target != NULL)
92 
93  /* Record the condition variable on which we will sleep. */
94  cv_sleep_target = cv;
95 
96  /*
97  * Reset my latch before adding myself to the queue, to ensure that we
98  * don't miss a wakeup that occurs immediately.
99  */
101 
102  /* Add myself to the wait queue. */
103  SpinLockAcquire(&cv->mutex);
104  proclist_push_tail(&cv->wakeup, pgprocno, cvWaitLink);
105  SpinLockRelease(&cv->mutex);
106 }
107 
108 /*
109  * Wait for the given condition variable to be signaled.
110  *
111  * This should be called in a predicate loop that tests for a specific exit
112  * condition and otherwise sleeps, like so:
113  *
114  * ConditionVariablePrepareToSleep(cv); // optional
115  * while (condition for which we are waiting is not true)
116  * ConditionVariableSleep(cv, wait_event_info);
117  * ConditionVariableCancelSleep();
118  *
119  * wait_event_info should be a value from one of the WaitEventXXX enums
120  * defined in pgstat.h. This controls the contents of pg_stat_activity's
121  * wait_event_type and wait_event columns while waiting.
122  */
123 void
125 {
126  (void) ConditionVariableTimedSleep(cv, -1 /* no timeout */ ,
127  wait_event_info);
128 }
129 
130 /*
131  * Wait for a condition variable to be signaled or a timeout to be reached.
132  *
133  * Returns true when timeout expires, otherwise returns false.
134  *
135  * See ConditionVariableSleep() for general usage.
136  */
137 bool
139  uint32 wait_event_info)
140 {
141  long cur_timeout = -1;
143  instr_time cur_time;
144 
145  /*
146  * If the caller didn't prepare to sleep explicitly, then do so now and
147  * return immediately. The caller's predicate loop should immediately
148  * call again if its exit condition is not yet met. This will result in
149  * the exit condition being tested twice before we first sleep. The extra
150  * test can be prevented by calling ConditionVariablePrepareToSleep(cv)
151  * first. Whether it's worth doing that depends on whether you expect the
152  * exit condition to be met initially, in which case skipping the prepare
153  * is recommended because it avoids manipulations of the wait list, or not
154  * met initially, in which case preparing first is better because it
155  * avoids one extra test of the exit condition.
156  *
157  * If we are currently prepared to sleep on some other CV, we just cancel
158  * that and prepare this one; see ConditionVariablePrepareToSleep.
159  */
160  if (cv_sleep_target != cv)
161  {
163  return false;
164  }
165 
166  /*
167  * Record the current time so that we can calculate the remaining timeout
168  * if we are woken up spuriously.
169  */
170  if (timeout >= 0)
171  {
172  INSTR_TIME_SET_CURRENT(start_time);
173  Assert(timeout >= 0 && timeout <= INT_MAX);
174  cur_timeout = timeout;
175  }
176 
177  while (true)
178  {
179  WaitEvent event;
180  bool done = false;
181 
182  /*
183  * Wait for latch to be set. (If we're awakened for some other
184  * reason, the code below will cope anyway.)
185  */
186  (void) WaitEventSetWait(cv_wait_event_set, cur_timeout, &event, 1,
187  wait_event_info);
188 
189  /* Reset latch before examining the state of the wait list. */
191 
193 
194  /*
195  * If this process has been taken out of the wait list, then we know
196  * that it has been signaled by ConditionVariableSignal (or
197  * ConditionVariableBroadcast), so we should return to the caller. But
198  * that doesn't guarantee that the exit condition is met, only that we
199  * ought to check it. So we must put the process back into the wait
200  * list, to ensure we don't miss any additional wakeup occurring while
201  * the caller checks its exit condition. We can take ourselves out of
202  * the wait list only when the caller calls
203  * ConditionVariableCancelSleep.
204  *
205  * If we're still in the wait list, then the latch must have been set
206  * by something other than ConditionVariableSignal; though we don't
207  * guarantee not to return spuriously, we'll avoid this obvious case.
208  */
209  SpinLockAcquire(&cv->mutex);
210  if (!proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink))
211  {
212  done = true;
213  proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
214  }
215  SpinLockRelease(&cv->mutex);
216 
217  /* We were signaled, so return */
218  if (done)
219  return false;
220 
221  /* If we're not done, update cur_timeout for next iteration */
222  if (timeout >= 0)
223  {
224  INSTR_TIME_SET_CURRENT(cur_time);
225  INSTR_TIME_SUBTRACT(cur_time, start_time);
226  cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
227 
228  /* Have we crossed the timeout threshold? */
229  if (cur_timeout <= 0)
230  return true;
231  }
232  }
233 }
234 
235 /*
236  * Cancel any pending sleep operation.
237  *
238  * We just need to remove ourselves from the wait queue of any condition
239  * variable for which we have previously prepared a sleep.
240  *
241  * Do nothing if nothing is pending; this allows this function to be called
242  * during transaction abort to clean up any unfinished CV sleep.
243  */
244 void
246 {
248  bool signaled = false;
249 
250  if (cv == NULL)
251  return;
252 
253  SpinLockAcquire(&cv->mutex);
254  if (proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink))
255  proclist_delete(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
256  else
257  signaled = true;
258  SpinLockRelease(&cv->mutex);
259 
260  /*
261  * If we've received a signal, pass it on to another waiting process, if
262  * there is one. Otherwise a call to ConditionVariableSignal() might get
263  * lost, despite there being another process ready to handle it.
264  */
265  if (signaled)
267 
268  cv_sleep_target = NULL;
269 }
270 
271 /*
272  * Wake up the oldest process sleeping on the CV, if there is any.
273  *
274  * Note: it's difficult to tell whether this has any real effect: we know
275  * whether we took an entry off the list, but the entry might only be a
276  * sentinel. Hence, think twice before proposing that this should return
277  * a flag telling whether it woke somebody.
278  */
279 void
281 {
282  PGPROC *proc = NULL;
283 
284  /* Remove the first process from the wakeup queue (if any). */
285  SpinLockAcquire(&cv->mutex);
286  if (!proclist_is_empty(&cv->wakeup))
287  proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
288  SpinLockRelease(&cv->mutex);
289 
290  /* If we found someone sleeping, set their latch to wake them up. */
291  if (proc != NULL)
292  SetLatch(&proc->procLatch);
293 }
294 
295 /*
296  * Wake up all processes sleeping on the given CV.
297  *
298  * This guarantees to wake all processes that were sleeping on the CV
299  * at time of call, but processes that add themselves to the list mid-call
300  * will typically not get awakened.
301  */
302 void
304 {
305  int pgprocno = MyProc->pgprocno;
306  PGPROC *proc = NULL;
307  bool have_sentinel = false;
308 
309  /*
310  * In some use-cases, it is common for awakened processes to immediately
311  * re-queue themselves. If we just naively try to reduce the wakeup list
312  * to empty, we'll get into a potentially-indefinite loop against such a
313  * process. The semantics we really want are just to be sure that we have
314  * wakened all processes that were in the list at entry. We can use our
315  * own cvWaitLink as a sentinel to detect when we've finished.
316  *
317  * A seeming flaw in this approach is that someone else might signal the
318  * CV and in doing so remove our sentinel entry. But that's fine: since
319  * CV waiters are always added and removed in order, that must mean that
320  * every previous waiter has been wakened, so we're done. We'll get an
321  * extra "set" on our latch from the someone else's signal, which is
322  * slightly inefficient but harmless.
323  *
324  * We can't insert our cvWaitLink as a sentinel if it's already in use in
325  * some other proclist. While that's not expected to be true for typical
326  * uses of this function, we can deal with it by simply canceling any
327  * prepared CV sleep. The next call to ConditionVariableSleep will take
328  * care of re-establishing the lost state.
329  */
330  if (cv_sleep_target != NULL)
332 
333  /*
334  * Inspect the state of the queue. If it's empty, we have nothing to do.
335  * If there's exactly one entry, we need only remove and signal that
336  * entry. Otherwise, remove the first entry and insert our sentinel.
337  */
338  SpinLockAcquire(&cv->mutex);
339  /* While we're here, let's assert we're not in the list. */
340  Assert(!proclist_contains(&cv->wakeup, pgprocno, cvWaitLink));
341 
342  if (!proclist_is_empty(&cv->wakeup))
343  {
344  proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
345  if (!proclist_is_empty(&cv->wakeup))
346  {
347  proclist_push_tail(&cv->wakeup, pgprocno, cvWaitLink);
348  have_sentinel = true;
349  }
350  }
351  SpinLockRelease(&cv->mutex);
352 
353  /* Awaken first waiter, if there was one. */
354  if (proc != NULL)
355  SetLatch(&proc->procLatch);
356 
357  while (have_sentinel)
358  {
359  /*
360  * Each time through the loop, remove the first wakeup list entry, and
361  * signal it unless it's our sentinel. Repeat as long as the sentinel
362  * remains in the list.
363  *
364  * Notice that if someone else removes our sentinel, we will waken one
365  * additional process before exiting. That's intentional, because if
366  * someone else signals the CV, they may be intending to waken some
367  * third process that added itself to the list after we added the
368  * sentinel. Better to give a spurious wakeup (which should be
369  * harmless beyond wasting some cycles) than to lose a wakeup.
370  */
371  proc = NULL;
372  SpinLockAcquire(&cv->mutex);
373  if (!proclist_is_empty(&cv->wakeup))
374  proc = proclist_pop_head_node(&cv->wakeup, cvWaitLink);
375  have_sentinel = proclist_contains(&cv->wakeup, pgprocno, cvWaitLink);
376  SpinLockRelease(&cv->mutex);
377 
378  if (proc != NULL && proc != MyProc)
379  SetLatch(&proc->procLatch);
380  }
381 }
int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch, void *user_data)
Definition: latch.c:690
proclist_head wakeup
PGPROC * MyProc
Definition: proc.c:68
#define SpinLockInit(lock)
Definition: spin.h:60
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
struct timeval instr_time
Definition: instr_time.h:150
static WaitEventSet * cv_wait_event_set
void ConditionVariableBroadcast(ConditionVariable *cv)
void SetLatch(Latch *latch)
Definition: latch.c:436
#define proclist_delete(list, procno, link_member)
Definition: proclist.h:187
void ResetLatch(Latch *latch)
Definition: latch.c:519
Latch procLatch
Definition: proc.h:104
static time_t start_time
Definition: pg_ctl.c:99
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
WaitEventSet * CreateWaitEventSet(MemoryContext context, int nevents)
Definition: latch.c:542
#define SpinLockAcquire(lock)
Definition: spin.h:62
void ConditionVariableInit(ConditionVariable *cv)
void ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
void ConditionVariableSignal(ConditionVariable *cv)
unsigned int uint32
Definition: c.h:358
MemoryContext TopMemoryContext
Definition: mcxt.c:44
#define SpinLockRelease(lock)
Definition: spin.h:64
#define PGINVALID_SOCKET
Definition: port.h:33
static ConditionVariable * cv_sleep_target
#define proclist_pop_head_node(list, link_member)
Definition: proclist.h:193
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
#define Assert(condition)
Definition: c.h:732
static bool proclist_is_empty(proclist_head *list)
Definition: proclist.h:38
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define proclist_push_tail(list, procno, link_member)
Definition: proclist.h:191
int pgprocno
Definition: proc.h:110
static void proclist_init(proclist_head *list)
Definition: proclist.h:29
struct Latch * MyLatch
Definition: globals.c:54
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
Definition: proc.h:95
#define WL_LATCH_SET
Definition: latch.h:124
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:129
static volatile sig_atomic_t signaled
Definition: pg_standby.c:53
int WaitEventSetWait(WaitEventSet *set, long timeout, WaitEvent *occurred_events, int nevents, uint32 wait_event_info)
Definition: latch.c:953
#define proclist_contains(list, procno, link_member)
Definition: proclist.h:195