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); 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 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); 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 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); 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 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); 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 * 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 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); 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 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); 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 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); 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" 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); 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" 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 *); 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