]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/lib/semaphore/sem.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / lib / semaphore / sem.c
1 /*      $NetBSD: sem.c,v 1.10 2012/03/09 14:25:34 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(blocktimedwait);
206 ATF_TC_HEAD(blocktimedwait, tc)
207 {
208
209         atf_tc_set_md_var(tc, "descr", "tests sem_timedwait can handle blocking"
210             " (%s)", LIBNAME);
211         atf_tc_set_md_var(tc, "timeout", "2");
212 }
213
214 ATF_TC_BODY(blocktimedwait, tc)
215 {
216         sem_t semid;
217         struct timespec tp;
218
219         rump_init();
220
221         clock_gettime(CLOCK_REALTIME, &tp);
222         tp.tv_nsec += 50000000;
223         tp.tv_sec += tp.tv_nsec / 1000000000;
224         tp.tv_nsec %= 1000000000;
225
226         ATF_REQUIRE_EQ(sem_init(&semid, 1, 0), 0);
227         ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&semid, &tp) == -1);
228 }
229
230 ATF_TC(named);
231 ATF_TC_HEAD(named, tc)
232 {
233
234         atf_tc_set_md_var(tc, "descr", "tests named semaphores (%s)", LIBNAME);
235 }
236
237 /*
238  * Wow, easy naming rules.  it's these times i'm really happy i can
239  * single-step into the kernel.
240  */
241 #define SEM1 "/precious_sem"
242 #define SEM2 "/justsem"
243 ATF_TC_BODY(named, tc)
244 {
245         sem_t *sem1, *sem2;
246         void *rv;
247
248         rump_init();
249         sem1 = sem_open(SEM1, 0);
250         ATF_REQUIRE_EQ(errno, ENOENT);
251         ATF_REQUIRE_EQ(sem1, NULL);
252
253         sem1 = sem_open(SEM1, O_CREAT, 0444, 1);
254         if (sem1 == NULL)
255                 atf_tc_fail_errno("sem_open O_CREAT");
256
257         rv = sem_open(SEM1, O_CREAT | O_EXCL);
258         ATF_REQUIRE_EQ(errno, EEXIST);
259         ATF_REQUIRE_EQ(rv, NULL);
260
261         sem2 = sem_open(SEM2, O_CREAT, 0444, 0);
262         if (sem2 == NULL)
263                 atf_tc_fail_errno("sem_open O_CREAT");
264
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);
269
270         /* check that unlinked remains valid */
271         sem_unlink(SEM2);
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);
276
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);
283 #endif
284
285         /* check that we still have sem1 */
286         sem_post(sem1);
287         ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
288         ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
289         ATF_REQUIRE_EQ(errno, EAGAIN);
290 }
291
292 ATF_TC(unlink);
293 ATF_TC_HEAD(unlink, tc)
294 {
295
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);
299 }
300
301 #define SEM "/thesem"
302 ATF_TC_BODY(unlink, tc)
303 {
304         sem_t *sem;
305
306         rump_init();
307         sem = sem_open(SEM, O_CREAT, 0444, 0);
308         ATF_REQUIRE(sem);
309
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");
314 }
315
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 *);
322 F1(close, intptr_t);
323 F1(destroy, intptr_t);
324 F1(post, intptr_t);
325 F1(unlink, const char *);
326 F1(trywait, intptr_t);
327 F1(wait, 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);}