108 lines
4.5 KiB
Diff
108 lines
4.5 KiB
Diff
commit 4f7b051f8ee3feff1b53b27a906f245afaa9cee1
|
|
Author: Malte Skarupke <malteskarupke@fastmail.fm>
|
|
Date: Wed Dec 4 07:56:13 2024 -0500
|
|
|
|
nptl: Remove unnecessary quadruple check in pthread_cond_wait
|
|
|
|
pthread_cond_wait was checking whether it was in a closed group no less than
|
|
four times. Checking once is enough. Here are the four checks:
|
|
|
|
1. While spin-waiting. This was dead code: maxspin is set to 0 and has been
|
|
for years.
|
|
2. Before deciding to go to sleep, and before incrementing grefs: I kept this
|
|
3. After incrementing grefs. There is no reason to think that the group would
|
|
close while we do an atomic increment. Obviously it could close at any
|
|
point, but that doesn't mean we have to recheck after every step. This
|
|
check was equally good as check 2, except it has to do more work.
|
|
4. When we find ourselves in a group that has a signal. We only get here after
|
|
we check that we're not in a closed group. There is no need to check again.
|
|
The check would only have helped in cases where the compare_exchange in the
|
|
next line would also have failed. Relying on the compare_exchange is fine.
|
|
|
|
Removing the duplicate checks clarifies the code.
|
|
|
|
Signed-off-by: Malte Skarupke <malteskarupke@fastmail.fm>
|
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
|
|
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
|
|
index 7dabcb15d2d818e7..ba9a19bedc2c176f 100644
|
|
--- a/nptl/pthread_cond_wait.c
|
|
+++ b/nptl/pthread_cond_wait.c
|
|
@@ -367,7 +367,6 @@ static __always_inline int
|
|
__pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|
clockid_t clockid, const struct __timespec64 *abstime)
|
|
{
|
|
- const int maxspin = 0;
|
|
int err;
|
|
int result = 0;
|
|
|
|
@@ -426,33 +425,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|
uint64_t g1_start = __condvar_load_g1_start_relaxed (cond);
|
|
unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
|
|
|
|
- /* Spin-wait first.
|
|
- Note that spinning first without checking whether a timeout
|
|
- passed might lead to what looks like a spurious wake-up even
|
|
- though we should return ETIMEDOUT (e.g., if the caller provides
|
|
- an absolute timeout that is clearly in the past). However,
|
|
- (1) spurious wake-ups are allowed, (2) it seems unlikely that a
|
|
- user will (ab)use pthread_cond_wait as a check for whether a
|
|
- point in time is in the past, and (3) spinning first without
|
|
- having to compare against the current time seems to be the right
|
|
- choice from a performance perspective for most use cases. */
|
|
- unsigned int spin = maxspin;
|
|
- while (spin > 0 && ((int)(signals - lowseq) < 2))
|
|
- {
|
|
- /* Check that we are not spinning on a group that's already
|
|
- closed. */
|
|
- if (seq < (g1_start >> 1))
|
|
- break;
|
|
-
|
|
- /* TODO Back off. */
|
|
-
|
|
- /* Reload signals. See above for MO. */
|
|
- signals = atomic_load_acquire (cond->__data.__g_signals + g);
|
|
- g1_start = __condvar_load_g1_start_relaxed (cond);
|
|
- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
|
|
- spin--;
|
|
- }
|
|
-
|
|
if (seq < (g1_start >> 1))
|
|
{
|
|
/* If the group is closed already,
|
|
@@ -483,24 +455,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|
an atomic read-modify-write operation and thus extend the release
|
|
sequence. */
|
|
atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2);
|
|
- signals = atomic_load_acquire (cond->__data.__g_signals + g);
|
|
- g1_start = __condvar_load_g1_start_relaxed (cond);
|
|
- lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
|
|
-
|
|
- if (seq < (g1_start >> 1))
|
|
- {
|
|
- /* group is closed already, so don't block */
|
|
- __condvar_dec_grefs (cond, g, private);
|
|
- goto done;
|
|
- }
|
|
-
|
|
- if ((int)(signals - lowseq) >= 2)
|
|
- {
|
|
- /* a signal showed up or G1/G2 switched after we grabbed the
|
|
- refcount */
|
|
- __condvar_dec_grefs (cond, g, private);
|
|
- break;
|
|
- }
|
|
|
|
// Now block.
|
|
struct _pthread_cleanup_buffer buffer;
|
|
@@ -534,9 +488,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|
/* Reload signals. See above for MO. */
|
|
signals = atomic_load_acquire (cond->__data.__g_signals + g);
|
|
}
|
|
-
|
|
- if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1))
|
|
- goto done;
|
|
}
|
|
/* Try to grab a signal. See above for MO. (if we do another loop
|
|
iteration we need to see the correct value of g1_start) */
|