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