diff options
author | Ulrich Drepper <drepper@redhat.com> | 2003-01-02 11:01:30 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2003-01-02 11:01:30 +0000 |
commit | 05df18c3475157cda8126a07b5bb0f52082a0b67 (patch) | |
tree | ad9be04821a2ec180444af2c737d104141857206 /nptl/DESIGN-condvar.txt | |
parent | caf7a872326ee21ad20698baa62ca5599a46d866 (diff) | |
download | glibc-05df18c3475157cda8126a07b5bb0f52082a0b67.tar glibc-05df18c3475157cda8126a07b5bb0f52082a0b67.tar.gz glibc-05df18c3475157cda8126a07b5bb0f52082a0b67.tar.bz2 glibc-05df18c3475157cda8126a07b5bb0f52082a0b67.zip |
Update.
2003-01-02 Ulrich Drepper <drepper@redhat.com>
* sysdeps/pthread/bits/pthreadtypes.h (pthread_cond_t): Add padding.
* condvar.c: Add symbol versioning. The compatibility versions
are the same as the change in the interface does not effect this
implementation.
* Versions [libpthread]: Add definitions for new pthread_cond_*
interfaces for version GLIBC_2.3.2.
Diffstat (limited to 'nptl/DESIGN-condvar.txt')
-rw-r--r-- | nptl/DESIGN-condvar.txt | 101 |
1 files changed, 60 insertions, 41 deletions
diff --git a/nptl/DESIGN-condvar.txt b/nptl/DESIGN-condvar.txt index 303807be6d..749180ed4b 100644 --- a/nptl/DESIGN-condvar.txt +++ b/nptl/DESIGN-condvar.txt @@ -7,49 +7,78 @@ Conditional Variable pseudocode. struct pthread_cond_t { - unsigned int lock: + unsigned int cond_lock; internal mutex - unsigned int nr_wakers: + uint64_t total_seq; - number of threads signalled to be woken up. + Total number of threads using the conditional variable. - unsigned int nr_sleepers: + uint64_t wakeup_seq; - number of threads waiting for the cv. + sequence number for next wakeup. + + uint64_t woken_seq; + + sequence number of last woken thread. } -#define ALL_THREADS (1 << (BITS_PER_LONG-1)) -cond_wait_timeout(cv, mutex, timeout): + +cleanup_handler(cv) +{ + lll_lock(cv->lock); + + ++cv->wakeup_seq; + ++cv->woken_seq; + + lll_unlock(cv->lock); +} + + +cond_timedwait(cv, mutex, timeout): { lll_lock(cv->lock); mutex_unlock(mutex); - cv->nr_sleepers++; - for (;;) { + cleanup_push + + ++cv->total_seq; + val = seq = cv->wakeup_seq; + + while (1) { + + lll_unlock(cv->lock); + + enable_async - if (cv->nr_wakers) { - cv->nr_wakers--; - break; - } - val = cv->nr_wakers; + ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout); - lll_unlock(cv->lock); + restore_async - ret = FUTEX WAIT (cv->nr_wakers, val, timeout) + lll_lock(cv->lock); - lll_lock(cv->lock); + val = cv->wakeup_seq; - if (ret == TIMEOUT) - break; + if (cv->woken_seq >= seq && cv->woken_seq < val) { ret = 0; + break; + } + + if (ret == TIMEDOUT) { + ++cv->wakeup_seq; + break; + } } - if (!--cv->nr_sleepers) - cv->nr_wakers = 0; /* no memory of wakeups */ + + ++cv->woken_seq; + lll_unlock(cv->lock); + + cleanup_pop + mutex_lock(mutex); return ret; @@ -57,34 +86,24 @@ cond_wait_timeout(cv, mutex, timeout): cond_signal(cv) { - int do_wakeup = 0; - lll_lock(cv->lock); - if (cv->nr_sleepers) { - if (!++cv->nr_wakers) /* overflow detection for the nutcase */ - cv->nr_wakers = ALL_THREADS; - do_wakeup = 1; + + if (cv->total_seq > cv->wakeup_seq) { + ++cv->wakeup_seq; + FUTEX_WAKE(cv->wakeup_seq, 1); } + lll_unlock(cv->lock); - if (do_wakeup) - FUTEX WAKE (cv->nr_wakers, 1) } cond_broadcast(cv) { - int do_wakeup = 0; - lll_lock(cv->lock); - if (cv->nr_sleepers) { - cv->nr_wakers |= ALL_THREADS; - do_wakeup = 1; + + if (cv->total_seq > cv->wakeup_seq) { + cv->wakeup_seq = cv->total_seq; + FUTEX_WAKE(cv->wakeup_seq, ALL); } + lll_unlock(cv->lock); - if (do_wakeup) - FUTEX WAKE (cv->nr_wakers, ALL_THREADS); } - -weaknesses of the implementation: - - it might generate spurious wakeups in the broadcast case, but those are - allowed by POSIX. |