]>
Commit | Line | Data |
---|---|---|
964d3577 A |
1 | #include <assert.h> |
2 | #include <pthread.h> | |
3 | #include <stdio.h> | |
4 | #include <stdlib.h> | |
5 | #include <string.h> | |
6 | #include <unistd.h> | |
7 | #include <stdbool.h> | |
8 | #include <errno.h> | |
9 | ||
10 | struct context { | |
11 | pthread_rwlock_t rwlock; | |
12 | long value; | |
13 | long count; | |
14 | }; | |
15 | ||
16 | void *test_thread(void *ptr) { | |
17 | int res; | |
18 | long old; | |
19 | struct context *context = ptr; | |
20 | ||
21 | int i = 0; | |
22 | char *str; | |
23 | ||
24 | do { | |
25 | bool try = i & 1; | |
26 | bool exclusive = i & 2; | |
27 | switch (i++ & 3) { | |
28 | case 0: | |
29 | str = "pthread_rwlock_rdlock"; | |
30 | res = pthread_rwlock_rdlock(&context->rwlock); | |
31 | break; | |
32 | case 1: | |
33 | str = "pthread_rwlock_tryrdlock"; | |
34 | res = pthread_rwlock_tryrdlock(&context->rwlock); | |
35 | break; | |
36 | case 2: | |
37 | str = "pthread_rwlock_wrlock"; | |
38 | res = pthread_rwlock_wrlock(&context->rwlock); | |
39 | break; | |
40 | case 3: | |
41 | str = "pthread_rwlock_trywrlock"; | |
42 | res = pthread_rwlock_trywrlock(&context->rwlock); | |
43 | break; | |
44 | } | |
45 | if (res != 0) { | |
46 | if (try && res == EBUSY) { | |
47 | continue; | |
48 | } | |
49 | fprintf(stderr, "[%ld] %s: %s\n", context->count, str, strerror(res)); | |
50 | abort(); | |
51 | } | |
52 | ||
53 | if (exclusive) { | |
54 | old = __sync_fetch_and_or(&context->value, 1); | |
55 | if ((old & 1) != 0) { | |
56 | fprintf(stderr, "[%ld] OR %lx\n", context->count, old); | |
57 | abort(); | |
58 | } | |
59 | } | |
60 | ||
61 | old = __sync_fetch_and_and(&context->value, 0); | |
62 | if ((old & 1) != (exclusive ? 1 : 0)) { | |
63 | fprintf(stderr, "[%ld] AND %lx\n", context->count, old); | |
64 | abort(); | |
65 | } | |
66 | ||
67 | res = pthread_rwlock_unlock(&context->rwlock); | |
68 | if (res) { | |
69 | fprintf(stderr, "[%ld] pthread_rwlock_unlock: %s\n", context->count, strerror(res)); | |
70 | abort(); | |
71 | } | |
72 | } while (__sync_fetch_and_sub(&context->count, 1) > 0); | |
73 | ||
74 | return NULL; | |
75 | } | |
76 | ||
77 | int main(int argc, char *argv[]) | |
78 | { | |
79 | struct context context = { | |
80 | .rwlock = PTHREAD_RWLOCK_INITIALIZER, | |
81 | .value = 0, | |
82 | .count = 5000000, | |
83 | }; | |
84 | int i; | |
85 | int res; | |
86 | int threads = 16; | |
87 | pthread_t p[threads]; | |
88 | for (i = 0; i < threads; ++i) { | |
89 | res = pthread_create(&p[i], NULL, test_thread, &context); | |
90 | assert(res == 0); | |
91 | } | |
92 | for (i = 0; i < threads; ++i) { | |
93 | res = pthread_join(p[i], NULL); | |
94 | assert(res == 0); | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } |