1 /* $NetBSD: sem.c,v 1.10 2012/03/09 14:25:34 joerg Exp $ */
4 * Common code for semaphore tests. This can be included both into
5 * programs using librt and libpthread.
10 #include <rump/rump.h>
11 #include <rump/rump_syscalls.h>
17 #include <semaphore.h>
24 #include "../../h_macros.h"
27 ATF_TC_HEAD(postwait
, tc
)
30 atf_tc_set_md_var(tc
, "descr", "tests post and wait from a "
31 "single thread (%s)", LIBNAME
);
34 ATF_TC_BODY(postwait
, tc
)
41 ATF_REQUIRE_EQ(sem_init(&sem
, 1, 0), 0);
48 rv
= sem_trywait(&sem
);
49 ATF_REQUIRE(errno
== EAGAIN
);
50 ATF_REQUIRE(rv
== -1);
54 ATF_TC_HEAD(initvalue
, tc
)
57 atf_tc_set_md_var(tc
, "descr", "tests initialization with a non-zero "
58 "value (%s)", LIBNAME
);
61 ATF_TC_BODY(initvalue
, tc
)
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);
76 ATF_TC_HEAD(destroy
, tc
)
79 atf_tc_set_md_var(tc
, "descr", "tests sem_destroy works (%s)", LIBNAME
);
82 ATF_TC_BODY(destroy
, tc
)
88 for (i
= 0; i
< 2; i
++) {
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);
101 ATF_TC_HEAD(busydestroy
, tc
)
104 atf_tc_set_md_var(tc
, "descr", "tests sem_destroy report EBUSY for "
105 "a busy semaphore (%s)", LIBNAME
);
111 sem_t
*semmarit
= arg
;
114 sem_post(&semmarit
[2]);
115 sem_wait(&semmarit
[1]);
116 sem_wait(&semmarit
[0]);
122 ATF_TC_BODY(busydestroy
, tc
)
128 /* use a unicpu rump kernel. this means less chance for race */
129 setenv("RUMP_NCPU", "1", 1);
132 sem_init(&semmarit
[0], 1, 0);
133 sem_init(&semmarit
[1], 1, 0);
134 sem_init(&semmarit
[2], 1, 0);
136 pthread_create(&pt
, NULL
, hthread
, semmarit
);
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
144 for (i
= 0; i
< 1000; i
++) {
145 sem_wait(&semmarit
[2]);
147 if (sem_destroy(&semmarit
[1]) == -1)
152 * Didn't catch it? ok, recreate and post to make the
155 sem_init(&semmarit
[1], 1, 0);
156 sem_post(&semmarit
[0]);
157 sem_post(&semmarit
[1]);
161 atf_tc_fail("sem destroy not reporting EBUSY");
164 pthread_join(pt
, NULL
);
168 ATF_TC_HEAD(blockwait
, tc
)
171 atf_tc_set_md_var(tc
, "descr", "tests sem_wait can handle blocking "
173 atf_tc_set_md_var(tc
, "timeout", "2");
176 ATF_TC_BODY(blockwait
, tc
)
183 sem_init(&semmarit
[0], 1, 0);
184 sem_init(&semmarit
[1], 1, 0);
185 sem_init(&semmarit
[2], 1, 0);
187 pthread_create(&pt
, NULL
, hthread
, semmarit
);
190 * Make a best-effort. Unless we're extremely unlucky, we should
191 * at least one blocking wait.
193 for (i
= 0; i
< 10; i
++) {
194 sem_wait(&semmarit
[2]);
196 sem_post(&semmarit
[0]);
197 sem_post(&semmarit
[1]);
202 pthread_join(pt
, NULL
);
205 ATF_TC(blocktimedwait
);
206 ATF_TC_HEAD(blocktimedwait
, tc
)
209 atf_tc_set_md_var(tc
, "descr", "tests sem_timedwait can handle blocking"
211 atf_tc_set_md_var(tc
, "timeout", "2");
214 ATF_TC_BODY(blocktimedwait
, tc
)
221 clock_gettime(CLOCK_REALTIME
, &tp
);
222 tp
.tv_nsec
+= 50000000;
223 tp
.tv_sec
+= tp
.tv_nsec
/ 1000000000;
224 tp
.tv_nsec
%= 1000000000;
226 ATF_REQUIRE_EQ(sem_init(&semid
, 1, 0), 0);
227 ATF_REQUIRE_ERRNO(ETIMEDOUT
, sem_timedwait(&semid
, &tp
) == -1);
231 ATF_TC_HEAD(named
, tc
)
234 atf_tc_set_md_var(tc
, "descr", "tests named semaphores (%s)", LIBNAME
);
238 * Wow, easy naming rules. it's these times i'm really happy i can
239 * single-step into the kernel.
241 #define SEM1 "/precious_sem"
242 #define SEM2 "/justsem"
243 ATF_TC_BODY(named
, tc
)
249 sem1
= sem_open(SEM1
, 0);
250 ATF_REQUIRE_EQ(errno
, ENOENT
);
251 ATF_REQUIRE_EQ(sem1
, NULL
);
253 sem1
= sem_open(SEM1
, O_CREAT
, 0444, 1);
255 atf_tc_fail_errno("sem_open O_CREAT");
257 rv
= sem_open(SEM1
, O_CREAT
| O_EXCL
);
258 ATF_REQUIRE_EQ(errno
, EEXIST
);
259 ATF_REQUIRE_EQ(rv
, NULL
);
261 sem2
= sem_open(SEM2
, O_CREAT
, 0444, 0);
263 atf_tc_fail_errno("sem_open O_CREAT");
265 /* check that semaphores are independent */
266 ATF_REQUIRE_EQ(sem_trywait(sem2
), -1);
267 ATF_REQUIRE_EQ(sem_trywait(sem1
), 0);
268 ATF_REQUIRE_EQ(sem_trywait(sem1
), -1);
270 /* check that unlinked remains valid */
272 ATF_REQUIRE_EQ(sem_post(sem2
), 0);
273 ATF_REQUIRE_EQ(sem_trywait(sem2
), 0);
274 ATF_REQUIRE_EQ(sem_trywait(sem2
), -1);
275 ATF_REQUIRE_EQ(errno
, EAGAIN
);
277 #if 0 /* see unlink */
278 /* close it and check that it's gone */
279 if (sem_close(sem2
) != 0)
280 atf_tc_fail_errno("sem close");
281 ATF_REQUIRE_EQ(sem_trywait(sem2
), -1);
282 ATF_REQUIRE_EQ(errno
, EINVAL
);
285 /* check that we still have sem1 */
287 ATF_REQUIRE_EQ(sem_trywait(sem1
), 0);
288 ATF_REQUIRE_EQ(sem_trywait(sem1
), -1);
289 ATF_REQUIRE_EQ(errno
, EAGAIN
);
293 ATF_TC_HEAD(unlink
, tc
)
296 /* this is currently broken. i'll append the PR number soon */
297 atf_tc_set_md_var(tc
, "descr", "tests unlinked semaphores can be "
298 "closed (%s)", LIBNAME
);
301 #define SEM "/thesem"
302 ATF_TC_BODY(unlink
, tc
)
307 sem
= sem_open(SEM
, O_CREAT
, 0444, 0);
310 if (sem_unlink(SEM
) == -1)
311 atf_tc_fail_errno("unlink");
312 if (sem_close(sem
) == -1)
313 atf_tc_fail_errno("close unlinked semaphore");
316 /* use rump calls for libpthread _ksem_foo() calls */
317 #define F1(name, a) int _ksem_##name(a); \
318 int _ksem_##name(a v1) {return rump_sys__ksem_##name(v1);}
319 #define F2(name, a, b) int _ksem_##name(a, b); \
320 int _ksem_##name(a v1, b v2) {return rump_sys__ksem_##name(v1, v2);}
321 F2(init
, unsigned int, intptr_t *);
323 F1(destroy
, intptr_t);
325 F1(unlink
, const char *);
326 F1(trywait
, intptr_t);
328 F2(getvalue
, intptr_t, unsigned int *);
329 F2(timedwait
, intptr_t, const struct timespec
*);
330 int _ksem_open(const char *, int, mode_t
, unsigned int, intptr_t *);
331 int _ksem_open(const char *a
, int b
, mode_t c
, unsigned int d
, intptr_t *e
)
332 {return rump_sys__ksem_open(a
,b
,c
,d
,e
);}