## Condition Variables

Condition variables are a mechanism used for signaling that a certain predicate has become true. The POSIX mechanism for handling them boils down to three functions: `cond_wait`, `cond_signal` and `cond_broadcast`. The first one causes the thread that calls it to wait. The second wakes a thread up so that it can verify whether the condition is true. The third wakes all the waiters up.

## The waiter

``` 1tb_futex_lock(&cond->lock);
2...
3++cond->waiters;
5int futex = cond->futex;
6tb_futex_unlock(&cond->lock);
7
8while(1) {
9  st = SYSCALL3(__NR_futex, &cond->futex, FUTEX_WAIT, futex);
10  if(st == -EINTR)
11    continue;
12
13  tb_futex_lock(&cond->lock);
14  if(cond->signal_num) {
15    --cond->signal_num;
16    goto exit;
17  }
18
20    goto exit;
21  tb_futex_unlock(&cond->lock);
22}```

The algorithm is as follows:

1. We lock the internal lock.
2. We remember the value of the broadcast sequence and the futex.
3. In a loop, we wait for the futex.
4. We go back to sleeping if the `FUTEX_WAIT` syscall was interrupted by a signal.
5. We consume a signal, if we can, and exit.
6. If there was a broadcast, we exit too.
7. Otherwise, we go back to sleep.

## Signal

We wake one of the threads up. We bump the value of the futex to prevent a deadlock. Then we bump the number of signals and wake the futex.

``` 1int tbthread_cond_signal(tbthread_cond_t *cond)
2{
3  tb_futex_lock(&cond->lock);
4  if(cond->waiters == cond->signal_num)
5    goto exit;
6  ++cond->futex;
7  ++cond->signal_num;
8  SYSCALL3(__NR_futex, &cond->futex, FUTEX_WAKE, 1);
9exit:
10  tb_futex_unlock(&cond->lock);
11  return 0;
12}```

We wake all the waiters. The algorithm is essentially the same as for signal, except that, we bump the broadcast sequence number and wake all the threads instead of just one.

``` 1int tbthread_cond_broadcast(tbthread_cond_t *cond)
2{
3  tb_futex_lock(&cond->lock);
4  if(!cond->waiters)
5    goto exit;
6  ++cond->futex;