9616dd85005eba918abeeb95e82c7a26f8155c68
[musl] / src / thread / pthread_cond_timedwait.c
1 #include "pthread_impl.h"
2
3 struct cm {
4         pthread_cond_t *c;
5         pthread_mutex_t *m;
6 };
7
8 static void unwait(pthread_cond_t *c, pthread_mutex_t *m)
9 {
10         int w;
11
12         /* Cannot leave waiting status if there are any live broadcasters
13          * which might be inspecting/using the mutex. */
14         while ((w=c->_c_bcast)) __wait(&c->_c_bcast, &c->_c_leavers, w, 0);
15
16         /* If the waiter count is zero, it must be the case that the
17          * caller's count has been moved to the mutex due to bcast. */
18         do w = c->_c_waiters;
19         while (w && a_cas(&c->_c_waiters, w, w-1)!=w);
20         if (!w) a_dec(&m->_m_waiters);
21 }
22
23 static void cleanup(void *p)
24 {
25         struct cm *cm = p;
26         unwait(cm->c, cm->m);
27         pthread_mutex_lock(cm->m);
28 }
29
30 int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts)
31 {
32         struct cm cm = { .c=c, .m=m };
33         int r, e, tid;
34
35         if (ts && ts->tv_nsec >= 1000000000UL)
36                 return EINVAL;
37
38         pthread_testcancel();
39
40         if (c->_c_mutex != (void *)-1) c->_c_mutex = m;
41
42         a_inc(&c->_c_waiters);
43         c->_c_block = tid = pthread_self()->tid;
44
45         if ((r=pthread_mutex_unlock(m))) return r;
46
47         do e = __timedwait(&c->_c_block, tid, c->_c_clock, ts, cleanup, &cm, 0);
48         while (c->_c_block == tid && (!e || e==EINTR));
49         if (e == EINTR) e = 0;
50
51         unwait(c, m);
52
53         if ((r=pthread_mutex_lock(m))) return r;
54
55         pthread_testcancel();
56         return e;
57 }