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