[BZ #2766]
[glibc.git] / nptl / DESIGN-condvar.txt
blob4845251c7586c9667cd33c38af3701910d65eaa8
1 Conditional Variable pseudocode.
2 ================================
4        int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
5        int pthread_cond_signal    (pthread_cond_t *cv);
6        int pthread_cond_broadcast (pthread_cond_t *cv);
8 struct pthread_cond_t {
10    unsigned int cond_lock;
12          internal mutex
14    uint64_t total_seq;
16      Total number of threads using the conditional variable.
18    uint64_t wakeup_seq;
20      sequence number for next wakeup.
22    uint64_t woken_seq;
24      sequence number of last woken thread.
26    uint32_t broadcast_seq;
31 struct cv_data {
33    pthread_cond_t *cv;
35    uint32_t bc_seq
41 cleanup_handler(cv_data)
43   cv = cv_data->cv;
44   lll_lock(cv->lock);
46   if (cv_data->bc_seq == cv->broadcast_seq) {
47     ++cv->wakeup_seq;
48     ++cv->woken_seq;
49   }
51   /* make sure no signal gets lost.  */
52   FUTEX_WAKE(cv->wakeup_seq, ALL);
54   lll_unlock(cv->lock);
58 cond_timedwait(cv, mutex, timeout):
60    lll_lock(cv->lock);
61    mutex_unlock(mutex);
63    cleanup_push
65    ++cv->total_seq;
66    val = seq =  cv->wakeup_seq;
67    cv_data.bc = cv->broadcast_seq;
68    cv_data.cv = cv;
70    while (1) {
72      lll_unlock(cv->lock);
74      enable_async(&cv_data);
76      ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
78      restore_async
80      lll_lock(cv->lock);
82      if (bc != cv->broadcast_seq)
83        goto bc_out;
85      val = cv->wakeup_seq;
87      if (val != seq && cv->woken_seq != val) {
88        ret = 0;
89        break;
90      }
92      if (ret == TIMEDOUT) {
93        ++cv->wakeup_seq;
94        break;
95      }
96    }
98    ++cv->woken_seq;
100  bc_out:
101    lll_unlock(cv->lock);
103    cleanup_pop
105    mutex_lock(mutex);
107    return ret;
110 cond_signal(cv)
112    lll_lock(cv->lock);
114    if (cv->total_seq > cv->wakeup_seq) {
115      ++cv->wakeup_seq;
116      FUTEX_WAKE(cv->wakeup_seq, 1);
117    }
119    lll_unlock(cv->lock);
122 cond_broadcast(cv)
124    lll_lock(cv->lock);
126    if (cv->total_seq > cv->wakeup_seq) {
127      cv->wakeup_seq = cv->total_seq;
128      cv->woken_seq = cv->total_seq;
129      ++cv->broadcast_seq;
130      FUTEX_WAKE(cv->wakeup_seq, ALL);
131    }
133    lll_unlock(cv->lock);