1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
_Atomic int waiting, should_exit;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static void *worker(void *arg) {
(void)arg;
pthread_mutex_lock(&mtx);
++waiting;
while (!should_exit)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
return NULL;
}
static void test_broadcast_wakes_all() {
pthread_t t1, t2;
pthread_create(&t1, NULL, &worker, NULL);
pthread_create(&t2, NULL, &worker, NULL);
// Wait until the workers have actually entered the cond_wait
// before doing a broadcast.
while (waiting != 2 || pthread_mutex_trylock(&mtx) == EBUSY)
usleep(150000); // 150ms
should_exit = 1;
assert(!pthread_cond_broadcast(&cond));
pthread_mutex_unlock(&mtx);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
static void test_timedwait_timedout() {
// Use CLOCK_MONOTONIC.
pthread_condattr_t attr;
pthread_condattr_init(&attr);
assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
struct timespec before_now;
assert(!clock_gettime(CLOCK_MONOTONIC, &before_now));
before_now.tv_nsec -= 10000;
pthread_mutex_lock(&mtx);
int e = pthread_cond_timedwait(&cond, &mtx, &before_now);
assert(e == ETIMEDOUT);
pthread_mutex_unlock(&mtx);
long nanos_per_second = 1000000000;
struct timespec after_now;
assert(!clock_gettime(CLOCK_MONOTONIC, &after_now));
after_now.tv_nsec += nanos_per_second / 10; // 100ms
if (after_now.tv_nsec >= nanos_per_second) {
after_now.tv_nsec -= nanos_per_second;
after_now.tv_sec++;
}
pthread_mutex_lock(&mtx);
e = pthread_cond_timedwait(&cond, &mtx, &after_now);
assert(e == ETIMEDOUT);
pthread_mutex_unlock(&mtx);
after_now.tv_nsec += nanos_per_second;
pthread_mutex_lock(&mtx);
e = pthread_cond_timedwait(&cond, &mtx, &after_now);
assert(e == EINVAL);
pthread_mutex_unlock(&mtx);
}
static void test_attr() {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
clockid_t clock;
assert(!pthread_condattr_getclock(&attr, &clock));
assert(clock == CLOCK_REALTIME);
assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
assert(!pthread_condattr_getclock(&attr, &clock));
assert(clock == CLOCK_MONOTONIC);
int pshared;
assert(!pthread_condattr_getpshared(&attr, &pshared));
assert(pshared == PTHREAD_PROCESS_PRIVATE);
assert(!pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
assert(!pthread_condattr_getpshared(&attr, &pshared));
assert(pshared == PTHREAD_PROCESS_SHARED);
pthread_condattr_destroy(&attr);
pthread_condattr_init(&attr);
// Make sure that we can create a pthread_cond_t with an attr.
pthread_cond_t cond;
pthread_cond_init(&cond, &attr);
pthread_cond_destroy(&cond);
pthread_condattr_destroy(&attr);
}
int main() {
test_attr();
test_broadcast_wakes_all();
test_timedwait_timedout();
}
|