1272343Sngie/* $NetBSD: sem.c,v 1.10 2012/03/09 14:25:34 joerg Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * Common code for semaphore tests. This can be included both into 5272343Sngie * programs using librt and libpthread. 6272343Sngie */ 7272343Sngie 8272343Sngie#include <sys/types.h> 9272343Sngie 10272343Sngie#include <rump/rump.h> 11272343Sngie#include <rump/rump_syscalls.h> 12272343Sngie 13272343Sngie#include <atf-c.h> 14272343Sngie#include <errno.h> 15272343Sngie#include <fcntl.h> 16272343Sngie#include <pthread.h> 17272343Sngie#include <semaphore.h> 18272343Sngie#include <sched.h> 19272343Sngie#include <stdint.h> 20272343Sngie#include <stdio.h> 21272343Sngie#include <stdlib.h> 22272343Sngie#include <unistd.h> 23272343Sngie 24272343Sngie#include "../../h_macros.h" 25272343Sngie 26272343SngieATF_TC(postwait); 27272343SngieATF_TC_HEAD(postwait, tc) 28272343Sngie{ 29272343Sngie 30272343Sngie atf_tc_set_md_var(tc, "descr", "tests post and wait from a " 31272343Sngie "single thread (%s)", LIBNAME); 32272343Sngie} 33272343Sngie 34272343SngieATF_TC_BODY(postwait, tc) 35272343Sngie{ 36272343Sngie sem_t sem; 37272343Sngie int rv; 38272343Sngie 39272343Sngie rump_init(); 40272343Sngie 41272343Sngie ATF_REQUIRE_EQ(sem_init(&sem, 1, 0), 0); 42272343Sngie 43272343Sngie sem_post(&sem); 44272343Sngie sem_post(&sem); 45272343Sngie 46272343Sngie sem_wait(&sem); 47272343Sngie sem_wait(&sem); 48272343Sngie rv = sem_trywait(&sem); 49272343Sngie ATF_REQUIRE(errno == EAGAIN); 50272343Sngie ATF_REQUIRE(rv == -1); 51272343Sngie} 52272343Sngie 53272343SngieATF_TC(initvalue); 54272343SngieATF_TC_HEAD(initvalue, tc) 55272343Sngie{ 56272343Sngie 57272343Sngie atf_tc_set_md_var(tc, "descr", "tests initialization with a non-zero " 58272343Sngie "value (%s)", LIBNAME); 59272343Sngie} 60272343Sngie 61272343SngieATF_TC_BODY(initvalue, tc) 62272343Sngie{ 63272343Sngie sem_t sem; 64272343Sngie 65272343Sngie rump_init(); 66272343Sngie sem_init(&sem, 1, 4); 67272343Sngie 68272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), 0); 69272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), 0); 70272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), 0); 71272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), 0); 72272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), -1); 73272343Sngie} 74272343Sngie 75272343SngieATF_TC(destroy); 76272343SngieATF_TC_HEAD(destroy, tc) 77272343Sngie{ 78272343Sngie 79272343Sngie atf_tc_set_md_var(tc, "descr", "tests sem_destroy works (%s)", LIBNAME); 80272343Sngie} 81272343Sngie 82272343SngieATF_TC_BODY(destroy, tc) 83272343Sngie{ 84272343Sngie sem_t sem; 85272343Sngie int rv, i; 86272343Sngie 87272343Sngie rump_init(); 88272343Sngie for (i = 0; i < 2; i++) { 89272343Sngie sem_init(&sem, 1, 1); 90272343Sngie 91272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), 0); 92272343Sngie ATF_REQUIRE_EQ(sem_trywait(&sem), -1); 93272343Sngie ATF_REQUIRE_EQ(sem_destroy(&sem), 0); 94272343Sngie rv = sem_trywait(&sem); 95272343Sngie ATF_REQUIRE_EQ(errno, EINVAL); 96272343Sngie ATF_REQUIRE_EQ(rv, -1); 97272343Sngie } 98272343Sngie} 99272343Sngie 100272343SngieATF_TC(busydestroy); 101272343SngieATF_TC_HEAD(busydestroy, tc) 102272343Sngie{ 103272343Sngie 104272343Sngie atf_tc_set_md_var(tc, "descr", "tests sem_destroy report EBUSY for " 105272343Sngie "a busy semaphore (%s)", LIBNAME); 106272343Sngie} 107272343Sngie 108272343Sngiestatic void * 109272343Sngiehthread(void *arg) 110272343Sngie{ 111272343Sngie sem_t *semmarit = arg; 112272343Sngie 113272343Sngie for (;;) { 114272343Sngie sem_post(&semmarit[2]); 115272343Sngie sem_wait(&semmarit[1]); 116272343Sngie sem_wait(&semmarit[0]); 117272343Sngie } 118272343Sngie 119272343Sngie return NULL; 120272343Sngie} 121272343Sngie 122272343SngieATF_TC_BODY(busydestroy, tc) 123272343Sngie{ 124272343Sngie sem_t semmarit[3]; 125272343Sngie pthread_t pt; 126272343Sngie int i; 127272343Sngie 128272343Sngie /* use a unicpu rump kernel. this means less chance for race */ 129272343Sngie setenv("RUMP_NCPU", "1", 1); 130272343Sngie 131272343Sngie rump_init(); 132272343Sngie sem_init(&semmarit[0], 1, 0); 133272343Sngie sem_init(&semmarit[1], 1, 0); 134272343Sngie sem_init(&semmarit[2], 1, 0); 135272343Sngie 136272343Sngie pthread_create(&pt, NULL, hthread, semmarit); 137272343Sngie 138272343Sngie /* 139272343Sngie * Make a best-effort to catch the other thread with its pants down. 140272343Sngie * We can't do this for sure, can we? Although, we could reach 141272343Sngie * inside the rump kernel and inquire about the thread's sleep 142272343Sngie * status. 143272343Sngie */ 144272343Sngie for (i = 0; i < 1000; i++) { 145272343Sngie sem_wait(&semmarit[2]); 146272343Sngie usleep(1); 147272343Sngie if (sem_destroy(&semmarit[1]) == -1) 148272343Sngie if (errno == EBUSY) 149272343Sngie break; 150272343Sngie 151272343Sngie /* 152272343Sngie * Didn't catch it? ok, recreate and post to make the 153272343Sngie * other thread run 154272343Sngie */ 155272343Sngie sem_init(&semmarit[1], 1, 0); 156272343Sngie sem_post(&semmarit[0]); 157272343Sngie sem_post(&semmarit[1]); 158272343Sngie 159272343Sngie } 160272343Sngie if (i == 1000) 161272343Sngie atf_tc_fail("sem destroy not reporting EBUSY"); 162272343Sngie 163272343Sngie pthread_cancel(pt); 164272343Sngie pthread_join(pt, NULL); 165272343Sngie} 166272343Sngie 167272343SngieATF_TC(blockwait); 168272343SngieATF_TC_HEAD(blockwait, tc) 169272343Sngie{ 170272343Sngie 171272343Sngie atf_tc_set_md_var(tc, "descr", "tests sem_wait can handle blocking " 172272343Sngie "(%s)", LIBNAME); 173272343Sngie atf_tc_set_md_var(tc, "timeout", "2"); 174272343Sngie} 175272343Sngie 176272343SngieATF_TC_BODY(blockwait, tc) 177272343Sngie{ 178272343Sngie sem_t semmarit[3]; 179272343Sngie pthread_t pt; 180272343Sngie int i; 181272343Sngie 182272343Sngie rump_init(); 183272343Sngie sem_init(&semmarit[0], 1, 0); 184272343Sngie sem_init(&semmarit[1], 1, 0); 185272343Sngie sem_init(&semmarit[2], 1, 0); 186272343Sngie 187272343Sngie pthread_create(&pt, NULL, hthread, semmarit); 188272343Sngie 189272343Sngie /* 190272343Sngie * Make a best-effort. Unless we're extremely unlucky, we should 191272343Sngie * at least one blocking wait. 192272343Sngie */ 193272343Sngie for (i = 0; i < 10; i++) { 194272343Sngie sem_wait(&semmarit[2]); 195272343Sngie usleep(1); 196272343Sngie sem_post(&semmarit[0]); 197272343Sngie sem_post(&semmarit[1]); 198272343Sngie 199272343Sngie } 200272343Sngie 201272343Sngie pthread_cancel(pt); 202272343Sngie pthread_join(pt, NULL); 203272343Sngie} 204272343Sngie 205272343SngieATF_TC(blocktimedwait); 206272343SngieATF_TC_HEAD(blocktimedwait, tc) 207272343Sngie{ 208272343Sngie 209272343Sngie atf_tc_set_md_var(tc, "descr", "tests sem_timedwait can handle blocking" 210272343Sngie " (%s)", LIBNAME); 211272343Sngie atf_tc_set_md_var(tc, "timeout", "2"); 212272343Sngie} 213272343Sngie 214272343SngieATF_TC_BODY(blocktimedwait, tc) 215272343Sngie{ 216272343Sngie sem_t semid; 217272343Sngie struct timespec tp; 218272343Sngie 219272343Sngie rump_init(); 220272343Sngie 221272343Sngie clock_gettime(CLOCK_REALTIME, &tp); 222272343Sngie tp.tv_nsec += 50000000; 223272343Sngie tp.tv_sec += tp.tv_nsec / 1000000000; 224272343Sngie tp.tv_nsec %= 1000000000; 225272343Sngie 226272343Sngie ATF_REQUIRE_EQ(sem_init(&semid, 1, 0), 0); 227272343Sngie ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&semid, &tp) == -1); 228272343Sngie} 229272343Sngie 230272343SngieATF_TC(named); 231272343SngieATF_TC_HEAD(named, tc) 232272343Sngie{ 233272343Sngie 234272343Sngie atf_tc_set_md_var(tc, "descr", "tests named semaphores (%s)", LIBNAME); 235272343Sngie} 236272343Sngie 237272343Sngie/* 238272343Sngie * Wow, easy naming rules. it's these times i'm really happy i can 239272343Sngie * single-step into the kernel. 240272343Sngie */ 241272343Sngie#define SEM1 "/precious_sem" 242272343Sngie#define SEM2 "/justsem" 243272343SngieATF_TC_BODY(named, tc) 244272343Sngie{ 245272343Sngie sem_t *sem1, *sem2; 246272343Sngie void *rv; 247272343Sngie 248272343Sngie rump_init(); 249272343Sngie sem1 = sem_open(SEM1, 0); 250272343Sngie ATF_REQUIRE_EQ(errno, ENOENT); 251272343Sngie ATF_REQUIRE_EQ(sem1, NULL); 252272343Sngie 253272343Sngie sem1 = sem_open(SEM1, O_CREAT, 0444, 1); 254272343Sngie if (sem1 == NULL) 255272343Sngie atf_tc_fail_errno("sem_open O_CREAT"); 256272343Sngie 257272343Sngie rv = sem_open(SEM1, O_CREAT | O_EXCL); 258272343Sngie ATF_REQUIRE_EQ(errno, EEXIST); 259272343Sngie ATF_REQUIRE_EQ(rv, NULL); 260272343Sngie 261272343Sngie sem2 = sem_open(SEM2, O_CREAT, 0444, 0); 262272343Sngie if (sem2 == NULL) 263272343Sngie atf_tc_fail_errno("sem_open O_CREAT"); 264272343Sngie 265272343Sngie /* check that semaphores are independent */ 266272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem2), -1); 267272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem1), 0); 268272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem1), -1); 269272343Sngie 270272343Sngie /* check that unlinked remains valid */ 271272343Sngie sem_unlink(SEM2); 272272343Sngie ATF_REQUIRE_EQ(sem_post(sem2), 0); 273272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem2), 0); 274272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem2), -1); 275272343Sngie ATF_REQUIRE_EQ(errno, EAGAIN); 276272343Sngie 277272343Sngie#if 0 /* see unlink */ 278272343Sngie /* close it and check that it's gone */ 279272343Sngie if (sem_close(sem2) != 0) 280272343Sngie atf_tc_fail_errno("sem close"); 281272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem2), -1); 282272343Sngie ATF_REQUIRE_EQ(errno, EINVAL); 283272343Sngie#endif 284272343Sngie 285272343Sngie /* check that we still have sem1 */ 286272343Sngie sem_post(sem1); 287272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem1), 0); 288272343Sngie ATF_REQUIRE_EQ(sem_trywait(sem1), -1); 289272343Sngie ATF_REQUIRE_EQ(errno, EAGAIN); 290272343Sngie} 291272343Sngie 292272343SngieATF_TC(unlink); 293272343SngieATF_TC_HEAD(unlink, tc) 294272343Sngie{ 295272343Sngie 296272343Sngie /* this is currently broken. i'll append the PR number soon */ 297272343Sngie atf_tc_set_md_var(tc, "descr", "tests unlinked semaphores can be " 298272343Sngie "closed (%s)", LIBNAME); 299272343Sngie} 300272343Sngie 301272343Sngie#define SEM "/thesem" 302272343SngieATF_TC_BODY(unlink, tc) 303272343Sngie{ 304272343Sngie sem_t *sem; 305272343Sngie 306272343Sngie rump_init(); 307272343Sngie sem = sem_open(SEM, O_CREAT, 0444, 0); 308272343Sngie ATF_REQUIRE(sem); 309272343Sngie 310272343Sngie if (sem_unlink(SEM) == -1) 311272343Sngie atf_tc_fail_errno("unlink"); 312272343Sngie if (sem_close(sem) == -1) 313272343Sngie atf_tc_fail_errno("close unlinked semaphore"); 314272343Sngie} 315272343Sngie 316272343Sngie/* use rump calls for libpthread _ksem_foo() calls */ 317272343Sngie#define F1(name, a) int _ksem_##name(a); \ 318272343Sngieint _ksem_##name(a v1) {return rump_sys__ksem_##name(v1);} 319272343Sngie#define F2(name, a, b) int _ksem_##name(a, b); \ 320272343Sngieint _ksem_##name(a v1, b v2) {return rump_sys__ksem_##name(v1, v2);} 321272343SngieF2(init, unsigned int, intptr_t *); 322272343SngieF1(close, intptr_t); 323272343SngieF1(destroy, intptr_t); 324272343SngieF1(post, intptr_t); 325272343SngieF1(unlink, const char *); 326272343SngieF1(trywait, intptr_t); 327272343SngieF1(wait, intptr_t); 328272343SngieF2(getvalue, intptr_t, unsigned int *); 329272343SngieF2(timedwait, intptr_t, const struct timespec *); 330272343Sngieint _ksem_open(const char *, int, mode_t, unsigned int, intptr_t *); 331272343Sngieint _ksem_open(const char *a, int b, mode_t c, unsigned int d, intptr_t *e) 332272343Sngie {return rump_sys__ksem_open(a,b,c,d,e);} 333