xref: /freebsd/contrib/netbsd-tests/lib/semaphore/sem.c (revision 1a36faad54665288ed4eb839d2a4699ae2ead45e)
1*63d1fd59SEnji Cooper /*	$NetBSD: sem.c,v 1.11 2017/01/13 21:30:42 christos Exp $	*/
257718be8SEnji Cooper 
357718be8SEnji Cooper /*
457718be8SEnji Cooper  * Common code for semaphore tests.  This can be included both into
557718be8SEnji Cooper  * programs using librt and libpthread.
657718be8SEnji Cooper  */
757718be8SEnji Cooper 
857718be8SEnji Cooper #include <sys/types.h>
957718be8SEnji Cooper 
1057718be8SEnji Cooper #include <rump/rump.h>
1157718be8SEnji Cooper #include <rump/rump_syscalls.h>
1257718be8SEnji Cooper 
1357718be8SEnji Cooper #include <atf-c.h>
1457718be8SEnji Cooper #include <errno.h>
1557718be8SEnji Cooper #include <fcntl.h>
1657718be8SEnji Cooper #include <pthread.h>
1757718be8SEnji Cooper #include <semaphore.h>
1857718be8SEnji Cooper #include <sched.h>
1957718be8SEnji Cooper #include <stdint.h>
2057718be8SEnji Cooper #include <stdio.h>
2157718be8SEnji Cooper #include <stdlib.h>
2257718be8SEnji Cooper #include <unistd.h>
2357718be8SEnji Cooper 
24*63d1fd59SEnji Cooper #include "h_macros.h"
2557718be8SEnji Cooper 
2657718be8SEnji Cooper ATF_TC(postwait);
ATF_TC_HEAD(postwait,tc)2757718be8SEnji Cooper ATF_TC_HEAD(postwait, tc)
2857718be8SEnji Cooper {
2957718be8SEnji Cooper 
3057718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests post and wait from a "
3157718be8SEnji Cooper 	    "single thread (%s)", LIBNAME);
3257718be8SEnji Cooper }
3357718be8SEnji Cooper 
ATF_TC_BODY(postwait,tc)3457718be8SEnji Cooper ATF_TC_BODY(postwait, tc)
3557718be8SEnji Cooper {
3657718be8SEnji Cooper 	sem_t sem;
3757718be8SEnji Cooper 	int rv;
3857718be8SEnji Cooper 
3957718be8SEnji Cooper 	rump_init();
4057718be8SEnji Cooper 
4157718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_init(&sem, 1, 0), 0);
4257718be8SEnji Cooper 
4357718be8SEnji Cooper 	sem_post(&sem);
4457718be8SEnji Cooper 	sem_post(&sem);
4557718be8SEnji Cooper 
4657718be8SEnji Cooper 	sem_wait(&sem);
4757718be8SEnji Cooper 	sem_wait(&sem);
4857718be8SEnji Cooper 	rv = sem_trywait(&sem);
4957718be8SEnji Cooper 	ATF_REQUIRE(errno == EAGAIN);
5057718be8SEnji Cooper 	ATF_REQUIRE(rv == -1);
5157718be8SEnji Cooper }
5257718be8SEnji Cooper 
5357718be8SEnji Cooper ATF_TC(initvalue);
ATF_TC_HEAD(initvalue,tc)5457718be8SEnji Cooper ATF_TC_HEAD(initvalue, tc)
5557718be8SEnji Cooper {
5657718be8SEnji Cooper 
5757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests initialization with a non-zero "
5857718be8SEnji Cooper 	    "value (%s)", LIBNAME);
5957718be8SEnji Cooper }
6057718be8SEnji Cooper 
ATF_TC_BODY(initvalue,tc)6157718be8SEnji Cooper ATF_TC_BODY(initvalue, tc)
6257718be8SEnji Cooper {
6357718be8SEnji Cooper 	sem_t sem;
6457718be8SEnji Cooper 
6557718be8SEnji Cooper 	rump_init();
6657718be8SEnji Cooper 	sem_init(&sem, 1, 4);
6757718be8SEnji Cooper 
6857718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
6957718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
7057718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
7157718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
7257718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
7357718be8SEnji Cooper }
7457718be8SEnji Cooper 
7557718be8SEnji Cooper ATF_TC(destroy);
ATF_TC_HEAD(destroy,tc)7657718be8SEnji Cooper ATF_TC_HEAD(destroy, tc)
7757718be8SEnji Cooper {
7857718be8SEnji Cooper 
7957718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests sem_destroy works (%s)", LIBNAME);
8057718be8SEnji Cooper }
8157718be8SEnji Cooper 
ATF_TC_BODY(destroy,tc)8257718be8SEnji Cooper ATF_TC_BODY(destroy, tc)
8357718be8SEnji Cooper {
8457718be8SEnji Cooper 	sem_t sem;
8557718be8SEnji Cooper 	int rv, i;
8657718be8SEnji Cooper 
8757718be8SEnji Cooper 	rump_init();
8857718be8SEnji Cooper 	for (i = 0; i < 2; i++) {
8957718be8SEnji Cooper 		sem_init(&sem, 1, 1);
9057718be8SEnji Cooper 
9157718be8SEnji Cooper 		ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
9257718be8SEnji Cooper 		ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
9357718be8SEnji Cooper 		ATF_REQUIRE_EQ(sem_destroy(&sem), 0);
9457718be8SEnji Cooper 		rv = sem_trywait(&sem);
9557718be8SEnji Cooper 		ATF_REQUIRE_EQ(errno, EINVAL);
9657718be8SEnji Cooper 		ATF_REQUIRE_EQ(rv, -1);
9757718be8SEnji Cooper 	}
9857718be8SEnji Cooper }
9957718be8SEnji Cooper 
10057718be8SEnji Cooper ATF_TC(busydestroy);
ATF_TC_HEAD(busydestroy,tc)10157718be8SEnji Cooper ATF_TC_HEAD(busydestroy, tc)
10257718be8SEnji Cooper {
10357718be8SEnji Cooper 
10457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests sem_destroy report EBUSY for "
10557718be8SEnji Cooper 	    "a busy semaphore (%s)", LIBNAME);
10657718be8SEnji Cooper }
10757718be8SEnji Cooper 
10857718be8SEnji Cooper static void *
hthread(void * arg)10957718be8SEnji Cooper hthread(void *arg)
11057718be8SEnji Cooper {
11157718be8SEnji Cooper 	sem_t *semmarit = arg;
11257718be8SEnji Cooper 
11357718be8SEnji Cooper 	for (;;) {
11457718be8SEnji Cooper 		sem_post(&semmarit[2]);
11557718be8SEnji Cooper 		sem_wait(&semmarit[1]);
11657718be8SEnji Cooper 		sem_wait(&semmarit[0]);
11757718be8SEnji Cooper 	}
11857718be8SEnji Cooper 
11957718be8SEnji Cooper 	return NULL;
12057718be8SEnji Cooper }
12157718be8SEnji Cooper 
ATF_TC_BODY(busydestroy,tc)12257718be8SEnji Cooper ATF_TC_BODY(busydestroy, tc)
12357718be8SEnji Cooper {
12457718be8SEnji Cooper 	sem_t semmarit[3];
12557718be8SEnji Cooper 	pthread_t pt;
12657718be8SEnji Cooper 	int i;
12757718be8SEnji Cooper 
12857718be8SEnji Cooper 	/* use a unicpu rump kernel.  this means less chance for race */
12957718be8SEnji Cooper 	setenv("RUMP_NCPU", "1", 1);
13057718be8SEnji Cooper 
13157718be8SEnji Cooper 	rump_init();
13257718be8SEnji Cooper 	sem_init(&semmarit[0], 1, 0);
13357718be8SEnji Cooper 	sem_init(&semmarit[1], 1, 0);
13457718be8SEnji Cooper 	sem_init(&semmarit[2], 1, 0);
13557718be8SEnji Cooper 
13657718be8SEnji Cooper 	pthread_create(&pt, NULL, hthread, semmarit);
13757718be8SEnji Cooper 
13857718be8SEnji Cooper 	/*
13957718be8SEnji Cooper 	 * Make a best-effort to catch the other thread with its pants down.
14057718be8SEnji Cooper 	 * We can't do this for sure, can we?  Although, we could reach
14157718be8SEnji Cooper 	 * inside the rump kernel and inquire about the thread's sleep
14257718be8SEnji Cooper 	 * status.
14357718be8SEnji Cooper 	 */
14457718be8SEnji Cooper 	for (i = 0; i < 1000; i++) {
14557718be8SEnji Cooper 		sem_wait(&semmarit[2]);
14657718be8SEnji Cooper 		usleep(1);
14757718be8SEnji Cooper 		if (sem_destroy(&semmarit[1]) == -1)
14857718be8SEnji Cooper 			if (errno == EBUSY)
14957718be8SEnji Cooper 				break;
15057718be8SEnji Cooper 
15157718be8SEnji Cooper 		/*
15257718be8SEnji Cooper 		 * Didn't catch it?  ok, recreate and post to make the
15357718be8SEnji Cooper 		 * other thread run
15457718be8SEnji Cooper 		 */
15557718be8SEnji Cooper 		sem_init(&semmarit[1], 1, 0);
15657718be8SEnji Cooper 		sem_post(&semmarit[0]);
15757718be8SEnji Cooper 		sem_post(&semmarit[1]);
15857718be8SEnji Cooper 
15957718be8SEnji Cooper 	}
16057718be8SEnji Cooper 	if (i == 1000)
16157718be8SEnji Cooper 		atf_tc_fail("sem destroy not reporting EBUSY");
16257718be8SEnji Cooper 
16357718be8SEnji Cooper 	pthread_cancel(pt);
16457718be8SEnji Cooper 	pthread_join(pt, NULL);
16557718be8SEnji Cooper }
16657718be8SEnji Cooper 
16757718be8SEnji Cooper ATF_TC(blockwait);
ATF_TC_HEAD(blockwait,tc)16857718be8SEnji Cooper ATF_TC_HEAD(blockwait, tc)
16957718be8SEnji Cooper {
17057718be8SEnji Cooper 
17157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests sem_wait can handle blocking "
17257718be8SEnji Cooper 	    "(%s)", LIBNAME);
17357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "timeout", "2");
17457718be8SEnji Cooper }
17557718be8SEnji Cooper 
ATF_TC_BODY(blockwait,tc)17657718be8SEnji Cooper ATF_TC_BODY(blockwait, tc)
17757718be8SEnji Cooper {
17857718be8SEnji Cooper 	sem_t semmarit[3];
17957718be8SEnji Cooper 	pthread_t pt;
18057718be8SEnji Cooper 	int i;
18157718be8SEnji Cooper 
18257718be8SEnji Cooper 	rump_init();
18357718be8SEnji Cooper 	sem_init(&semmarit[0], 1, 0);
18457718be8SEnji Cooper 	sem_init(&semmarit[1], 1, 0);
18557718be8SEnji Cooper 	sem_init(&semmarit[2], 1, 0);
18657718be8SEnji Cooper 
18757718be8SEnji Cooper 	pthread_create(&pt, NULL, hthread, semmarit);
18857718be8SEnji Cooper 
18957718be8SEnji Cooper 	/*
19057718be8SEnji Cooper 	 * Make a best-effort.  Unless we're extremely unlucky, we should
19157718be8SEnji Cooper 	 * at least one blocking wait.
19257718be8SEnji Cooper 	 */
19357718be8SEnji Cooper 	for (i = 0; i < 10; i++) {
19457718be8SEnji Cooper 		sem_wait(&semmarit[2]);
19557718be8SEnji Cooper 		usleep(1);
19657718be8SEnji Cooper 		sem_post(&semmarit[0]);
19757718be8SEnji Cooper 		sem_post(&semmarit[1]);
19857718be8SEnji Cooper 
19957718be8SEnji Cooper 	}
20057718be8SEnji Cooper 
20157718be8SEnji Cooper 	pthread_cancel(pt);
20257718be8SEnji Cooper 	pthread_join(pt, NULL);
20357718be8SEnji Cooper }
20457718be8SEnji Cooper 
20557718be8SEnji Cooper ATF_TC(blocktimedwait);
ATF_TC_HEAD(blocktimedwait,tc)20657718be8SEnji Cooper ATF_TC_HEAD(blocktimedwait, tc)
20757718be8SEnji Cooper {
20857718be8SEnji Cooper 
20957718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests sem_timedwait can handle blocking"
21057718be8SEnji Cooper 	    " (%s)", LIBNAME);
21157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "timeout", "2");
21257718be8SEnji Cooper }
21357718be8SEnji Cooper 
ATF_TC_BODY(blocktimedwait,tc)21457718be8SEnji Cooper ATF_TC_BODY(blocktimedwait, tc)
21557718be8SEnji Cooper {
21657718be8SEnji Cooper 	sem_t semid;
21757718be8SEnji Cooper 	struct timespec tp;
21857718be8SEnji Cooper 
21957718be8SEnji Cooper 	rump_init();
22057718be8SEnji Cooper 
22157718be8SEnji Cooper 	clock_gettime(CLOCK_REALTIME, &tp);
22257718be8SEnji Cooper 	tp.tv_nsec += 50000000;
22357718be8SEnji Cooper 	tp.tv_sec += tp.tv_nsec / 1000000000;
22457718be8SEnji Cooper 	tp.tv_nsec %= 1000000000;
22557718be8SEnji Cooper 
22657718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_init(&semid, 1, 0), 0);
22757718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&semid, &tp) == -1);
22857718be8SEnji Cooper }
22957718be8SEnji Cooper 
23057718be8SEnji Cooper ATF_TC(named);
ATF_TC_HEAD(named,tc)23157718be8SEnji Cooper ATF_TC_HEAD(named, tc)
23257718be8SEnji Cooper {
23357718be8SEnji Cooper 
23457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests named semaphores (%s)", LIBNAME);
23557718be8SEnji Cooper }
23657718be8SEnji Cooper 
23757718be8SEnji Cooper /*
23857718be8SEnji Cooper  * Wow, easy naming rules.  it's these times i'm really happy i can
23957718be8SEnji Cooper  * single-step into the kernel.
24057718be8SEnji Cooper  */
24157718be8SEnji Cooper #define SEM1 "/precious_sem"
24257718be8SEnji Cooper #define SEM2 "/justsem"
ATF_TC_BODY(named,tc)24357718be8SEnji Cooper ATF_TC_BODY(named, tc)
24457718be8SEnji Cooper {
24557718be8SEnji Cooper 	sem_t *sem1, *sem2;
24657718be8SEnji Cooper 	void *rv;
24757718be8SEnji Cooper 
24857718be8SEnji Cooper 	rump_init();
24957718be8SEnji Cooper 	sem1 = sem_open(SEM1, 0);
25057718be8SEnji Cooper 	ATF_REQUIRE_EQ(errno, ENOENT);
25157718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem1, NULL);
25257718be8SEnji Cooper 
25357718be8SEnji Cooper 	sem1 = sem_open(SEM1, O_CREAT, 0444, 1);
25457718be8SEnji Cooper 	if (sem1 == NULL)
25557718be8SEnji Cooper 		atf_tc_fail_errno("sem_open O_CREAT");
25657718be8SEnji Cooper 
25757718be8SEnji Cooper 	rv = sem_open(SEM1, O_CREAT | O_EXCL);
25857718be8SEnji Cooper 	ATF_REQUIRE_EQ(errno, EEXIST);
25957718be8SEnji Cooper 	ATF_REQUIRE_EQ(rv, NULL);
26057718be8SEnji Cooper 
26157718be8SEnji Cooper 	sem2 = sem_open(SEM2, O_CREAT, 0444, 0);
26257718be8SEnji Cooper 	if (sem2 == NULL)
26357718be8SEnji Cooper 		atf_tc_fail_errno("sem_open O_CREAT");
26457718be8SEnji Cooper 
26557718be8SEnji Cooper 	/* check that semaphores are independent */
26657718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
26757718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
26857718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
26957718be8SEnji Cooper 
27057718be8SEnji Cooper 	/* check that unlinked remains valid */
27157718be8SEnji Cooper 	sem_unlink(SEM2);
27257718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_post(sem2), 0);
27357718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem2), 0);
27457718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
27557718be8SEnji Cooper 	ATF_REQUIRE_EQ(errno, EAGAIN);
27657718be8SEnji Cooper 
27757718be8SEnji Cooper #if 0 /* see unlink */
27857718be8SEnji Cooper 	/* close it and check that it's gone */
27957718be8SEnji Cooper 	if (sem_close(sem2) != 0)
28057718be8SEnji Cooper 		atf_tc_fail_errno("sem close");
28157718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
28257718be8SEnji Cooper 	ATF_REQUIRE_EQ(errno, EINVAL);
28357718be8SEnji Cooper #endif
28457718be8SEnji Cooper 
28557718be8SEnji Cooper 	/* check that we still have sem1 */
28657718be8SEnji Cooper 	sem_post(sem1);
28757718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
28857718be8SEnji Cooper 	ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
28957718be8SEnji Cooper 	ATF_REQUIRE_EQ(errno, EAGAIN);
29057718be8SEnji Cooper }
29157718be8SEnji Cooper 
29257718be8SEnji Cooper ATF_TC(unlink);
ATF_TC_HEAD(unlink,tc)29357718be8SEnji Cooper ATF_TC_HEAD(unlink, tc)
29457718be8SEnji Cooper {
29557718be8SEnji Cooper 
29657718be8SEnji Cooper 	/* this is currently broken.  i'll append the PR number soon */
29757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "tests unlinked semaphores can be "
29857718be8SEnji Cooper 	    "closed (%s)", LIBNAME);
29957718be8SEnji Cooper }
30057718be8SEnji Cooper 
30157718be8SEnji Cooper #define SEM "/thesem"
ATF_TC_BODY(unlink,tc)30257718be8SEnji Cooper ATF_TC_BODY(unlink, tc)
30357718be8SEnji Cooper {
30457718be8SEnji Cooper 	sem_t *sem;
30557718be8SEnji Cooper 
30657718be8SEnji Cooper 	rump_init();
30757718be8SEnji Cooper 	sem = sem_open(SEM, O_CREAT, 0444, 0);
30857718be8SEnji Cooper 	ATF_REQUIRE(sem);
30957718be8SEnji Cooper 
31057718be8SEnji Cooper 	if (sem_unlink(SEM) == -1)
31157718be8SEnji Cooper 		atf_tc_fail_errno("unlink");
31257718be8SEnji Cooper 	if (sem_close(sem) == -1)
31357718be8SEnji Cooper 		atf_tc_fail_errno("close unlinked semaphore");
31457718be8SEnji Cooper }
31557718be8SEnji Cooper 
31657718be8SEnji Cooper /* use rump calls for libpthread _ksem_foo() calls */
31757718be8SEnji Cooper #define F1(name, a) int _ksem_##name(a); \
31857718be8SEnji Cooper int _ksem_##name(a v1) {return rump_sys__ksem_##name(v1);}
31957718be8SEnji Cooper #define F2(name, a, b) int _ksem_##name(a, b); \
32057718be8SEnji Cooper int _ksem_##name(a v1, b v2) {return rump_sys__ksem_##name(v1, v2);}
32157718be8SEnji Cooper F2(init, unsigned int, intptr_t *);
32257718be8SEnji Cooper F1(close, intptr_t);
32357718be8SEnji Cooper F1(destroy, intptr_t);
32457718be8SEnji Cooper F1(post, intptr_t);
32557718be8SEnji Cooper F1(unlink, const char *);
32657718be8SEnji Cooper F1(trywait, intptr_t);
32757718be8SEnji Cooper F1(wait, intptr_t);
32857718be8SEnji Cooper F2(getvalue, intptr_t, unsigned int *);
32957718be8SEnji Cooper F2(timedwait, intptr_t, const struct timespec *);
33057718be8SEnji Cooper int _ksem_open(const char *, int, mode_t, unsigned int, intptr_t *);
_ksem_open(const char * a,int b,mode_t c,unsigned int d,intptr_t * e)33157718be8SEnji Cooper int _ksem_open(const char *a, int b, mode_t c, unsigned int d, intptr_t *e)
33257718be8SEnji Cooper     {return rump_sys__ksem_open(a,b,c,d,e);}
333