sem.c revision 1.8 1 /* $NetBSD: sem.c,v 1.8 2011/03/23 13:57:04 joerg Exp $ */
2
3 /*
4 * Common code for semaphore tests. This can be included both into
5 * programs using librt and libpthread.
6 */
7
8 #include <sys/types.h>
9
10 #include <rump/rump.h>
11 #include <rump/rump_syscalls.h>
12
13 #include <atf-c.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <pthread.h>
17 #include <semaphore.h>
18 #include <sched.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include "../../h_macros.h"
25
26 ATF_TC(postwait);
27 ATF_TC_HEAD(postwait, tc)
28 {
29
30 atf_tc_set_md_var(tc, "descr", "tests post and wait from a "
31 "single thread (%s)", LIBNAME);
32 }
33
34 ATF_TC_BODY(postwait, tc)
35 {
36 sem_t sem;
37 int rv;
38
39 rump_init();
40
41 ATF_REQUIRE_EQ(sem_init(&sem, 1, 0), 0);
42
43 sem_post(&sem);
44 sem_post(&sem);
45
46 sem_wait(&sem);
47 sem_wait(&sem);
48 rv = sem_trywait(&sem);
49 ATF_REQUIRE(errno == EAGAIN);
50 ATF_REQUIRE(rv == -1);
51 }
52
53 ATF_TC(initvalue);
54 ATF_TC_HEAD(initvalue, tc)
55 {
56
57 atf_tc_set_md_var(tc, "descr", "tests initialization with a non-zero "
58 "value (%s)", LIBNAME);
59 }
60
61 ATF_TC_BODY(initvalue, tc)
62 {
63 sem_t sem;
64
65 rump_init();
66 sem_init(&sem, 1, 4);
67
68 ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
69 ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
70 ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
71 ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
72 ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
73 }
74
75 ATF_TC(destroy);
76 ATF_TC_HEAD(destroy, tc)
77 {
78
79 atf_tc_set_md_var(tc, "descr", "tests sem_destroy works (%s)", LIBNAME);
80 }
81
82 ATF_TC_BODY(destroy, tc)
83 {
84 sem_t sem;
85 int rv, i;
86
87 rump_init();
88 for (i = 0; i < 2; i++) {
89 sem_init(&sem, 1, 1);
90
91 ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
92 ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
93 ATF_REQUIRE_EQ(sem_destroy(&sem), 0);
94 rv = sem_trywait(&sem);
95 ATF_REQUIRE_EQ(errno, EINVAL);
96 ATF_REQUIRE_EQ(rv, -1);
97 }
98 }
99
100 ATF_TC(busydestroy);
101 ATF_TC_HEAD(busydestroy, tc)
102 {
103
104 atf_tc_set_md_var(tc, "descr", "tests sem_destroy report EBUSY for "
105 "a busy semaphore (%s)", LIBNAME);
106 }
107
108 static void *
109 hthread(void *arg)
110 {
111 sem_t *semmarit = arg;
112
113 for (;;) {
114 sem_post(&semmarit[2]);
115 sem_wait(&semmarit[1]);
116 sem_wait(&semmarit[0]);
117 }
118
119 return NULL;
120 }
121
122 ATF_TC_BODY(busydestroy, tc)
123 {
124 sem_t semmarit[3];
125 pthread_t pt;
126 int i;
127
128 /* use a unicpu rump kernel. this means less chance for race */
129 setenv("RUMP_NCPU", "1", 1);
130
131 rump_init();
132 sem_init(&semmarit[0], 1, 0);
133 sem_init(&semmarit[1], 1, 0);
134 sem_init(&semmarit[2], 1, 0);
135
136 pthread_create(&pt, NULL, hthread, semmarit);
137
138 /*
139 * Make a best-effort to catch the other thread with its pants down.
140 * We can't do this for sure, can we? Although, we could reach
141 * inside the rump kernel and inquire about the thread's sleep
142 * status.
143 */
144 for (i = 0; i < 1000; i++) {
145 sem_wait(&semmarit[2]);
146 usleep(1);
147 if (sem_destroy(&semmarit[1]) == -1)
148 if (errno == EBUSY)
149 break;
150
151 /*
152 * Didn't catch it? ok, recreate and post to make the
153 * other thread run
154 */
155 sem_init(&semmarit[1], 1, 0);
156 sem_post(&semmarit[0]);
157 sem_post(&semmarit[1]);
158
159 }
160 if (i == 1000)
161 atf_tc_fail("sem destroy not reporting EBUSY");
162
163 pthread_cancel(pt);
164 pthread_join(pt, NULL);
165 }
166
167 ATF_TC(blockwait);
168 ATF_TC_HEAD(blockwait, tc)
169 {
170
171 atf_tc_set_md_var(tc, "descr", "tests sem_wait can handle blocking "
172 "(%s)", LIBNAME);
173 atf_tc_set_md_var(tc, "timeout", "2");
174 }
175
176 ATF_TC_BODY(blockwait, tc)
177 {
178 sem_t semmarit[3];
179 pthread_t pt;
180 int i;
181
182 rump_init();
183 sem_init(&semmarit[0], 1, 0);
184 sem_init(&semmarit[1], 1, 0);
185 sem_init(&semmarit[2], 1, 0);
186
187 pthread_create(&pt, NULL, hthread, semmarit);
188
189 /*
190 * Make a best-effort. Unless we're extremely unlucky, we should
191 * at least one blocking wait.
192 */
193 for (i = 0; i < 10; i++) {
194 sem_wait(&semmarit[2]);
195 usleep(1);
196 sem_post(&semmarit[0]);
197 sem_post(&semmarit[1]);
198
199 }
200
201 pthread_cancel(pt);
202 pthread_join(pt, NULL);
203 }
204
205 ATF_TC(named);
206 ATF_TC_HEAD(named, tc)
207 {
208
209 atf_tc_set_md_var(tc, "descr", "tests named semaphores (%s)", LIBNAME);
210 }
211
212 /*
213 * Wow, easy naming rules. it's these times i'm really happy i can
214 * single-step into the kernel.
215 */
216 #define SEM1 "/precious_sem"
217 #define SEM2 "/justsem"
218 ATF_TC_BODY(named, tc)
219 {
220 sem_t *sem1, *sem2;
221 void *rv;
222
223 rump_init();
224 sem1 = sem_open(SEM1, 0);
225 ATF_REQUIRE_EQ(errno, ENOENT);
226 ATF_REQUIRE_EQ(sem1, NULL);
227
228 sem1 = sem_open(SEM1, O_CREAT, 0444, 1);
229 if (sem1 == NULL)
230 atf_tc_fail_errno("sem_open O_CREAT");
231
232 rv = sem_open(SEM1, O_CREAT | O_EXCL);
233 ATF_REQUIRE_EQ(errno, EEXIST);
234 ATF_REQUIRE_EQ(rv, NULL);
235
236 sem2 = sem_open(SEM2, O_CREAT, 0444, 0);
237 if (sem2 == NULL)
238 atf_tc_fail_errno("sem_open O_CREAT");
239
240 /* check that semaphores are independent */
241 ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
242 ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
243 ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
244
245 /* check that unlinked remains valid */
246 sem_unlink(SEM2);
247 ATF_REQUIRE_EQ(sem_post(sem2), 0);
248 ATF_REQUIRE_EQ(sem_trywait(sem2), 0);
249 ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
250 ATF_REQUIRE_EQ(errno, EAGAIN);
251
252 #if 0 /* see unlink */
253 /* close it and check that it's gone */
254 if (sem_close(sem2) != 0)
255 atf_tc_fail_errno("sem close");
256 ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
257 ATF_REQUIRE_EQ(errno, EINVAL);
258 #endif
259
260 /* check that we still have sem1 */
261 sem_post(sem1);
262 ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
263 ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
264 ATF_REQUIRE_EQ(errno, EAGAIN);
265 }
266
267 ATF_TC(unlink);
268 ATF_TC_HEAD(unlink, tc)
269 {
270
271 /* this is currently broken. i'll append the PR number soon */
272 atf_tc_set_md_var(tc, "descr", "tests unlinked semaphores can be "
273 "closed (%s)", LIBNAME);
274 }
275
276 #define SEM "/thesem"
277 ATF_TC_BODY(unlink, tc)
278 {
279 sem_t *sem;
280
281 rump_init();
282 sem = sem_open(SEM, O_CREAT, 0444, 0);
283 ATF_REQUIRE(sem);
284
285 if (sem_unlink(SEM) == -1)
286 atf_tc_fail_errno("unlink");
287 atf_tc_expect_fail("PR kern/43452");
288 if (sem_close(sem) == -1)
289 atf_tc_fail_errno("close unlinked semaphore");
290 }
291
292 /* use rump calls for libpthread _ksem_foo() calls */
293 #define F1(name, a) int _ksem_##name(a); \
294 int _ksem_##name(a v1) {return rump_sys__ksem_##name(v1);}
295 #define F2(name, a, b) int _ksem_##name(a, b); \
296 int _ksem_##name(a v1, b v2) {return rump_sys__ksem_##name(v1, v2);}
297 F2(init, unsigned int, intptr_t *);
298 F1(close, intptr_t);
299 F1(destroy, intptr_t);
300 F1(post, intptr_t);
301 F1(unlink, const char *);
302 F1(trywait, intptr_t);
303 F1(wait, intptr_t);
304 F2(getvalue, intptr_t, unsigned int *);
305 int _ksem_open(const char *, int, mode_t, unsigned int, intptr_t *);
306 int _ksem_open(const char *a, int b, mode_t c, unsigned int d, intptr_t *e)
307 {return rump_sys__ksem_open(a,b,c,d,e);}
308