]>
Commit | Line | Data |
---|---|---|
214d78a2 A |
1 | #include <pthread.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | #include <unistd.h> | |
5 | #include <stdbool.h> | |
6 | #include <errno.h> | |
7 | #include <TargetConditionals.h> | |
8 | ||
9 | #include <pthread/pthread_spis.h> | |
10 | ||
11 | #include <sys/sysctl.h> | |
12 | ||
13 | #include "darwintest_defaults.h" | |
14 | #include <darwintest_multiprocess.h> | |
15 | ||
16 | struct context { | |
17 | union { | |
18 | pthread_mutex_t mutex; | |
19 | pthread_cond_t cond; | |
20 | }; | |
21 | pthread_mutex_t mutex2; | |
22 | long value; | |
23 | long count; | |
24 | }; | |
25 | ||
26 | static void *test_cond(void *ptr) { | |
27 | struct context *context = ptr; | |
28 | int res; | |
29 | ||
30 | res = pthread_cond_wait(&context->cond, &context->mutex2); | |
31 | T_ASSERT_POSIX_ZERO(res, "condition wait on condvar completed"); | |
32 | res = pthread_mutex_unlock(&context->mutex2); | |
33 | T_ASSERT_POSIX_ZERO(res, "unlock condvar mutex"); | |
34 | return NULL; | |
35 | } | |
36 | ||
37 | static void *test_cond_wake(void *ptr) { | |
38 | struct context *context = ptr; | |
39 | int res; | |
40 | ||
41 | res = pthread_mutex_lock(&context->mutex2); | |
42 | T_ASSERT_POSIX_ZERO(res, "locked condvar mutex"); | |
43 | res = pthread_cond_signal(&context->cond); | |
44 | T_ASSERT_POSIX_ZERO(res, "condvar signalled"); | |
45 | res = pthread_mutex_unlock(&context->mutex2); | |
46 | T_ASSERT_POSIX_ZERO(res, "dropped condvar mutex"); | |
47 | ||
48 | return NULL; | |
49 | } | |
50 | ||
51 | static void *test_thread(void *ptr) { | |
52 | int res; | |
53 | long old; | |
54 | struct context *context = ptr; | |
55 | ||
56 | int i = 0; | |
57 | char *str; | |
58 | ||
59 | do { | |
60 | bool try = i++ & 1; | |
61 | ||
62 | if (!try){ | |
63 | str = "pthread_mutex_lock"; | |
64 | res = pthread_mutex_lock(&context->mutex); | |
65 | } else { | |
66 | str = "pthread_mutex_trylock"; | |
67 | res = pthread_mutex_trylock(&context->mutex); | |
68 | } | |
69 | if (res != 0) { | |
70 | if (try && res == EBUSY) { | |
71 | continue; | |
72 | } | |
73 | T_ASSERT_POSIX_ZERO(res, "[%ld] %s", context->count, str); | |
74 | } | |
75 | ||
76 | old = __sync_fetch_and_or(&context->value, 1); | |
77 | if ((old & 1) != 0) { | |
78 | T_FAIL("[%ld] OR %lx\n", context->count, old); | |
79 | } | |
80 | ||
81 | old = __sync_fetch_and_and(&context->value, 0); | |
82 | if ((old & 1) == 0) { | |
83 | T_FAIL("[%ld] AND %lx\n", context->count, old); | |
84 | } | |
85 | ||
86 | res = pthread_mutex_unlock(&context->mutex); | |
87 | if (res) { | |
88 | T_ASSERT_POSIX_ZERO(res, "[%ld] pthread_mutex_lock", context->count); | |
89 | } | |
90 | } while (__sync_fetch_and_sub(&context->count, 1) > 0); | |
91 | return NULL; | |
92 | } | |
93 | ||
94 | ||
95 | static void | |
96 | _test_condvar_prepost_race(void) | |
97 | { | |
98 | struct context context = { | |
99 | .mutex = PTHREAD_MUTEX_INITIALIZER, | |
100 | .mutex2 = PTHREAD_MUTEX_INITIALIZER, | |
101 | .value = 0, | |
102 | .count = 1000, | |
103 | }; | |
104 | int i; | |
105 | int res; | |
106 | int threads = 8; | |
107 | pthread_t p[threads]; | |
108 | for (i = 0; i < threads; ++i) { | |
109 | res = pthread_create(&p[i], NULL, test_thread, &context); | |
110 | T_ASSERT_POSIX_ZERO(res, "pthread_create()"); | |
111 | } | |
112 | for (i = 0; i < threads; ++i) { | |
113 | res = pthread_join(p[i], NULL); | |
114 | T_ASSERT_POSIX_ZERO(res, "pthread_join()"); | |
115 | } | |
116 | ||
117 | T_PASS("initial pthread mutex storm completed"); | |
118 | ||
119 | pthread_mutex_destroy(&context.mutex); | |
120 | ||
121 | pthread_cond_init(&context.cond, NULL); | |
122 | res = pthread_mutex_lock(&context.mutex2); | |
123 | T_ASSERT_POSIX_ZERO(res, "mutex lock for condition wait"); | |
124 | res = pthread_create(&p[0], NULL, test_cond, &context); | |
125 | T_QUIET; T_ASSERT_POSIX_ZERO(res, "pthread_create()"); | |
126 | res = pthread_create(&p[1], NULL, test_cond_wake, &context); | |
127 | T_QUIET; T_ASSERT_POSIX_ZERO(res, "pthread_create()"); | |
128 | ||
129 | res = pthread_join(p[0], NULL); | |
130 | T_QUIET; T_ASSERT_POSIX_ZERO(res, "pthread_join()"); | |
131 | res = pthread_join(p[1], NULL); | |
132 | T_QUIET; T_ASSERT_POSIX_ZERO(res, "pthread_join()"); | |
133 | ||
134 | pthread_cond_destroy(&context.cond); | |
135 | } | |
136 | ||
137 | T_DECL(mutex_prepost_fairshare, "pthread_mutex_prepost (fairshare)", | |
138 | T_META_ALL_VALID_ARCHS(YES), | |
139 | T_META_ENVVAR("PTHREAD_MUTEX_DEFAULT_POLICY=1")) | |
140 | { | |
141 | int i; | |
142 | int count = 100; | |
143 | for (i=0; i < count; i++) { | |
144 | _test_condvar_prepost_race(); | |
145 | } | |
146 | } | |
147 | ||
148 | T_DECL(mutex_prepost_firstfit, "pthread_mutex_prepost (firstfit)", | |
149 | T_META_ALL_VALID_ARCHS(YES), | |
150 | T_META_ENVVAR("PTHREAD_MUTEX_DEFAULT_POLICY=3")) | |
151 | { | |
152 | int i; | |
153 | int count = 100; | |
154 | for (i=0; i < count; i++) { | |
155 | _test_condvar_prepost_race(); | |
156 | } | |
157 | } |