Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite35dba4

Browse files
committed
Cosmetic improvements in condition_variable.[hc].
Clarify a bunch of comments.Discussion:https://postgr.es/m/CAEepm=0NWKehYw7NDoUSf8juuKOPRnCyY3vuaSvhrEWsOTAa3w@mail.gmail.com
1 parentea8e1bb commite35dba4

File tree

2 files changed

+70
-45
lines changed

2 files changed

+70
-45
lines changed

‎src/backend/storage/lmgr/condition_variable.c

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
5263
void
5364
ConditionVariablePrepareToSleep(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-
*Supplya value from one of the WaitEventXXX enums defined in pgstat.h to
104-
*controlthe contents of pg_stat_activity's wait_event_type and wait_event
105-
* columns while waiting.
106-
*-------------------------------------------------------------------------*/
115+
*wait_event_info should bea value from one of the WaitEventXXX enums
116+
*defined in pgstat.h. This controlsthe contents of pg_stat_activity's
117+
*wait_event_type and wait_eventcolumns while waiting.
118+
*/
107119
void
108120
ConditionVariableSleep(ConditionVariable*cv,uint32wait_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 manipulationof the wait list, or not met initially,
121-
* in which case preparing firstallows you to skip a spurious test of the
122-
*caller's exit condition.
132+
*exitcondition to be met initially, in which case skipping the prepare
133+
*is recommended because it avoids manipulationsof the wait list, or not
134+
*met initially,in which case preparing firstis 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 beforetesting whether we can return. */
156+
/* Reset latch beforeexamining 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
*/
171193
void
172194
ConditionVariableCancelSleep(void)

‎src/include/storage/condition_variable.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,33 @@
2727

2828
typedefstruct
2929
{
30-
slock_tmutex;
31-
proclist_headwakeup;
30+
slock_tmutex;/* spinlock protecting the wakeup list */
31+
proclist_headwakeup;/* list of wake-able processes */
3232
}ConditionVariable;
3333

3434
/* Initialize a condition variable. */
35-
externvoidConditionVariableInit(ConditionVariable*);
35+
externvoidConditionVariableInit(ConditionVariable*cv);
3636

3737
/*
3838
* To sleep on a condition variable, a process should use a loop which first
3939
* checks the condition, exiting the loop if it is met, and then calls
4040
* ConditionVariableSleep. Spurious wakeups are possible, but should be
41-
* infrequent. After exiting the loop, ConditionVariableCancelSleepshould
41+
* infrequent. After exiting the loop, ConditionVariableCancelSleepmust
4242
* be called to ensure that the process is no longer in the wait list for
43-
* the condition variable.
43+
* the condition variable. Only one condition variable can be used at a
44+
* time, ie, ConditionVariableCancelSleep must be called before any attempt
45+
* is made to sleep on a different condition variable.
4446
*/
45-
externvoidConditionVariableSleep(ConditionVariable*,uint32wait_event_info);
47+
externvoidConditionVariableSleep(ConditionVariable*cv,uint32wait_event_info);
4648
externvoidConditionVariableCancelSleep(void);
4749

4850
/*
49-
* The use of this function is optional and not necessary for correctness;
50-
* for efficiency, it should be called prior entering the loop described above
51-
* if it is thought that the condition is unlikely to hold immediately.
51+
* Optionally, ConditionVariablePrepareToSleep can be called before entering
52+
* the test-and-sleep loop described above. Doing so is more efficient if
53+
* at least one sleep is needed, whereas not doing so is more efficient when
54+
* no sleep is needed because the test condition is true the first time.
5255
*/
53-
externvoidConditionVariablePrepareToSleep(ConditionVariable*);
56+
externvoidConditionVariablePrepareToSleep(ConditionVariable*cv);
5457

5558
/* Wake up a single waiter (via signal) or all waiters (via broadcast). */
5659
externvoidConditionVariableSignal(ConditionVariable*cv);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp