1 1.6 wiz /* $NetBSD: t_sem.c,v 1.6 2021/12/14 16:25:11 wiz Exp $ */ 2 1.1 jmmv 3 1.1 jmmv /* 4 1.4 thorpej * Copyright (c) 2008, 2010, 2019 The NetBSD Foundation, Inc. 5 1.1 jmmv * All rights reserved. 6 1.1 jmmv * 7 1.1 jmmv * Redistribution and use in source and binary forms, with or without 8 1.1 jmmv * modification, are permitted provided that the following conditions 9 1.1 jmmv * are met: 10 1.1 jmmv * 1. Redistributions of source code must retain the above copyright 11 1.1 jmmv * notice, this list of conditions and the following disclaimer. 12 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmmv * notice, this list of conditions and the following disclaimer in the 14 1.1 jmmv * documentation and/or other materials provided with the distribution. 15 1.1 jmmv * 16 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE. 27 1.1 jmmv */ 28 1.1 jmmv 29 1.1 jmmv /* 30 1.1 jmmv * Copyright (C) 2000 Jason Evans <jasone (at) freebsd.org>. 31 1.1 jmmv * All rights reserved. 32 1.1 jmmv * 33 1.1 jmmv * Redistribution and use in source and binary forms, with or without 34 1.1 jmmv * modification, are permitted provided that the following conditions 35 1.1 jmmv * are met: 36 1.1 jmmv * 1. Redistributions of source code must retain the above copyright 37 1.1 jmmv * notice(s), this list of conditions and the following disclaimer as 38 1.1 jmmv * the first lines of this file unmodified other than the possible 39 1.1 jmmv * addition of one or more copyright notices. 40 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright 41 1.1 jmmv * notice(s), this list of conditions and the following disclaimer in 42 1.1 jmmv * the documentation and/or other materials provided with the 43 1.1 jmmv * distribution. 44 1.1 jmmv * 45 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 46 1.1 jmmv * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 1.1 jmmv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 49 1.1 jmmv * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 52 1.1 jmmv * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 1.1 jmmv * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 54 1.1 jmmv * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 55 1.1 jmmv * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 1.1 jmmv */ 57 1.1 jmmv 58 1.1 jmmv #include <sys/cdefs.h> 59 1.4 thorpej __COPYRIGHT("@(#) Copyright (c) 2008, 2010, 2019\ 60 1.1 jmmv The NetBSD Foundation, inc. All rights reserved."); 61 1.6 wiz __RCSID("$NetBSD: t_sem.c,v 1.6 2021/12/14 16:25:11 wiz Exp $"); 62 1.1 jmmv 63 1.4 thorpej #include <sys/mman.h> 64 1.1 jmmv #include <sys/wait.h> 65 1.1 jmmv 66 1.1 jmmv #include <errno.h> 67 1.1 jmmv #include <fcntl.h> 68 1.1 jmmv #include <semaphore.h> 69 1.1 jmmv #include <stdio.h> 70 1.1 jmmv #include <unistd.h> 71 1.1 jmmv 72 1.1 jmmv #include <atf-c.h> 73 1.1 jmmv 74 1.1 jmmv #define NCHILDREN 10 75 1.1 jmmv 76 1.3 christos ATF_TC_WITH_CLEANUP(basic); 77 1.1 jmmv ATF_TC_HEAD(basic, tc) 78 1.1 jmmv { 79 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Checks basic functionality of POSIX " 80 1.1 jmmv "semaphores"); 81 1.1 jmmv } 82 1.1 jmmv ATF_TC_BODY(basic, tc) 83 1.1 jmmv { 84 1.1 jmmv int val; 85 1.1 jmmv sem_t *sem_b; 86 1.1 jmmv 87 1.2 njoly if (sysconf(_SC_SEMAPHORES) == -1) 88 1.2 njoly atf_tc_skip("POSIX semaphores not supported"); 89 1.1 jmmv 90 1.1 jmmv sem_b = sem_open("/sem_b", O_CREAT | O_EXCL, 0644, 0); 91 1.1 jmmv ATF_REQUIRE(sem_b != SEM_FAILED); 92 1.1 jmmv 93 1.1 jmmv ATF_REQUIRE_EQ(sem_getvalue(sem_b, &val), 0); 94 1.1 jmmv ATF_REQUIRE_EQ(val, 0); 95 1.1 jmmv 96 1.1 jmmv ATF_REQUIRE_EQ(sem_post(sem_b), 0); 97 1.1 jmmv ATF_REQUIRE_EQ(sem_getvalue(sem_b, &val), 0); 98 1.1 jmmv ATF_REQUIRE_EQ(val, 1); 99 1.1 jmmv 100 1.1 jmmv ATF_REQUIRE_EQ(sem_wait(sem_b), 0); 101 1.1 jmmv ATF_REQUIRE_EQ(sem_trywait(sem_b), -1); 102 1.1 jmmv ATF_REQUIRE_EQ(errno, EAGAIN); 103 1.1 jmmv ATF_REQUIRE_EQ(sem_post(sem_b), 0); 104 1.1 jmmv ATF_REQUIRE_EQ(sem_trywait(sem_b), 0); 105 1.1 jmmv ATF_REQUIRE_EQ(sem_post(sem_b), 0); 106 1.1 jmmv ATF_REQUIRE_EQ(sem_wait(sem_b), 0); 107 1.1 jmmv ATF_REQUIRE_EQ(sem_post(sem_b), 0); 108 1.1 jmmv 109 1.1 jmmv ATF_REQUIRE_EQ(sem_close(sem_b), 0); 110 1.1 jmmv ATF_REQUIRE_EQ(sem_unlink("/sem_b"), 0); 111 1.1 jmmv } 112 1.3 christos ATF_TC_CLEANUP(basic, tc) 113 1.3 christos { 114 1.3 christos (void)sem_unlink("/sem_b"); 115 1.3 christos } 116 1.1 jmmv 117 1.3 christos ATF_TC_WITH_CLEANUP(child); 118 1.1 jmmv ATF_TC_HEAD(child, tc) 119 1.1 jmmv { 120 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Checks using semaphores to synchronize " 121 1.1 jmmv "parent with multiple child processes"); 122 1.1 jmmv } 123 1.1 jmmv ATF_TC_BODY(child, tc) 124 1.1 jmmv { 125 1.1 jmmv pid_t children[NCHILDREN]; 126 1.1 jmmv unsigned i, j; 127 1.1 jmmv sem_t *sem_a; 128 1.1 jmmv int status; 129 1.1 jmmv 130 1.1 jmmv pid_t pid; 131 1.1 jmmv 132 1.3 christos if (sysconf(_SC_SEMAPHORES) == -1) 133 1.2 njoly atf_tc_skip("POSIX semaphores not supported"); 134 1.2 njoly 135 1.1 jmmv sem_a = sem_open("/sem_a", O_CREAT | O_EXCL, 0644, 0); 136 1.1 jmmv ATF_REQUIRE(sem_a != SEM_FAILED); 137 1.1 jmmv 138 1.1 jmmv for (j = 1; j <= 2; j++) { 139 1.1 jmmv for (i = 0; i < NCHILDREN; i++) { 140 1.1 jmmv switch ((pid = fork())) { 141 1.1 jmmv case -1: 142 1.1 jmmv atf_tc_fail("fork() returned -1"); 143 1.1 jmmv case 0: 144 1.1 jmmv printf("PID %d waiting for semaphore...\n", 145 1.1 jmmv getpid()); 146 1.1 jmmv ATF_REQUIRE_MSG(sem_wait(sem_a) == 0, 147 1.1 jmmv "sem_wait failed; iteration %d", j); 148 1.1 jmmv printf("PID %d got semaphore\n", getpid()); 149 1.1 jmmv _exit(0); 150 1.1 jmmv default: 151 1.1 jmmv children[i] = pid; 152 1.1 jmmv break; 153 1.1 jmmv } 154 1.1 jmmv } 155 1.1 jmmv 156 1.1 jmmv for (i = 0; i < NCHILDREN; i++) { 157 1.1 jmmv sleep(1); 158 1.1 jmmv printf("main loop %d: posting...\n", j); 159 1.1 jmmv ATF_REQUIRE_EQ(sem_post(sem_a), 0); 160 1.1 jmmv } 161 1.1 jmmv 162 1.1 jmmv for (i = 0; i < NCHILDREN; i++) { 163 1.1 jmmv ATF_REQUIRE_EQ(waitpid(children[i], &status, 0), children[i]); 164 1.1 jmmv ATF_REQUIRE(WIFEXITED(status)); 165 1.1 jmmv ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); 166 1.1 jmmv } 167 1.1 jmmv } 168 1.1 jmmv 169 1.1 jmmv ATF_REQUIRE_EQ(sem_close(sem_a), 0); 170 1.1 jmmv ATF_REQUIRE_EQ(sem_unlink("/sem_a"), 0); 171 1.1 jmmv } 172 1.3 christos ATF_TC_CLEANUP(child, tc) 173 1.3 christos { 174 1.3 christos (void)sem_unlink("/sem_a"); 175 1.3 christos } 176 1.1 jmmv 177 1.4 thorpej ATF_TC_WITH_CLEANUP(pshared); 178 1.4 thorpej ATF_TC_HEAD(pshared, tc) 179 1.4 thorpej { 180 1.4 thorpej atf_tc_set_md_var(tc, "descr", "Checks using pshared unnamed " 181 1.4 thorpej "semaphores to synchronize a master with multiple slave processes"); 182 1.4 thorpej } 183 1.4 thorpej 184 1.4 thorpej struct shared_region { 185 1.4 thorpej sem_t the_sem; 186 1.4 thorpej }; 187 1.4 thorpej 188 1.4 thorpej static struct shared_region * 189 1.4 thorpej get_shared_region(int o_flags) 190 1.4 thorpej { 191 1.4 thorpej 192 1.4 thorpej int fd = shm_open("/shm_semtest_a", o_flags, 0644); 193 1.4 thorpej ATF_REQUIRE(fd != -1); 194 1.4 thorpej 195 1.4 thorpej ATF_REQUIRE_EQ(ftruncate(fd, sizeof(struct shared_region)), 0); 196 1.4 thorpej 197 1.4 thorpej void *rv = mmap(NULL, sizeof(struct shared_region), 198 1.4 thorpej PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 199 1.4 thorpej ATF_REQUIRE(rv != MAP_FAILED); 200 1.4 thorpej 201 1.4 thorpej (void)close(fd); 202 1.4 thorpej 203 1.4 thorpej return rv; 204 1.4 thorpej } 205 1.4 thorpej 206 1.4 thorpej static void 207 1.4 thorpej put_shared_region(struct shared_region *r) 208 1.4 thorpej { 209 1.4 thorpej ATF_REQUIRE_EQ(munmap(r, sizeof(struct shared_region)), 0); 210 1.4 thorpej } 211 1.4 thorpej 212 1.4 thorpej ATF_TC_BODY(pshared, tc) 213 1.4 thorpej { 214 1.5 msaitoh struct shared_region *master_region, *slave_region; 215 1.4 thorpej 216 1.4 thorpej if (sysconf(_SC_SEMAPHORES) == -1) 217 1.4 thorpej atf_tc_skip("POSIX semaphores not supported"); 218 1.4 thorpej 219 1.4 thorpej /* 220 1.4 thorpej * Create a shared memory region to contain the pshared 221 1.4 thorpej * semaphore, create the semaphore there, and then detach 222 1.4 thorpej * from the shared memory region to ensure that our child 223 1.4 thorpej * processes will be getting at it from scratch. 224 1.4 thorpej */ 225 1.4 thorpej master_region = get_shared_region(O_RDWR | O_CREAT | O_EXCL); 226 1.4 thorpej ATF_REQUIRE(sem_init(&master_region->the_sem, 1, 0) == 0); 227 1.4 thorpej put_shared_region(master_region); 228 1.4 thorpej 229 1.4 thorpej /* 230 1.4 thorpej * Now execute a test that's essentially equivalent to the 231 1.4 thorpej * "child" test above, but using the pshared semaphore in the 232 1.4 thorpej * shared memory region. 233 1.4 thorpej */ 234 1.4 thorpej 235 1.4 thorpej pid_t pid, children[NCHILDREN]; 236 1.4 thorpej unsigned i, j; 237 1.4 thorpej int status; 238 1.4 thorpej 239 1.4 thorpej for (j = 1; j <= 2; j++) { 240 1.4 thorpej for (i = 0; i < NCHILDREN; i++) { 241 1.4 thorpej switch ((pid = fork())) { 242 1.4 thorpej case -1: 243 1.4 thorpej atf_tc_fail("fork() returned -1"); 244 1.4 thorpej case 0: 245 1.4 thorpej slave_region = get_shared_region(O_RDWR); 246 1.4 thorpej printf("PID %d waiting for semaphore...\n", 247 1.4 thorpej getpid()); 248 1.4 thorpej ATF_REQUIRE_MSG(sem_wait(&slave_region->the_sem) 249 1.4 thorpej == 0, 250 1.4 thorpej "sem_wait failed; iteration %d", j); 251 1.4 thorpej printf("PID %d got semaphore\n", getpid()); 252 1.4 thorpej _exit(0); 253 1.4 thorpej default: 254 1.4 thorpej children[i] = pid; 255 1.4 thorpej break; 256 1.4 thorpej } 257 1.4 thorpej } 258 1.4 thorpej 259 1.4 thorpej master_region = get_shared_region(O_RDWR); 260 1.4 thorpej 261 1.4 thorpej for (i = 0; i < NCHILDREN; i++) { 262 1.4 thorpej sleep(1); 263 1.4 thorpej printf("main loop %d: posting...\n", j); 264 1.4 thorpej ATF_REQUIRE_EQ(sem_post(&master_region->the_sem), 0); 265 1.4 thorpej } 266 1.4 thorpej 267 1.4 thorpej put_shared_region(master_region); 268 1.4 thorpej 269 1.4 thorpej for (i = 0; i < NCHILDREN; i++) { 270 1.4 thorpej ATF_REQUIRE_EQ(waitpid(children[i], &status, 0), children[i]); 271 1.4 thorpej ATF_REQUIRE(WIFEXITED(status)); 272 1.4 thorpej ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); 273 1.4 thorpej } 274 1.4 thorpej } 275 1.4 thorpej 276 1.4 thorpej master_region = get_shared_region(O_RDWR); 277 1.4 thorpej ATF_REQUIRE_EQ(sem_destroy(&master_region->the_sem), 0); 278 1.4 thorpej put_shared_region(master_region); 279 1.4 thorpej 280 1.4 thorpej ATF_REQUIRE_EQ(shm_unlink("/shm_semtest_a"), 0); 281 1.4 thorpej } 282 1.4 thorpej ATF_TC_CLEANUP(pshared, tc) 283 1.4 thorpej { 284 1.4 thorpej /* 285 1.4 thorpej * The kernel will g/c the pshared semaphore when the process that 286 1.4 thorpej * created it exits, so no need to include that in the cleanup here. 287 1.4 thorpej */ 288 1.4 thorpej (void)shm_unlink("/shm_semtest_a"); 289 1.4 thorpej } 290 1.4 thorpej 291 1.4 thorpej ATF_TC_WITH_CLEANUP(invalid_ops); 292 1.4 thorpej ATF_TC_HEAD(invalid_ops, tc) 293 1.4 thorpej { 294 1.4 thorpej atf_tc_set_md_var(tc, "descr", "Validates behavior when calling " 295 1.4 thorpej "bad operations for the semaphore type"); 296 1.4 thorpej } 297 1.4 thorpej ATF_TC_BODY(invalid_ops, tc) 298 1.4 thorpej { 299 1.4 thorpej sem_t *sem; 300 1.4 thorpej sem_t the_sem; 301 1.4 thorpej 302 1.4 thorpej sem = sem_open("/sem_c", O_CREAT | O_EXCL, 0644, 0); 303 1.4 thorpej ATF_REQUIRE(sem != SEM_FAILED); 304 1.4 thorpej ATF_REQUIRE(sem_destroy(sem) == -1 && errno == EINVAL); 305 1.4 thorpej ATF_REQUIRE_EQ(sem_close(sem), 0); 306 1.4 thorpej 307 1.4 thorpej ATF_REQUIRE_EQ(sem_init(&the_sem, 0, 0), 0); 308 1.4 thorpej ATF_REQUIRE(sem_close(&the_sem) == -1 && errno == EINVAL); 309 1.4 thorpej ATF_REQUIRE_EQ(sem_destroy(&the_sem), 0); 310 1.4 thorpej } 311 1.4 thorpej ATF_TC_CLEANUP(invalid_ops, tc) 312 1.4 thorpej { 313 1.4 thorpej (void)sem_unlink("/sem_c"); 314 1.4 thorpej } 315 1.4 thorpej 316 1.6 wiz ATF_TC_WITH_CLEANUP(sem_open_address); 317 1.6 wiz ATF_TC_HEAD(sem_open_address, tc) 318 1.6 wiz { 319 1.6 wiz atf_tc_set_md_var(tc, "descr", "Validate that multiple sem_open calls " 320 1.6 wiz "return the same address"); 321 1.6 wiz } 322 1.6 wiz ATF_TC_BODY(sem_open_address, tc) 323 1.6 wiz { 324 1.6 wiz sem_t *sem, *sem2, *sem3; 325 1.6 wiz atf_tc_expect_fail("kern/56549: consecutive sem_open() do not return the same address"); 326 1.6 wiz sem = sem_open("/sem_d", O_CREAT | O_EXCL, 0777, 0); 327 1.6 wiz ATF_REQUIRE(sem != SEM_FAILED); 328 1.6 wiz sem2 = sem_open("/sem_d", O_CREAT | O_EXCL, 0777, 0); 329 1.6 wiz ATF_REQUIRE(sem2 == SEM_FAILED && errno == EEXIST); 330 1.6 wiz sem3 = sem_open("/sem_d", 0); 331 1.6 wiz ATF_REQUIRE(sem3 != SEM_FAILED); 332 1.6 wiz ATF_REQUIRE(sem == sem3); 333 1.6 wiz ATF_REQUIRE_EQ(sem_close(sem3), 0); 334 1.6 wiz ATF_REQUIRE_EQ(sem_close(sem), 0); 335 1.6 wiz ATF_REQUIRE_EQ(sem_unlink("/sem_d"), 0); 336 1.6 wiz } 337 1.6 wiz ATF_TC_CLEANUP(sem_open_address, tc) 338 1.6 wiz { 339 1.6 wiz (void)sem_unlink("/sem_d"); 340 1.6 wiz } 341 1.6 wiz 342 1.1 jmmv ATF_TP_ADD_TCS(tp) 343 1.1 jmmv { 344 1.1 jmmv 345 1.1 jmmv ATF_TP_ADD_TC(tp, basic); 346 1.1 jmmv ATF_TP_ADD_TC(tp, child); 347 1.4 thorpej ATF_TP_ADD_TC(tp, pshared); 348 1.4 thorpej ATF_TP_ADD_TC(tp, invalid_ops); 349 1.6 wiz ATF_TP_ADD_TC(tp, sem_open_address); 350 1.1 jmmv 351 1.1 jmmv return atf_no_error(); 352 1.1 jmmv } 353