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