1Conditional Variable pseudocode.
2================================
3
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);
7
8struct pthread_cond_t {
9
10   unsigned int cond_lock;
11
12         internal mutex
13
14   uint64_t total_seq;
15
16     Total number of threads using the conditional variable.
17
18   uint64_t wakeup_seq;
19
20     sequence number for next wakeup.
21
22   uint64_t woken_seq;
23
24     sequence number of last woken thread.
25
26   uint32_t broadcast_seq;
27
28}
29
30
31struct cv_data {
32
33   pthread_cond_t *cv;
34
35   uint32_t bc_seq
36
37}
38
39
40
41cleanup_handler(cv_data)
42{
43  cv = cv_data->cv;
44  lll_lock(cv->lock);
45
46  if (cv_data->bc_seq == cv->broadcast_seq) {
47    ++cv->wakeup_seq;
48    ++cv->woken_seq;
49  }
50
51  /* make sure no signal gets lost.  */
52  FUTEX_WAKE(cv->wakeup_seq, ALL);
53
54  lll_unlock(cv->lock);
55}
56
57
58cond_timedwait(cv, mutex, timeout):
59{
60   lll_lock(cv->lock);
61   mutex_unlock(mutex);
62
63   cleanup_push
64
65   ++cv->total_seq;
66   val = seq =  cv->wakeup_seq;
67   cv_data.bc = cv->broadcast_seq;
68   cv_data.cv = cv;
69
70   while (1) {
71
72     lll_unlock(cv->lock);
73
74     enable_async(&cv_data);
75
76     ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
77
78     restore_async
79
80     lll_lock(cv->lock);
81
82     if (bc != cv->broadcast_seq)
83       goto bc_out;
84
85     val = cv->wakeup_seq;
86
87     if (val != seq && cv->woken_seq != val) {
88       ret = 0;
89       break;
90     }
91
92     if (ret == TIMEDOUT) {
93       ++cv->wakeup_seq;
94       break;
95     }
96   }
97
98   ++cv->woken_seq;
99
100 bc_out:
101   lll_unlock(cv->lock);
102
103   cleanup_pop
104
105   mutex_lock(mutex);
106
107   return ret;
108}
109
110cond_signal(cv)
111{
112   lll_lock(cv->lock);
113
114   if (cv->total_seq > cv->wakeup_seq) {
115     ++cv->wakeup_seq;
116     FUTEX_WAKE(cv->wakeup_seq, 1);
117   }
118
119   lll_unlock(cv->lock);
120}
121
122cond_broadcast(cv)
123{
124   lll_lock(cv->lock);
125
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   }
132
133   lll_unlock(cv->lock);
134}
135