16bc1e9cdSJohn Baldwin /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 46bc1e9cdSJohn Baldwin * Copyright (c) 2008 Yahoo!, Inc. 56bc1e9cdSJohn Baldwin * All rights reserved. 66bc1e9cdSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 76bc1e9cdSJohn Baldwin * 86bc1e9cdSJohn Baldwin * Redistribution and use in source and binary forms, with or without 96bc1e9cdSJohn Baldwin * modification, are permitted provided that the following conditions 106bc1e9cdSJohn Baldwin * are met: 116bc1e9cdSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 126bc1e9cdSJohn Baldwin * notice, this list of conditions and the following disclaimer. 136bc1e9cdSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 146bc1e9cdSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 156bc1e9cdSJohn Baldwin * documentation and/or other materials provided with the distribution. 166bc1e9cdSJohn Baldwin * 3. Neither the name of the author nor the names of any co-contributors 176bc1e9cdSJohn Baldwin * may be used to endorse or promote products derived from this software 186bc1e9cdSJohn Baldwin * without specific prior written permission. 196bc1e9cdSJohn Baldwin * 206bc1e9cdSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 216bc1e9cdSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 226bc1e9cdSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 236bc1e9cdSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 246bc1e9cdSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 256bc1e9cdSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 266bc1e9cdSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 276bc1e9cdSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 286bc1e9cdSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 296bc1e9cdSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 306bc1e9cdSJohn Baldwin * SUCH DAMAGE. 316bc1e9cdSJohn Baldwin */ 326bc1e9cdSJohn Baldwin 336bc1e9cdSJohn Baldwin #include <sys/cdefs.h> 346bc1e9cdSJohn Baldwin __FBSDID("$FreeBSD$"); 356bc1e9cdSJohn Baldwin 366bc1e9cdSJohn Baldwin #include <sys/param.h> 376bc1e9cdSJohn Baldwin #include <sys/queue.h> 386bc1e9cdSJohn Baldwin #include <sys/_semaphore.h> 396bc1e9cdSJohn Baldwin #include <sys/sysctl.h> 406bc1e9cdSJohn Baldwin #include <sys/time.h> 416bc1e9cdSJohn Baldwin #include <sys/user.h> 426bc1e9cdSJohn Baldwin #include <sys/wait.h> 436bc1e9cdSJohn Baldwin 446bc1e9cdSJohn Baldwin #include <errno.h> 456bc1e9cdSJohn Baldwin #include <fcntl.h> 466bc1e9cdSJohn Baldwin #include <kvm.h> 476bc1e9cdSJohn Baldwin #include <limits.h> 486bc1e9cdSJohn Baldwin #include <semaphore.h> 496bc1e9cdSJohn Baldwin #include <signal.h> 506bc1e9cdSJohn Baldwin #include <stdio.h> 516bc1e9cdSJohn Baldwin #include <stdlib.h> 526bc1e9cdSJohn Baldwin #include <string.h> 536bc1e9cdSJohn Baldwin #include <time.h> 546bc1e9cdSJohn Baldwin #include <unistd.h> 556bc1e9cdSJohn Baldwin 566bc1e9cdSJohn Baldwin #include "test.h" 576bc1e9cdSJohn Baldwin 586bc1e9cdSJohn Baldwin /* Cut and pasted from kernel header, bah! */ 596bc1e9cdSJohn Baldwin 606bc1e9cdSJohn Baldwin /* Operations on timespecs */ 616bc1e9cdSJohn Baldwin #define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0) 626bc1e9cdSJohn Baldwin #define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec) 636bc1e9cdSJohn Baldwin #define timespeccmp(tvp, uvp, cmp) \ 646bc1e9cdSJohn Baldwin (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 656bc1e9cdSJohn Baldwin ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ 666bc1e9cdSJohn Baldwin ((tvp)->tv_sec cmp (uvp)->tv_sec)) 676bc1e9cdSJohn Baldwin #define timespecadd(vvp, uvp) \ 686bc1e9cdSJohn Baldwin do { \ 696bc1e9cdSJohn Baldwin (vvp)->tv_sec += (uvp)->tv_sec; \ 706bc1e9cdSJohn Baldwin (vvp)->tv_nsec += (uvp)->tv_nsec; \ 716bc1e9cdSJohn Baldwin if ((vvp)->tv_nsec >= 1000000000) { \ 726bc1e9cdSJohn Baldwin (vvp)->tv_sec++; \ 736bc1e9cdSJohn Baldwin (vvp)->tv_nsec -= 1000000000; \ 746bc1e9cdSJohn Baldwin } \ 756bc1e9cdSJohn Baldwin } while (0) 766bc1e9cdSJohn Baldwin #define timespecsub(vvp, uvp) \ 776bc1e9cdSJohn Baldwin do { \ 786bc1e9cdSJohn Baldwin (vvp)->tv_sec -= (uvp)->tv_sec; \ 796bc1e9cdSJohn Baldwin (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 806bc1e9cdSJohn Baldwin if ((vvp)->tv_nsec < 0) { \ 816bc1e9cdSJohn Baldwin (vvp)->tv_sec--; \ 826bc1e9cdSJohn Baldwin (vvp)->tv_nsec += 1000000000; \ 836bc1e9cdSJohn Baldwin } \ 846bc1e9cdSJohn Baldwin } while (0) 856bc1e9cdSJohn Baldwin 866bc1e9cdSJohn Baldwin 876bc1e9cdSJohn Baldwin #define TEST_PATH "/tmp/posixsem_regression_test" 886bc1e9cdSJohn Baldwin 896bc1e9cdSJohn Baldwin #define ELAPSED(elapsed, limit) (abs((elapsed) - (limit)) < 100) 906bc1e9cdSJohn Baldwin 916bc1e9cdSJohn Baldwin /* Macros for passing child status to parent over a pipe. */ 926bc1e9cdSJohn Baldwin #define CSTAT(class, error) ((class) << 16 | (error)) 936bc1e9cdSJohn Baldwin #define CSTAT_CLASS(stat) ((stat) >> 16) 946bc1e9cdSJohn Baldwin #define CSTAT_ERROR(stat) ((stat) & 0xffff) 956bc1e9cdSJohn Baldwin 966bc1e9cdSJohn Baldwin /* 976bc1e9cdSJohn Baldwin * Helper routine for tests that use a child process. This routine 986bc1e9cdSJohn Baldwin * creates a pipe and forks a child process. The child process runs 996bc1e9cdSJohn Baldwin * the 'func' routine which returns a status integer. The status 1006bc1e9cdSJohn Baldwin * integer gets written over the pipe to the parent and returned in 1016bc1e9cdSJohn Baldwin * '*stat'. If there is an error in pipe(), fork(), or wait() this 1026bc1e9cdSJohn Baldwin * returns -1 and fails the test. 1036bc1e9cdSJohn Baldwin */ 1046bc1e9cdSJohn Baldwin static int 1056bc1e9cdSJohn Baldwin child_worker(int (*func)(void *arg), void *arg, int *stat) 1066bc1e9cdSJohn Baldwin { 1076bc1e9cdSJohn Baldwin pid_t pid; 1086bc1e9cdSJohn Baldwin int pfd[2], cstat; 1096bc1e9cdSJohn Baldwin 1106bc1e9cdSJohn Baldwin if (pipe(pfd) < 0) { 1116bc1e9cdSJohn Baldwin fail_errno("pipe"); 1126bc1e9cdSJohn Baldwin return (-1); 1136bc1e9cdSJohn Baldwin } 1146bc1e9cdSJohn Baldwin 1156bc1e9cdSJohn Baldwin pid = fork(); 1166bc1e9cdSJohn Baldwin switch (pid) { 1176bc1e9cdSJohn Baldwin case -1: 1186bc1e9cdSJohn Baldwin /* Error. */ 1196bc1e9cdSJohn Baldwin fail_errno("fork"); 1206bc1e9cdSJohn Baldwin close(pfd[0]); 1216bc1e9cdSJohn Baldwin close(pfd[1]); 1226bc1e9cdSJohn Baldwin return (-1); 1236bc1e9cdSJohn Baldwin case 0: 1246bc1e9cdSJohn Baldwin /* Child. */ 1256bc1e9cdSJohn Baldwin cstat = func(arg); 1266bc1e9cdSJohn Baldwin write(pfd[1], &cstat, sizeof(cstat)); 1276bc1e9cdSJohn Baldwin exit(0); 1286bc1e9cdSJohn Baldwin } 1296bc1e9cdSJohn Baldwin 1306bc1e9cdSJohn Baldwin if (read(pfd[0], stat, sizeof(*stat)) < 0) { 1316bc1e9cdSJohn Baldwin fail_errno("read(pipe)"); 1326bc1e9cdSJohn Baldwin close(pfd[0]); 1336bc1e9cdSJohn Baldwin close(pfd[1]); 1346bc1e9cdSJohn Baldwin return (-1); 1356bc1e9cdSJohn Baldwin } 1366bc1e9cdSJohn Baldwin if (waitpid(pid, NULL, 0) < 0) { 1376bc1e9cdSJohn Baldwin fail_errno("wait"); 1386bc1e9cdSJohn Baldwin close(pfd[0]); 1396bc1e9cdSJohn Baldwin close(pfd[1]); 1406bc1e9cdSJohn Baldwin return (-1); 1416bc1e9cdSJohn Baldwin } 1426bc1e9cdSJohn Baldwin close(pfd[0]); 1436bc1e9cdSJohn Baldwin close(pfd[1]); 1446bc1e9cdSJohn Baldwin return (0); 1456bc1e9cdSJohn Baldwin } 1466bc1e9cdSJohn Baldwin 1476bc1e9cdSJohn Baldwin /* 1486bc1e9cdSJohn Baldwin * Attempt a ksem_open() that should fail with an expected error of 1496bc1e9cdSJohn Baldwin * 'error'. 1506bc1e9cdSJohn Baldwin */ 1516bc1e9cdSJohn Baldwin static void 1526bc1e9cdSJohn Baldwin ksem_open_should_fail(const char *path, int flags, mode_t mode, unsigned int 1536bc1e9cdSJohn Baldwin value, int error) 1546bc1e9cdSJohn Baldwin { 1556bc1e9cdSJohn Baldwin semid_t id; 1566bc1e9cdSJohn Baldwin 1576bc1e9cdSJohn Baldwin if (ksem_open(&id, path, flags, mode, value) >= 0) { 1586bc1e9cdSJohn Baldwin fail_err("ksem_open() didn't fail"); 1596bc1e9cdSJohn Baldwin ksem_close(id); 1606bc1e9cdSJohn Baldwin return; 1616bc1e9cdSJohn Baldwin } 1626bc1e9cdSJohn Baldwin if (errno != error) { 1636bc1e9cdSJohn Baldwin fail_errno("ksem_open"); 1646bc1e9cdSJohn Baldwin return; 1656bc1e9cdSJohn Baldwin } 1666bc1e9cdSJohn Baldwin pass(); 1676bc1e9cdSJohn Baldwin } 1686bc1e9cdSJohn Baldwin 1696bc1e9cdSJohn Baldwin /* 1706bc1e9cdSJohn Baldwin * Attempt a ksem_unlink() that should fail with an expected error of 1716bc1e9cdSJohn Baldwin * 'error'. 1726bc1e9cdSJohn Baldwin */ 1736bc1e9cdSJohn Baldwin static void 1746bc1e9cdSJohn Baldwin ksem_unlink_should_fail(const char *path, int error) 1756bc1e9cdSJohn Baldwin { 1766bc1e9cdSJohn Baldwin 1776bc1e9cdSJohn Baldwin if (ksem_unlink(path) >= 0) { 1786bc1e9cdSJohn Baldwin fail_err("ksem_unlink() didn't fail"); 1796bc1e9cdSJohn Baldwin return; 1806bc1e9cdSJohn Baldwin } 1816bc1e9cdSJohn Baldwin if (errno != error) { 1826bc1e9cdSJohn Baldwin fail_errno("ksem_unlink"); 1836bc1e9cdSJohn Baldwin return; 1846bc1e9cdSJohn Baldwin } 1856bc1e9cdSJohn Baldwin pass(); 1866bc1e9cdSJohn Baldwin } 1876bc1e9cdSJohn Baldwin 1886bc1e9cdSJohn Baldwin /* 1896bc1e9cdSJohn Baldwin * Attempt a ksem_close() that should fail with an expected error of 1906bc1e9cdSJohn Baldwin * 'error'. 1916bc1e9cdSJohn Baldwin */ 1926bc1e9cdSJohn Baldwin static void 1936bc1e9cdSJohn Baldwin ksem_close_should_fail(semid_t id, int error) 1946bc1e9cdSJohn Baldwin { 1956bc1e9cdSJohn Baldwin 1966bc1e9cdSJohn Baldwin if (ksem_close(id) >= 0) { 1976bc1e9cdSJohn Baldwin fail_err("ksem_close() didn't fail"); 1986bc1e9cdSJohn Baldwin return; 1996bc1e9cdSJohn Baldwin } 2006bc1e9cdSJohn Baldwin if (errno != error) { 2016bc1e9cdSJohn Baldwin fail_errno("ksem_close"); 2026bc1e9cdSJohn Baldwin return; 2036bc1e9cdSJohn Baldwin } 2046bc1e9cdSJohn Baldwin pass(); 2056bc1e9cdSJohn Baldwin } 2066bc1e9cdSJohn Baldwin 2076bc1e9cdSJohn Baldwin /* 2086bc1e9cdSJohn Baldwin * Attempt a ksem_init() that should fail with an expected error of 2096bc1e9cdSJohn Baldwin * 'error'. 2106bc1e9cdSJohn Baldwin */ 2116bc1e9cdSJohn Baldwin static void 2126bc1e9cdSJohn Baldwin ksem_init_should_fail(unsigned int value, int error) 2136bc1e9cdSJohn Baldwin { 2146bc1e9cdSJohn Baldwin semid_t id; 2156bc1e9cdSJohn Baldwin 2166bc1e9cdSJohn Baldwin if (ksem_init(&id, value) >= 0) { 2176bc1e9cdSJohn Baldwin fail_err("ksem_init() didn't fail"); 2186bc1e9cdSJohn Baldwin ksem_destroy(id); 2196bc1e9cdSJohn Baldwin return; 2206bc1e9cdSJohn Baldwin } 2216bc1e9cdSJohn Baldwin if (errno != error) { 2226bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 2236bc1e9cdSJohn Baldwin return; 2246bc1e9cdSJohn Baldwin } 2256bc1e9cdSJohn Baldwin pass(); 2266bc1e9cdSJohn Baldwin } 2276bc1e9cdSJohn Baldwin 2286bc1e9cdSJohn Baldwin /* 2296bc1e9cdSJohn Baldwin * Attempt a ksem_destroy() that should fail with an expected error of 2306bc1e9cdSJohn Baldwin * 'error'. 2316bc1e9cdSJohn Baldwin */ 2326bc1e9cdSJohn Baldwin static void 2336bc1e9cdSJohn Baldwin ksem_destroy_should_fail(semid_t id, int error) 2346bc1e9cdSJohn Baldwin { 2356bc1e9cdSJohn Baldwin 2366bc1e9cdSJohn Baldwin if (ksem_destroy(id) >= 0) { 2376bc1e9cdSJohn Baldwin fail_err("ksem_destroy() didn't fail"); 2386bc1e9cdSJohn Baldwin return; 2396bc1e9cdSJohn Baldwin } 2406bc1e9cdSJohn Baldwin if (errno != error) { 2416bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 2426bc1e9cdSJohn Baldwin return; 2436bc1e9cdSJohn Baldwin } 2446bc1e9cdSJohn Baldwin pass(); 2456bc1e9cdSJohn Baldwin } 2466bc1e9cdSJohn Baldwin 2476bc1e9cdSJohn Baldwin /* 2486bc1e9cdSJohn Baldwin * Attempt a ksem_post() that should fail with an expected error of 2496bc1e9cdSJohn Baldwin * 'error'. 2506bc1e9cdSJohn Baldwin */ 2516bc1e9cdSJohn Baldwin static void 2526bc1e9cdSJohn Baldwin ksem_post_should_fail(semid_t id, int error) 2536bc1e9cdSJohn Baldwin { 2546bc1e9cdSJohn Baldwin 2556bc1e9cdSJohn Baldwin if (ksem_post(id) >= 0) { 2566bc1e9cdSJohn Baldwin fail_err("ksem_post() didn't fail"); 2576bc1e9cdSJohn Baldwin return; 2586bc1e9cdSJohn Baldwin } 2596bc1e9cdSJohn Baldwin if (errno != error) { 2606bc1e9cdSJohn Baldwin fail_errno("ksem_post"); 2616bc1e9cdSJohn Baldwin return; 2626bc1e9cdSJohn Baldwin } 2636bc1e9cdSJohn Baldwin pass(); 2646bc1e9cdSJohn Baldwin } 2656bc1e9cdSJohn Baldwin 2666bc1e9cdSJohn Baldwin static void 2676bc1e9cdSJohn Baldwin open_after_unlink(void) 2686bc1e9cdSJohn Baldwin { 2696bc1e9cdSJohn Baldwin semid_t id; 2706bc1e9cdSJohn Baldwin 2716bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) { 2726bc1e9cdSJohn Baldwin fail_errno("ksem_open(1)"); 2736bc1e9cdSJohn Baldwin return; 2746bc1e9cdSJohn Baldwin } 2756bc1e9cdSJohn Baldwin ksem_close(id); 2766bc1e9cdSJohn Baldwin 2776bc1e9cdSJohn Baldwin if (ksem_unlink(TEST_PATH) < 0) { 2786bc1e9cdSJohn Baldwin fail_errno("ksem_unlink"); 2796bc1e9cdSJohn Baldwin return; 2806bc1e9cdSJohn Baldwin } 2816bc1e9cdSJohn Baldwin 2826bc1e9cdSJohn Baldwin ksem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT); 2836bc1e9cdSJohn Baldwin } 2846bc1e9cdSJohn Baldwin TEST(open_after_unlink, "open after unlink"); 2856bc1e9cdSJohn Baldwin 2866bc1e9cdSJohn Baldwin static void 2876bc1e9cdSJohn Baldwin open_invalid_path(void) 2886bc1e9cdSJohn Baldwin { 2896bc1e9cdSJohn Baldwin 2906bc1e9cdSJohn Baldwin ksem_open_should_fail("blah", 0, 0777, 1, EINVAL); 2916bc1e9cdSJohn Baldwin } 2926bc1e9cdSJohn Baldwin TEST(open_invalid_path, "open invalid path"); 2936bc1e9cdSJohn Baldwin 2946bc1e9cdSJohn Baldwin static void 2956bc1e9cdSJohn Baldwin open_extra_flags(void) 2966bc1e9cdSJohn Baldwin { 2976bc1e9cdSJohn Baldwin 2986bc1e9cdSJohn Baldwin ksem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL); 2996bc1e9cdSJohn Baldwin } 3006bc1e9cdSJohn Baldwin TEST(open_extra_flags, "open with extra flags"); 3016bc1e9cdSJohn Baldwin 3026bc1e9cdSJohn Baldwin static void 3036bc1e9cdSJohn Baldwin open_bad_value(void) 3046bc1e9cdSJohn Baldwin { 3056bc1e9cdSJohn Baldwin 3066bc1e9cdSJohn Baldwin (void)ksem_unlink(TEST_PATH); 3076bc1e9cdSJohn Baldwin 3086bc1e9cdSJohn Baldwin ksem_open_should_fail(TEST_PATH, O_CREAT, 0777, UINT_MAX, EINVAL); 3096bc1e9cdSJohn Baldwin } 3106bc1e9cdSJohn Baldwin TEST(open_bad_value, "open with invalid initial value"); 3116bc1e9cdSJohn Baldwin 3126bc1e9cdSJohn Baldwin static void 3136bc1e9cdSJohn Baldwin open_bad_path_pointer(void) 3146bc1e9cdSJohn Baldwin { 3156bc1e9cdSJohn Baldwin 3166bc1e9cdSJohn Baldwin ksem_open_should_fail((char *)1024, O_RDONLY, 0777, 1, EFAULT); 3176bc1e9cdSJohn Baldwin } 3186bc1e9cdSJohn Baldwin TEST(open_bad_path_pointer, "open bad path pointer"); 3196bc1e9cdSJohn Baldwin 3206bc1e9cdSJohn Baldwin static void 3216bc1e9cdSJohn Baldwin open_path_too_long(void) 3226bc1e9cdSJohn Baldwin { 3236bc1e9cdSJohn Baldwin char *page; 3246bc1e9cdSJohn Baldwin 3256bc1e9cdSJohn Baldwin page = malloc(MAXPATHLEN + 1); 3266bc1e9cdSJohn Baldwin memset(page, 'a', MAXPATHLEN); 3276bc1e9cdSJohn Baldwin page[MAXPATHLEN] = '\0'; 3286bc1e9cdSJohn Baldwin ksem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG); 3296bc1e9cdSJohn Baldwin free(page); 3306bc1e9cdSJohn Baldwin } 3316bc1e9cdSJohn Baldwin TEST(open_path_too_long, "open pathname too long"); 3326bc1e9cdSJohn Baldwin 3336bc1e9cdSJohn Baldwin static void 3346bc1e9cdSJohn Baldwin open_nonexisting_semaphore(void) 3356bc1e9cdSJohn Baldwin { 3366bc1e9cdSJohn Baldwin 3376bc1e9cdSJohn Baldwin ksem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT); 3386bc1e9cdSJohn Baldwin } 3396bc1e9cdSJohn Baldwin TEST(open_nonexisting_semaphore, "open nonexistent semaphore"); 3406bc1e9cdSJohn Baldwin 3416bc1e9cdSJohn Baldwin static void 3426bc1e9cdSJohn Baldwin exclusive_create_existing_semaphore(void) 3436bc1e9cdSJohn Baldwin { 3446bc1e9cdSJohn Baldwin semid_t id; 3456bc1e9cdSJohn Baldwin 3466bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) { 3476bc1e9cdSJohn Baldwin fail_errno("ksem_open(O_CREAT)"); 3486bc1e9cdSJohn Baldwin return; 3496bc1e9cdSJohn Baldwin } 3506bc1e9cdSJohn Baldwin ksem_close(id); 3516bc1e9cdSJohn Baldwin 3526bc1e9cdSJohn Baldwin ksem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST); 3536bc1e9cdSJohn Baldwin 3546bc1e9cdSJohn Baldwin ksem_unlink(TEST_PATH); 3556bc1e9cdSJohn Baldwin } 3566bc1e9cdSJohn Baldwin TEST(exclusive_create_existing_semaphore, "O_EXCL of existing semaphore"); 3576bc1e9cdSJohn Baldwin 3586bc1e9cdSJohn Baldwin static void 3596bc1e9cdSJohn Baldwin init_bad_value(void) 3606bc1e9cdSJohn Baldwin { 3616bc1e9cdSJohn Baldwin 3626bc1e9cdSJohn Baldwin ksem_init_should_fail(UINT_MAX, EINVAL); 3636bc1e9cdSJohn Baldwin } 3646bc1e9cdSJohn Baldwin TEST(init_bad_value, "init with invalid initial value"); 3656bc1e9cdSJohn Baldwin 3666bc1e9cdSJohn Baldwin static void 3676bc1e9cdSJohn Baldwin unlink_bad_path_pointer(void) 3686bc1e9cdSJohn Baldwin { 3696bc1e9cdSJohn Baldwin 3706bc1e9cdSJohn Baldwin ksem_unlink_should_fail((char *)1024, EFAULT); 3716bc1e9cdSJohn Baldwin } 3726bc1e9cdSJohn Baldwin TEST(unlink_bad_path_pointer, "unlink bad path pointer"); 3736bc1e9cdSJohn Baldwin 3746bc1e9cdSJohn Baldwin static void 3756bc1e9cdSJohn Baldwin unlink_path_too_long(void) 3766bc1e9cdSJohn Baldwin { 3776bc1e9cdSJohn Baldwin char *page; 3786bc1e9cdSJohn Baldwin 3796bc1e9cdSJohn Baldwin page = malloc(MAXPATHLEN + 1); 3806bc1e9cdSJohn Baldwin memset(page, 'a', MAXPATHLEN); 3816bc1e9cdSJohn Baldwin page[MAXPATHLEN] = '\0'; 3826bc1e9cdSJohn Baldwin ksem_unlink_should_fail(page, ENAMETOOLONG); 3836bc1e9cdSJohn Baldwin free(page); 3846bc1e9cdSJohn Baldwin } 3856bc1e9cdSJohn Baldwin TEST(unlink_path_too_long, "unlink pathname too long"); 3866bc1e9cdSJohn Baldwin 3876bc1e9cdSJohn Baldwin static void 3886bc1e9cdSJohn Baldwin destroy_named_semaphore(void) 3896bc1e9cdSJohn Baldwin { 3906bc1e9cdSJohn Baldwin semid_t id; 3916bc1e9cdSJohn Baldwin 3926bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) { 3936bc1e9cdSJohn Baldwin fail_errno("ksem_open(O_CREAT)"); 3946bc1e9cdSJohn Baldwin return; 3956bc1e9cdSJohn Baldwin } 3966bc1e9cdSJohn Baldwin 3976bc1e9cdSJohn Baldwin ksem_destroy_should_fail(id, EINVAL); 3986bc1e9cdSJohn Baldwin 3996bc1e9cdSJohn Baldwin ksem_close(id); 4006bc1e9cdSJohn Baldwin ksem_unlink(TEST_PATH); 4016bc1e9cdSJohn Baldwin } 4026bc1e9cdSJohn Baldwin TEST(destroy_named_semaphore, "destroy named semaphore"); 4036bc1e9cdSJohn Baldwin 4046bc1e9cdSJohn Baldwin static void 4056bc1e9cdSJohn Baldwin close_unnamed_semaphore(void) 4066bc1e9cdSJohn Baldwin { 4076bc1e9cdSJohn Baldwin semid_t id; 4086bc1e9cdSJohn Baldwin 4096bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 4106bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 4116bc1e9cdSJohn Baldwin return; 4126bc1e9cdSJohn Baldwin } 4136bc1e9cdSJohn Baldwin 4146bc1e9cdSJohn Baldwin ksem_close_should_fail(id, EINVAL); 4156bc1e9cdSJohn Baldwin 4166bc1e9cdSJohn Baldwin ksem_destroy(id); 4176bc1e9cdSJohn Baldwin } 4186bc1e9cdSJohn Baldwin TEST(close_unnamed_semaphore, "close unnamed semaphore"); 4196bc1e9cdSJohn Baldwin 4206bc1e9cdSJohn Baldwin static void 4216bc1e9cdSJohn Baldwin destroy_invalid_fd(void) 4226bc1e9cdSJohn Baldwin { 4236bc1e9cdSJohn Baldwin 4246bc1e9cdSJohn Baldwin ksem_destroy_should_fail(STDERR_FILENO, EINVAL); 4256bc1e9cdSJohn Baldwin } 4266bc1e9cdSJohn Baldwin TEST(destroy_invalid_fd, "destroy non-semaphore file descriptor"); 4276bc1e9cdSJohn Baldwin 4286bc1e9cdSJohn Baldwin static void 4296bc1e9cdSJohn Baldwin close_invalid_fd(void) 4306bc1e9cdSJohn Baldwin { 4316bc1e9cdSJohn Baldwin 4326bc1e9cdSJohn Baldwin ksem_close_should_fail(STDERR_FILENO, EINVAL); 4336bc1e9cdSJohn Baldwin } 4346bc1e9cdSJohn Baldwin TEST(close_invalid_fd, "close non-semaphore file descriptor"); 4356bc1e9cdSJohn Baldwin 4366bc1e9cdSJohn Baldwin static void 4376bc1e9cdSJohn Baldwin create_unnamed_semaphore(void) 4386bc1e9cdSJohn Baldwin { 4396bc1e9cdSJohn Baldwin semid_t id; 4406bc1e9cdSJohn Baldwin 4416bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 4426bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 4436bc1e9cdSJohn Baldwin return; 4446bc1e9cdSJohn Baldwin } 4456bc1e9cdSJohn Baldwin 4466bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 4476bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 4486bc1e9cdSJohn Baldwin return; 4496bc1e9cdSJohn Baldwin } 4506bc1e9cdSJohn Baldwin pass(); 4516bc1e9cdSJohn Baldwin } 4526bc1e9cdSJohn Baldwin TEST(create_unnamed_semaphore, "create unnamed semaphore"); 4536bc1e9cdSJohn Baldwin 4546bc1e9cdSJohn Baldwin static void 4556bc1e9cdSJohn Baldwin open_named_semaphore(void) 4566bc1e9cdSJohn Baldwin { 4576bc1e9cdSJohn Baldwin semid_t id; 4586bc1e9cdSJohn Baldwin 4596bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) { 4606bc1e9cdSJohn Baldwin fail_errno("ksem_open(O_CREAT)"); 4616bc1e9cdSJohn Baldwin return; 4626bc1e9cdSJohn Baldwin } 4636bc1e9cdSJohn Baldwin 4646bc1e9cdSJohn Baldwin if (ksem_close(id) < 0) { 4656bc1e9cdSJohn Baldwin fail_errno("ksem_close"); 4666bc1e9cdSJohn Baldwin return; 4676bc1e9cdSJohn Baldwin } 4686bc1e9cdSJohn Baldwin 4696bc1e9cdSJohn Baldwin if (ksem_unlink(TEST_PATH) < 0) { 4706bc1e9cdSJohn Baldwin fail_errno("ksem_unlink"); 4716bc1e9cdSJohn Baldwin return; 4726bc1e9cdSJohn Baldwin } 4736bc1e9cdSJohn Baldwin pass(); 4746bc1e9cdSJohn Baldwin } 4756bc1e9cdSJohn Baldwin TEST(open_named_semaphore, "create named semaphore"); 4766bc1e9cdSJohn Baldwin 4776bc1e9cdSJohn Baldwin static void 4786bc1e9cdSJohn Baldwin getvalue_invalid_semaphore(void) 4796bc1e9cdSJohn Baldwin { 4806bc1e9cdSJohn Baldwin int val; 4816bc1e9cdSJohn Baldwin 4826bc1e9cdSJohn Baldwin if (ksem_getvalue(STDERR_FILENO, &val) >= 0) { 4836bc1e9cdSJohn Baldwin fail_err("ksem_getvalue() didn't fail"); 4846bc1e9cdSJohn Baldwin return; 4856bc1e9cdSJohn Baldwin } 4866bc1e9cdSJohn Baldwin if (errno != EINVAL) { 4876bc1e9cdSJohn Baldwin fail_errno("ksem_getvalue"); 4886bc1e9cdSJohn Baldwin return; 4896bc1e9cdSJohn Baldwin } 4906bc1e9cdSJohn Baldwin pass(); 4916bc1e9cdSJohn Baldwin } 4926bc1e9cdSJohn Baldwin TEST(getvalue_invalid_semaphore, "get value of invalid semaphore"); 4936bc1e9cdSJohn Baldwin 4946bc1e9cdSJohn Baldwin static void 4956bc1e9cdSJohn Baldwin post_invalid_semaphore(void) 4966bc1e9cdSJohn Baldwin { 4976bc1e9cdSJohn Baldwin 4986bc1e9cdSJohn Baldwin ksem_post_should_fail(STDERR_FILENO, EINVAL); 4996bc1e9cdSJohn Baldwin } 5006bc1e9cdSJohn Baldwin TEST(post_invalid_semaphore, "post of invalid semaphore"); 5016bc1e9cdSJohn Baldwin 5026bc1e9cdSJohn Baldwin static void 5036bc1e9cdSJohn Baldwin wait_invalid_semaphore(void) 5046bc1e9cdSJohn Baldwin { 5056bc1e9cdSJohn Baldwin 5066bc1e9cdSJohn Baldwin if (ksem_wait(STDERR_FILENO) >= 0) { 5076bc1e9cdSJohn Baldwin fail_err("ksem_wait() didn't fail"); 5086bc1e9cdSJohn Baldwin return; 5096bc1e9cdSJohn Baldwin } 5106bc1e9cdSJohn Baldwin if (errno != EINVAL) { 5116bc1e9cdSJohn Baldwin fail_errno("ksem_wait"); 5126bc1e9cdSJohn Baldwin return; 5136bc1e9cdSJohn Baldwin } 5146bc1e9cdSJohn Baldwin pass(); 5156bc1e9cdSJohn Baldwin } 5166bc1e9cdSJohn Baldwin TEST(wait_invalid_semaphore, "wait for invalid semaphore"); 5176bc1e9cdSJohn Baldwin 5186bc1e9cdSJohn Baldwin static void 5196bc1e9cdSJohn Baldwin trywait_invalid_semaphore(void) 5206bc1e9cdSJohn Baldwin { 5216bc1e9cdSJohn Baldwin 5226bc1e9cdSJohn Baldwin if (ksem_trywait(STDERR_FILENO) >= 0) { 5236bc1e9cdSJohn Baldwin fail_err("ksem_trywait() didn't fail"); 5246bc1e9cdSJohn Baldwin return; 5256bc1e9cdSJohn Baldwin } 5266bc1e9cdSJohn Baldwin if (errno != EINVAL) { 5276bc1e9cdSJohn Baldwin fail_errno("ksem_trywait"); 5286bc1e9cdSJohn Baldwin return; 5296bc1e9cdSJohn Baldwin } 5306bc1e9cdSJohn Baldwin pass(); 5316bc1e9cdSJohn Baldwin } 5326bc1e9cdSJohn Baldwin TEST(trywait_invalid_semaphore, "try wait for invalid semaphore"); 5336bc1e9cdSJohn Baldwin 5346bc1e9cdSJohn Baldwin static void 5356bc1e9cdSJohn Baldwin timedwait_invalid_semaphore(void) 5366bc1e9cdSJohn Baldwin { 5376bc1e9cdSJohn Baldwin 5386bc1e9cdSJohn Baldwin if (ksem_timedwait(STDERR_FILENO, NULL) >= 0) { 5396bc1e9cdSJohn Baldwin fail_err("ksem_timedwait() didn't fail"); 5406bc1e9cdSJohn Baldwin return; 5416bc1e9cdSJohn Baldwin } 5426bc1e9cdSJohn Baldwin if (errno != EINVAL) { 5436bc1e9cdSJohn Baldwin fail_errno("ksem_timedwait"); 5446bc1e9cdSJohn Baldwin return; 5456bc1e9cdSJohn Baldwin } 5466bc1e9cdSJohn Baldwin pass(); 5476bc1e9cdSJohn Baldwin } 5486bc1e9cdSJohn Baldwin TEST(timedwait_invalid_semaphore, "timed wait for invalid semaphore"); 5496bc1e9cdSJohn Baldwin 5506bc1e9cdSJohn Baldwin static int 5516bc1e9cdSJohn Baldwin checkvalue(semid_t id, int expected) 5526bc1e9cdSJohn Baldwin { 5536bc1e9cdSJohn Baldwin int val; 5546bc1e9cdSJohn Baldwin 5556bc1e9cdSJohn Baldwin if (ksem_getvalue(id, &val) < 0) { 5566bc1e9cdSJohn Baldwin fail_errno("ksem_getvalue"); 5576bc1e9cdSJohn Baldwin return (-1); 5586bc1e9cdSJohn Baldwin } 5596bc1e9cdSJohn Baldwin if (val != expected) { 5606bc1e9cdSJohn Baldwin fail_err("sem value should be %d instead of %d", expected, val); 5616bc1e9cdSJohn Baldwin return (-1); 5626bc1e9cdSJohn Baldwin } 5636bc1e9cdSJohn Baldwin return (0); 5646bc1e9cdSJohn Baldwin } 5656bc1e9cdSJohn Baldwin 5666bc1e9cdSJohn Baldwin static void 5676bc1e9cdSJohn Baldwin post_test(void) 5686bc1e9cdSJohn Baldwin { 5696bc1e9cdSJohn Baldwin semid_t id; 5706bc1e9cdSJohn Baldwin 5716bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 5726bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 5736bc1e9cdSJohn Baldwin return; 5746bc1e9cdSJohn Baldwin } 5756bc1e9cdSJohn Baldwin if (checkvalue(id, 1) < 0) { 5766bc1e9cdSJohn Baldwin ksem_destroy(id); 5776bc1e9cdSJohn Baldwin return; 5786bc1e9cdSJohn Baldwin } 5796bc1e9cdSJohn Baldwin if (ksem_post(id) < 0) { 5806bc1e9cdSJohn Baldwin fail_errno("ksem_post"); 5816bc1e9cdSJohn Baldwin ksem_destroy(id); 5826bc1e9cdSJohn Baldwin return; 5836bc1e9cdSJohn Baldwin } 5846bc1e9cdSJohn Baldwin if (checkvalue(id, 2) < 0) { 5856bc1e9cdSJohn Baldwin ksem_destroy(id); 5866bc1e9cdSJohn Baldwin return; 5876bc1e9cdSJohn Baldwin } 5886bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 5896bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 5906bc1e9cdSJohn Baldwin return; 5916bc1e9cdSJohn Baldwin } 5926bc1e9cdSJohn Baldwin pass(); 5936bc1e9cdSJohn Baldwin } 5946bc1e9cdSJohn Baldwin TEST(post_test, "simple post"); 5956bc1e9cdSJohn Baldwin 5966bc1e9cdSJohn Baldwin static void 5976bc1e9cdSJohn Baldwin use_after_unlink_test(void) 5986bc1e9cdSJohn Baldwin { 5996bc1e9cdSJohn Baldwin semid_t id; 6006bc1e9cdSJohn Baldwin 6016bc1e9cdSJohn Baldwin /* 6026bc1e9cdSJohn Baldwin * Create named semaphore with value of 1 and then unlink it 6036bc1e9cdSJohn Baldwin * while still retaining the initial reference. 6046bc1e9cdSJohn Baldwin */ 6056bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) { 6066bc1e9cdSJohn Baldwin fail_errno("ksem_open(O_CREAT | O_EXCL)"); 6076bc1e9cdSJohn Baldwin return; 6086bc1e9cdSJohn Baldwin } 6096bc1e9cdSJohn Baldwin if (ksem_unlink(TEST_PATH) < 0) { 6106bc1e9cdSJohn Baldwin fail_errno("ksem_unlink"); 6116bc1e9cdSJohn Baldwin ksem_close(id); 6126bc1e9cdSJohn Baldwin return; 6136bc1e9cdSJohn Baldwin } 6146bc1e9cdSJohn Baldwin if (checkvalue(id, 1) < 0) { 6156bc1e9cdSJohn Baldwin ksem_close(id); 6166bc1e9cdSJohn Baldwin return; 6176bc1e9cdSJohn Baldwin } 6186bc1e9cdSJohn Baldwin 6196bc1e9cdSJohn Baldwin /* Post the semaphore to set its value to 2. */ 6206bc1e9cdSJohn Baldwin if (ksem_post(id) < 0) { 6216bc1e9cdSJohn Baldwin fail_errno("ksem_post"); 6226bc1e9cdSJohn Baldwin ksem_close(id); 6236bc1e9cdSJohn Baldwin return; 6246bc1e9cdSJohn Baldwin } 6256bc1e9cdSJohn Baldwin if (checkvalue(id, 2) < 0) { 6266bc1e9cdSJohn Baldwin ksem_close(id); 6276bc1e9cdSJohn Baldwin return; 6286bc1e9cdSJohn Baldwin } 6296bc1e9cdSJohn Baldwin 6306bc1e9cdSJohn Baldwin /* Wait on the semaphore which should set its value to 1. */ 6316bc1e9cdSJohn Baldwin if (ksem_wait(id) < 0) { 6326bc1e9cdSJohn Baldwin fail_errno("ksem_wait"); 6336bc1e9cdSJohn Baldwin ksem_close(id); 6346bc1e9cdSJohn Baldwin return; 6356bc1e9cdSJohn Baldwin } 6366bc1e9cdSJohn Baldwin if (checkvalue(id, 1) < 0) { 6376bc1e9cdSJohn Baldwin ksem_close(id); 6386bc1e9cdSJohn Baldwin return; 6396bc1e9cdSJohn Baldwin } 6406bc1e9cdSJohn Baldwin 6416bc1e9cdSJohn Baldwin if (ksem_close(id) < 0) { 6426bc1e9cdSJohn Baldwin fail_errno("ksem_close"); 6436bc1e9cdSJohn Baldwin return; 6446bc1e9cdSJohn Baldwin } 6456bc1e9cdSJohn Baldwin pass(); 6466bc1e9cdSJohn Baldwin } 6476bc1e9cdSJohn Baldwin TEST(use_after_unlink_test, "use named semaphore after unlink"); 6486bc1e9cdSJohn Baldwin 6496bc1e9cdSJohn Baldwin static void 6506bc1e9cdSJohn Baldwin unlocked_trywait(void) 6516bc1e9cdSJohn Baldwin { 6526bc1e9cdSJohn Baldwin semid_t id; 6536bc1e9cdSJohn Baldwin 6546bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 6556bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 6566bc1e9cdSJohn Baldwin return; 6576bc1e9cdSJohn Baldwin } 6586bc1e9cdSJohn Baldwin 6596bc1e9cdSJohn Baldwin /* This should succeed and decrement the value to 0. */ 6606bc1e9cdSJohn Baldwin if (ksem_trywait(id) < 0) { 6616bc1e9cdSJohn Baldwin fail_errno("ksem_trywait()"); 6626bc1e9cdSJohn Baldwin ksem_destroy(id); 6636bc1e9cdSJohn Baldwin return; 6646bc1e9cdSJohn Baldwin } 6656bc1e9cdSJohn Baldwin if (checkvalue(id, 0) < 0) { 6666bc1e9cdSJohn Baldwin ksem_destroy(id); 6676bc1e9cdSJohn Baldwin return; 6686bc1e9cdSJohn Baldwin } 6696bc1e9cdSJohn Baldwin 6706bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 6716bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 6726bc1e9cdSJohn Baldwin return; 6736bc1e9cdSJohn Baldwin } 6746bc1e9cdSJohn Baldwin pass(); 6756bc1e9cdSJohn Baldwin } 6766bc1e9cdSJohn Baldwin TEST(unlocked_trywait, "unlocked trywait"); 6776bc1e9cdSJohn Baldwin 6786bc1e9cdSJohn Baldwin static void 6796bc1e9cdSJohn Baldwin locked_trywait(void) 6806bc1e9cdSJohn Baldwin { 6816bc1e9cdSJohn Baldwin semid_t id; 6826bc1e9cdSJohn Baldwin 6836bc1e9cdSJohn Baldwin if (ksem_init(&id, 0) < 0) { 6846bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 6856bc1e9cdSJohn Baldwin return; 6866bc1e9cdSJohn Baldwin } 6876bc1e9cdSJohn Baldwin 6886bc1e9cdSJohn Baldwin /* This should fail with EAGAIN and leave the value at 0. */ 6896bc1e9cdSJohn Baldwin if (ksem_trywait(id) >= 0) { 6906bc1e9cdSJohn Baldwin fail_err("ksem_trywait() didn't fail"); 6916bc1e9cdSJohn Baldwin ksem_destroy(id); 6926bc1e9cdSJohn Baldwin return; 6936bc1e9cdSJohn Baldwin } 6946bc1e9cdSJohn Baldwin if (errno != EAGAIN) { 6956bc1e9cdSJohn Baldwin fail_errno("wrong error from ksem_trywait()"); 6966bc1e9cdSJohn Baldwin ksem_destroy(id); 6976bc1e9cdSJohn Baldwin return; 6986bc1e9cdSJohn Baldwin } 6996bc1e9cdSJohn Baldwin if (checkvalue(id, 0) < 0) { 7006bc1e9cdSJohn Baldwin ksem_destroy(id); 7016bc1e9cdSJohn Baldwin return; 7026bc1e9cdSJohn Baldwin } 7036bc1e9cdSJohn Baldwin 7046bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 7056bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 7066bc1e9cdSJohn Baldwin return; 7076bc1e9cdSJohn Baldwin } 7086bc1e9cdSJohn Baldwin pass(); 7096bc1e9cdSJohn Baldwin } 7106bc1e9cdSJohn Baldwin TEST(locked_trywait, "locked trywait"); 7116bc1e9cdSJohn Baldwin 7126bc1e9cdSJohn Baldwin /* 7136bc1e9cdSJohn Baldwin * Use a timer to post a specific semaphore after a timeout. A timer 7146bc1e9cdSJohn Baldwin * is scheduled via schedule_post(). check_alarm() must be called 7156bc1e9cdSJohn Baldwin * afterwards to clean up and check for errors. 7166bc1e9cdSJohn Baldwin */ 7176bc1e9cdSJohn Baldwin static semid_t alarm_id = -1; 7186bc1e9cdSJohn Baldwin static int alarm_errno; 7196bc1e9cdSJohn Baldwin static int alarm_handler_installed; 7206bc1e9cdSJohn Baldwin 7216bc1e9cdSJohn Baldwin static void 7226bc1e9cdSJohn Baldwin alarm_handler(int signo) 7236bc1e9cdSJohn Baldwin { 7246bc1e9cdSJohn Baldwin 7256bc1e9cdSJohn Baldwin if (ksem_post(alarm_id) < 0) 7266bc1e9cdSJohn Baldwin alarm_errno = errno; 7276bc1e9cdSJohn Baldwin } 7286bc1e9cdSJohn Baldwin 7296bc1e9cdSJohn Baldwin static int 7306bc1e9cdSJohn Baldwin check_alarm(int just_clear) 7316bc1e9cdSJohn Baldwin { 7326bc1e9cdSJohn Baldwin struct itimerval it; 7336bc1e9cdSJohn Baldwin 7346bc1e9cdSJohn Baldwin bzero(&it, sizeof(it)); 7356bc1e9cdSJohn Baldwin if (just_clear) { 7366bc1e9cdSJohn Baldwin setitimer(ITIMER_REAL, &it, NULL); 7376bc1e9cdSJohn Baldwin alarm_errno = 0; 7386bc1e9cdSJohn Baldwin alarm_id = -1; 7396bc1e9cdSJohn Baldwin return (0); 7406bc1e9cdSJohn Baldwin } 7416bc1e9cdSJohn Baldwin if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 7426bc1e9cdSJohn Baldwin fail_errno("setitimer"); 7436bc1e9cdSJohn Baldwin return (-1); 7446bc1e9cdSJohn Baldwin } 7456bc1e9cdSJohn Baldwin if (alarm_errno != 0 && !just_clear) { 7466bc1e9cdSJohn Baldwin errno = alarm_errno; 7476bc1e9cdSJohn Baldwin fail_errno("ksem_post() (via timeout)"); 7486bc1e9cdSJohn Baldwin alarm_errno = 0; 7496bc1e9cdSJohn Baldwin return (-1); 7506bc1e9cdSJohn Baldwin } 7516bc1e9cdSJohn Baldwin alarm_id = -1; 7526bc1e9cdSJohn Baldwin 7536bc1e9cdSJohn Baldwin return (0); 7546bc1e9cdSJohn Baldwin } 7556bc1e9cdSJohn Baldwin 7566bc1e9cdSJohn Baldwin static int 7576bc1e9cdSJohn Baldwin schedule_post(semid_t id, u_int msec) 7586bc1e9cdSJohn Baldwin { 7596bc1e9cdSJohn Baldwin struct itimerval it; 7606bc1e9cdSJohn Baldwin 7616bc1e9cdSJohn Baldwin if (!alarm_handler_installed) { 7626bc1e9cdSJohn Baldwin if (signal(SIGALRM, alarm_handler) == SIG_ERR) { 7636bc1e9cdSJohn Baldwin fail_errno("signal(SIGALRM)"); 7646bc1e9cdSJohn Baldwin return (-1); 7656bc1e9cdSJohn Baldwin } 7666bc1e9cdSJohn Baldwin alarm_handler_installed = 1; 7676bc1e9cdSJohn Baldwin } 7686bc1e9cdSJohn Baldwin if (alarm_id != -1) { 7696bc1e9cdSJohn Baldwin fail_err("ksem_post() already scheduled"); 7706bc1e9cdSJohn Baldwin return (-1); 7716bc1e9cdSJohn Baldwin } 7726bc1e9cdSJohn Baldwin alarm_id = id; 7736bc1e9cdSJohn Baldwin bzero(&it, sizeof(it)); 7746bc1e9cdSJohn Baldwin it.it_value.tv_sec = msec / 1000; 7756bc1e9cdSJohn Baldwin it.it_value.tv_usec = (msec % 1000) * 1000; 7766bc1e9cdSJohn Baldwin if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 7776bc1e9cdSJohn Baldwin fail_errno("setitimer"); 7786bc1e9cdSJohn Baldwin return (-1); 7796bc1e9cdSJohn Baldwin } 7806bc1e9cdSJohn Baldwin return (0); 7816bc1e9cdSJohn Baldwin } 7826bc1e9cdSJohn Baldwin 7836bc1e9cdSJohn Baldwin static int 7846bc1e9cdSJohn Baldwin timedwait(semid_t id, u_int msec, u_int *delta, int error) 7856bc1e9cdSJohn Baldwin { 7866bc1e9cdSJohn Baldwin struct timespec start, end; 7876bc1e9cdSJohn Baldwin 7886bc1e9cdSJohn Baldwin if (clock_gettime(CLOCK_REALTIME, &start) < 0) { 7896bc1e9cdSJohn Baldwin fail_errno("clock_gettime(CLOCK_REALTIME)"); 7906bc1e9cdSJohn Baldwin return (-1); 7916bc1e9cdSJohn Baldwin } 7926bc1e9cdSJohn Baldwin end.tv_sec = msec / 1000; 7936bc1e9cdSJohn Baldwin end.tv_nsec = msec % 1000 * 1000000; 7946bc1e9cdSJohn Baldwin timespecadd(&end, &start); 7956bc1e9cdSJohn Baldwin if (ksem_timedwait(id, &end) < 0) { 7966bc1e9cdSJohn Baldwin if (errno != error) { 7976bc1e9cdSJohn Baldwin fail_errno("ksem_timedwait"); 7986bc1e9cdSJohn Baldwin return (-1); 7996bc1e9cdSJohn Baldwin } 8006bc1e9cdSJohn Baldwin } else if (error != 0) { 8016bc1e9cdSJohn Baldwin fail_err("ksem_timedwait() didn't fail"); 8026bc1e9cdSJohn Baldwin return (-1); 8036bc1e9cdSJohn Baldwin } 8046bc1e9cdSJohn Baldwin if (clock_gettime(CLOCK_REALTIME, &end) < 0) { 8056bc1e9cdSJohn Baldwin fail_errno("clock_gettime(CLOCK_REALTIME)"); 8066bc1e9cdSJohn Baldwin return (-1); 8076bc1e9cdSJohn Baldwin } 8086bc1e9cdSJohn Baldwin timespecsub(&end, &start); 8096bc1e9cdSJohn Baldwin *delta = end.tv_nsec / 1000000; 8106bc1e9cdSJohn Baldwin *delta += end.tv_sec * 1000; 8116bc1e9cdSJohn Baldwin return (0); 8126bc1e9cdSJohn Baldwin } 8136bc1e9cdSJohn Baldwin 8146bc1e9cdSJohn Baldwin static void 8156bc1e9cdSJohn Baldwin unlocked_timedwait(void) 8166bc1e9cdSJohn Baldwin { 8176bc1e9cdSJohn Baldwin semid_t id; 8186bc1e9cdSJohn Baldwin u_int elapsed; 8196bc1e9cdSJohn Baldwin 8206bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 8216bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 8226bc1e9cdSJohn Baldwin return; 8236bc1e9cdSJohn Baldwin } 8246bc1e9cdSJohn Baldwin 8256bc1e9cdSJohn Baldwin /* This should succeed right away and set the value to 0. */ 8266bc1e9cdSJohn Baldwin if (timedwait(id, 5000, &elapsed, 0) < 0) { 8276bc1e9cdSJohn Baldwin ksem_destroy(id); 8286bc1e9cdSJohn Baldwin return; 8296bc1e9cdSJohn Baldwin } 8306bc1e9cdSJohn Baldwin if (!ELAPSED(elapsed, 0)) { 8316bc1e9cdSJohn Baldwin fail_err("ksem_timedwait() of unlocked sem took %ums", elapsed); 8326bc1e9cdSJohn Baldwin ksem_destroy(id); 8336bc1e9cdSJohn Baldwin return; 8346bc1e9cdSJohn Baldwin } 8356bc1e9cdSJohn Baldwin if (checkvalue(id, 0) < 0) { 8366bc1e9cdSJohn Baldwin ksem_destroy(id); 8376bc1e9cdSJohn Baldwin return; 8386bc1e9cdSJohn Baldwin } 8396bc1e9cdSJohn Baldwin 8406bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 8416bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 8426bc1e9cdSJohn Baldwin return; 8436bc1e9cdSJohn Baldwin } 8446bc1e9cdSJohn Baldwin pass(); 8456bc1e9cdSJohn Baldwin } 8466bc1e9cdSJohn Baldwin TEST(unlocked_timedwait, "unlocked timedwait"); 8476bc1e9cdSJohn Baldwin 8486bc1e9cdSJohn Baldwin static void 8496bc1e9cdSJohn Baldwin expired_timedwait(void) 8506bc1e9cdSJohn Baldwin { 8516bc1e9cdSJohn Baldwin semid_t id; 8526bc1e9cdSJohn Baldwin u_int elapsed; 8536bc1e9cdSJohn Baldwin 8546bc1e9cdSJohn Baldwin if (ksem_init(&id, 0) < 0) { 8556bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 8566bc1e9cdSJohn Baldwin return; 8576bc1e9cdSJohn Baldwin } 8586bc1e9cdSJohn Baldwin 8596bc1e9cdSJohn Baldwin /* This should fail with a timeout and leave the value at 0. */ 8606bc1e9cdSJohn Baldwin if (timedwait(id, 2500, &elapsed, ETIMEDOUT) < 0) { 8616bc1e9cdSJohn Baldwin ksem_destroy(id); 8626bc1e9cdSJohn Baldwin return; 8636bc1e9cdSJohn Baldwin } 8646bc1e9cdSJohn Baldwin if (!ELAPSED(elapsed, 2500)) { 8656bc1e9cdSJohn Baldwin fail_err( 8666bc1e9cdSJohn Baldwin "ksem_timedwait() of locked sem took %ums instead of 2500ms", 8676bc1e9cdSJohn Baldwin elapsed); 8686bc1e9cdSJohn Baldwin ksem_destroy(id); 8696bc1e9cdSJohn Baldwin return; 8706bc1e9cdSJohn Baldwin } 8716bc1e9cdSJohn Baldwin if (checkvalue(id, 0) < 0) { 8726bc1e9cdSJohn Baldwin ksem_destroy(id); 8736bc1e9cdSJohn Baldwin return; 8746bc1e9cdSJohn Baldwin } 8756bc1e9cdSJohn Baldwin 8766bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 8776bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 8786bc1e9cdSJohn Baldwin return; 8796bc1e9cdSJohn Baldwin } 8806bc1e9cdSJohn Baldwin pass(); 8816bc1e9cdSJohn Baldwin } 8826bc1e9cdSJohn Baldwin TEST(expired_timedwait, "locked timedwait timeout"); 8836bc1e9cdSJohn Baldwin 8846bc1e9cdSJohn Baldwin static void 8856bc1e9cdSJohn Baldwin locked_timedwait(void) 8866bc1e9cdSJohn Baldwin { 8876bc1e9cdSJohn Baldwin semid_t id; 8886bc1e9cdSJohn Baldwin u_int elapsed; 8896bc1e9cdSJohn Baldwin 8906bc1e9cdSJohn Baldwin if (ksem_init(&id, 0) < 0) { 8916bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 8926bc1e9cdSJohn Baldwin return; 8936bc1e9cdSJohn Baldwin } 8946bc1e9cdSJohn Baldwin 8956bc1e9cdSJohn Baldwin /* 8966bc1e9cdSJohn Baldwin * Schedule a post to trigger after 1000 ms. The subsequent 8976bc1e9cdSJohn Baldwin * timedwait should succeed after 1000 ms as a result w/o 8986bc1e9cdSJohn Baldwin * timing out. 8996bc1e9cdSJohn Baldwin */ 9006bc1e9cdSJohn Baldwin if (schedule_post(id, 1000) < 0) { 9016bc1e9cdSJohn Baldwin ksem_destroy(id); 9026bc1e9cdSJohn Baldwin return; 9036bc1e9cdSJohn Baldwin } 9046bc1e9cdSJohn Baldwin if (timedwait(id, 2000, &elapsed, 0) < 0) { 9056bc1e9cdSJohn Baldwin check_alarm(1); 9066bc1e9cdSJohn Baldwin ksem_destroy(id); 9076bc1e9cdSJohn Baldwin return; 9086bc1e9cdSJohn Baldwin } 9096bc1e9cdSJohn Baldwin if (!ELAPSED(elapsed, 1000)) { 9106bc1e9cdSJohn Baldwin fail_err( 9116bc1e9cdSJohn Baldwin "ksem_timedwait() with delayed post took %ums instead of 1000ms", 9126bc1e9cdSJohn Baldwin elapsed); 9136bc1e9cdSJohn Baldwin check_alarm(1); 9146bc1e9cdSJohn Baldwin ksem_destroy(id); 9156bc1e9cdSJohn Baldwin return; 9166bc1e9cdSJohn Baldwin } 9176bc1e9cdSJohn Baldwin if (check_alarm(0) < 0) { 9186bc1e9cdSJohn Baldwin ksem_destroy(id); 9196bc1e9cdSJohn Baldwin return; 9206bc1e9cdSJohn Baldwin } 9216bc1e9cdSJohn Baldwin 9226bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 9236bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 9246bc1e9cdSJohn Baldwin return; 9256bc1e9cdSJohn Baldwin } 9266bc1e9cdSJohn Baldwin pass(); 9276bc1e9cdSJohn Baldwin } 9286bc1e9cdSJohn Baldwin TEST(locked_timedwait, "locked timedwait"); 9296bc1e9cdSJohn Baldwin 9306bc1e9cdSJohn Baldwin static int 9316bc1e9cdSJohn Baldwin testwait(semid_t id, u_int *delta) 9326bc1e9cdSJohn Baldwin { 9336bc1e9cdSJohn Baldwin struct timespec start, end; 9346bc1e9cdSJohn Baldwin 9356bc1e9cdSJohn Baldwin if (clock_gettime(CLOCK_REALTIME, &start) < 0) { 9366bc1e9cdSJohn Baldwin fail_errno("clock_gettime(CLOCK_REALTIME)"); 9376bc1e9cdSJohn Baldwin return (-1); 9386bc1e9cdSJohn Baldwin } 9396bc1e9cdSJohn Baldwin if (ksem_wait(id) < 0) { 9406bc1e9cdSJohn Baldwin fail_errno("ksem_wait"); 9416bc1e9cdSJohn Baldwin return (-1); 9426bc1e9cdSJohn Baldwin } 9436bc1e9cdSJohn Baldwin if (clock_gettime(CLOCK_REALTIME, &end) < 0) { 9446bc1e9cdSJohn Baldwin fail_errno("clock_gettime(CLOCK_REALTIME)"); 9456bc1e9cdSJohn Baldwin return (-1); 9466bc1e9cdSJohn Baldwin } 9476bc1e9cdSJohn Baldwin timespecsub(&end, &start); 9486bc1e9cdSJohn Baldwin *delta = end.tv_nsec / 1000000; 9496bc1e9cdSJohn Baldwin *delta += end.tv_sec * 1000; 9506bc1e9cdSJohn Baldwin return (0); 9516bc1e9cdSJohn Baldwin } 9526bc1e9cdSJohn Baldwin 9536bc1e9cdSJohn Baldwin static void 9546bc1e9cdSJohn Baldwin unlocked_wait(void) 9556bc1e9cdSJohn Baldwin { 9566bc1e9cdSJohn Baldwin semid_t id; 9576bc1e9cdSJohn Baldwin u_int elapsed; 9586bc1e9cdSJohn Baldwin 9596bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 9606bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 9616bc1e9cdSJohn Baldwin return; 9626bc1e9cdSJohn Baldwin } 9636bc1e9cdSJohn Baldwin 9646bc1e9cdSJohn Baldwin /* This should succeed right away and set the value to 0. */ 9656bc1e9cdSJohn Baldwin if (testwait(id, &elapsed) < 0) { 9666bc1e9cdSJohn Baldwin ksem_destroy(id); 9676bc1e9cdSJohn Baldwin return; 9686bc1e9cdSJohn Baldwin } 9696bc1e9cdSJohn Baldwin if (!ELAPSED(elapsed, 0)) { 9706bc1e9cdSJohn Baldwin fail_err("ksem_wait() of unlocked sem took %ums", elapsed); 9716bc1e9cdSJohn Baldwin ksem_destroy(id); 9726bc1e9cdSJohn Baldwin return; 9736bc1e9cdSJohn Baldwin } 9746bc1e9cdSJohn Baldwin if (checkvalue(id, 0) < 0) { 9756bc1e9cdSJohn Baldwin ksem_destroy(id); 9766bc1e9cdSJohn Baldwin return; 9776bc1e9cdSJohn Baldwin } 9786bc1e9cdSJohn Baldwin 9796bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 9806bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 9816bc1e9cdSJohn Baldwin return; 9826bc1e9cdSJohn Baldwin } 9836bc1e9cdSJohn Baldwin pass(); 9846bc1e9cdSJohn Baldwin } 9856bc1e9cdSJohn Baldwin TEST(unlocked_wait, "unlocked wait"); 9866bc1e9cdSJohn Baldwin 9876bc1e9cdSJohn Baldwin static void 9886bc1e9cdSJohn Baldwin locked_wait(void) 9896bc1e9cdSJohn Baldwin { 9906bc1e9cdSJohn Baldwin semid_t id; 9916bc1e9cdSJohn Baldwin u_int elapsed; 9926bc1e9cdSJohn Baldwin 9936bc1e9cdSJohn Baldwin if (ksem_init(&id, 0) < 0) { 9946bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 9956bc1e9cdSJohn Baldwin return; 9966bc1e9cdSJohn Baldwin } 9976bc1e9cdSJohn Baldwin 9986bc1e9cdSJohn Baldwin /* 9996bc1e9cdSJohn Baldwin * Schedule a post to trigger after 1000 ms. The subsequent 10006bc1e9cdSJohn Baldwin * wait should succeed after 1000 ms as a result. 10016bc1e9cdSJohn Baldwin */ 10026bc1e9cdSJohn Baldwin if (schedule_post(id, 1000) < 0) { 10036bc1e9cdSJohn Baldwin ksem_destroy(id); 10046bc1e9cdSJohn Baldwin return; 10056bc1e9cdSJohn Baldwin } 10066bc1e9cdSJohn Baldwin if (testwait(id, &elapsed) < 0) { 10076bc1e9cdSJohn Baldwin check_alarm(1); 10086bc1e9cdSJohn Baldwin ksem_destroy(id); 10096bc1e9cdSJohn Baldwin return; 10106bc1e9cdSJohn Baldwin } 10116bc1e9cdSJohn Baldwin if (!ELAPSED(elapsed, 1000)) { 10126bc1e9cdSJohn Baldwin fail_err( 10136bc1e9cdSJohn Baldwin "ksem_wait() with delayed post took %ums instead of 1000ms", 10146bc1e9cdSJohn Baldwin elapsed); 10156bc1e9cdSJohn Baldwin check_alarm(1); 10166bc1e9cdSJohn Baldwin ksem_destroy(id); 10176bc1e9cdSJohn Baldwin return; 10186bc1e9cdSJohn Baldwin } 10196bc1e9cdSJohn Baldwin if (check_alarm(0) < 0) { 10206bc1e9cdSJohn Baldwin ksem_destroy(id); 10216bc1e9cdSJohn Baldwin return; 10226bc1e9cdSJohn Baldwin } 10236bc1e9cdSJohn Baldwin 10246bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 10256bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 10266bc1e9cdSJohn Baldwin return; 10276bc1e9cdSJohn Baldwin } 10286bc1e9cdSJohn Baldwin pass(); 10296bc1e9cdSJohn Baldwin } 10306bc1e9cdSJohn Baldwin TEST(locked_wait, "locked wait"); 10316bc1e9cdSJohn Baldwin 10326bc1e9cdSJohn Baldwin /* 10336bc1e9cdSJohn Baldwin * Fork off a child process. The child will open the semaphore via 10346bc1e9cdSJohn Baldwin * the same name. The child will then block on the semaphore waiting 10356bc1e9cdSJohn Baldwin * for the parent to post it. 10366bc1e9cdSJohn Baldwin */ 10376bc1e9cdSJohn Baldwin static int 10386bc1e9cdSJohn Baldwin wait_twoproc_child(void *arg) 10396bc1e9cdSJohn Baldwin { 10406bc1e9cdSJohn Baldwin semid_t id; 10416bc1e9cdSJohn Baldwin 10426bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0) 10436bc1e9cdSJohn Baldwin return (CSTAT(1, errno)); 10446bc1e9cdSJohn Baldwin if (ksem_wait(id) < 0) 10456bc1e9cdSJohn Baldwin return (CSTAT(2, errno)); 10466bc1e9cdSJohn Baldwin if (ksem_close(id) < 0) 10476bc1e9cdSJohn Baldwin return (CSTAT(3, errno)); 10486bc1e9cdSJohn Baldwin return (CSTAT(0, 0)); 10496bc1e9cdSJohn Baldwin } 10506bc1e9cdSJohn Baldwin 10516bc1e9cdSJohn Baldwin static void 10526bc1e9cdSJohn Baldwin wait_twoproc_test(void) 10536bc1e9cdSJohn Baldwin { 10546bc1e9cdSJohn Baldwin semid_t id; 10556bc1e9cdSJohn Baldwin int stat; 10566bc1e9cdSJohn Baldwin 10576bc1e9cdSJohn Baldwin if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 0)) { 10586bc1e9cdSJohn Baldwin fail_errno("ksem_open"); 10596bc1e9cdSJohn Baldwin return; 10606bc1e9cdSJohn Baldwin } 10616bc1e9cdSJohn Baldwin 10626bc1e9cdSJohn Baldwin if (schedule_post(id, 500) < 0) { 10636bc1e9cdSJohn Baldwin ksem_close(id); 10646bc1e9cdSJohn Baldwin ksem_unlink(TEST_PATH); 10656bc1e9cdSJohn Baldwin return; 10666bc1e9cdSJohn Baldwin } 10676bc1e9cdSJohn Baldwin 10686bc1e9cdSJohn Baldwin if (child_worker(wait_twoproc_child, NULL, &stat) < 0) { 10696bc1e9cdSJohn Baldwin check_alarm(1); 10706bc1e9cdSJohn Baldwin ksem_close(id); 10716bc1e9cdSJohn Baldwin ksem_unlink(TEST_PATH); 10726bc1e9cdSJohn Baldwin return; 10736bc1e9cdSJohn Baldwin } 10746bc1e9cdSJohn Baldwin 10756bc1e9cdSJohn Baldwin errno = CSTAT_ERROR(stat); 10766bc1e9cdSJohn Baldwin switch (CSTAT_CLASS(stat)) { 10776bc1e9cdSJohn Baldwin case 0: 10786bc1e9cdSJohn Baldwin pass(); 10796bc1e9cdSJohn Baldwin break; 10806bc1e9cdSJohn Baldwin case 1: 10816bc1e9cdSJohn Baldwin fail_errno("child ksem_open()"); 10826bc1e9cdSJohn Baldwin break; 10836bc1e9cdSJohn Baldwin case 2: 10846bc1e9cdSJohn Baldwin fail_errno("child ksem_wait()"); 10856bc1e9cdSJohn Baldwin break; 10866bc1e9cdSJohn Baldwin case 3: 10876bc1e9cdSJohn Baldwin fail_errno("child ksem_close()"); 10886bc1e9cdSJohn Baldwin break; 10896bc1e9cdSJohn Baldwin default: 10906bc1e9cdSJohn Baldwin fail_err("bad child state %#x", stat); 10916bc1e9cdSJohn Baldwin break; 10926bc1e9cdSJohn Baldwin } 10936bc1e9cdSJohn Baldwin 10946bc1e9cdSJohn Baldwin check_alarm(1); 10956bc1e9cdSJohn Baldwin ksem_close(id); 10966bc1e9cdSJohn Baldwin ksem_unlink(TEST_PATH); 10976bc1e9cdSJohn Baldwin } 10986bc1e9cdSJohn Baldwin TEST(wait_twoproc_test, "two proc wait"); 10996bc1e9cdSJohn Baldwin 11006bc1e9cdSJohn Baldwin static void 11016bc1e9cdSJohn Baldwin maxvalue_test(void) 11026bc1e9cdSJohn Baldwin { 11036bc1e9cdSJohn Baldwin semid_t id; 11046bc1e9cdSJohn Baldwin int val; 11056bc1e9cdSJohn Baldwin 11066bc1e9cdSJohn Baldwin if (ksem_init(&id, SEM_VALUE_MAX) < 0) { 11076bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 11086bc1e9cdSJohn Baldwin return; 11096bc1e9cdSJohn Baldwin } 11106bc1e9cdSJohn Baldwin if (ksem_getvalue(id, &val) < 0) { 11116bc1e9cdSJohn Baldwin fail_errno("ksem_getvalue"); 11126bc1e9cdSJohn Baldwin ksem_destroy(id); 11136bc1e9cdSJohn Baldwin return; 11146bc1e9cdSJohn Baldwin } 11156bc1e9cdSJohn Baldwin if (val != SEM_VALUE_MAX) { 11166bc1e9cdSJohn Baldwin fail_err("value %d != SEM_VALUE_MAX"); 11176bc1e9cdSJohn Baldwin ksem_destroy(id); 11186bc1e9cdSJohn Baldwin return; 11196bc1e9cdSJohn Baldwin } 11206bc1e9cdSJohn Baldwin if (val < 0) { 11216bc1e9cdSJohn Baldwin fail_err("value < 0"); 11226bc1e9cdSJohn Baldwin ksem_destroy(id); 11236bc1e9cdSJohn Baldwin return; 11246bc1e9cdSJohn Baldwin } 11256bc1e9cdSJohn Baldwin if (ksem_destroy(id) < 0) { 11266bc1e9cdSJohn Baldwin fail_errno("ksem_destroy"); 11276bc1e9cdSJohn Baldwin return; 11286bc1e9cdSJohn Baldwin } 11296bc1e9cdSJohn Baldwin pass(); 11306bc1e9cdSJohn Baldwin } 11316bc1e9cdSJohn Baldwin TEST(maxvalue_test, "get value of SEM_VALUE_MAX semaphore"); 11326bc1e9cdSJohn Baldwin 11336bc1e9cdSJohn Baldwin static void 11346bc1e9cdSJohn Baldwin maxvalue_post_test(void) 11356bc1e9cdSJohn Baldwin { 11366bc1e9cdSJohn Baldwin semid_t id; 11376bc1e9cdSJohn Baldwin 11386bc1e9cdSJohn Baldwin if (ksem_init(&id, SEM_VALUE_MAX) < 0) { 11396bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 11406bc1e9cdSJohn Baldwin return; 11416bc1e9cdSJohn Baldwin } 11426bc1e9cdSJohn Baldwin 11436bc1e9cdSJohn Baldwin ksem_post_should_fail(id, EOVERFLOW); 11446bc1e9cdSJohn Baldwin 11456bc1e9cdSJohn Baldwin ksem_destroy(id); 11466bc1e9cdSJohn Baldwin } 11476bc1e9cdSJohn Baldwin TEST(maxvalue_post_test, "post SEM_VALUE_MAX semaphore"); 11486bc1e9cdSJohn Baldwin 11496bc1e9cdSJohn Baldwin static void 11506bc1e9cdSJohn Baldwin busy_destroy_test(void) 11516bc1e9cdSJohn Baldwin { 11526bc1e9cdSJohn Baldwin char errbuf[_POSIX2_LINE_MAX]; 11536bc1e9cdSJohn Baldwin struct kinfo_proc *kp; 11546bc1e9cdSJohn Baldwin semid_t id; 11556bc1e9cdSJohn Baldwin pid_t pid; 11566bc1e9cdSJohn Baldwin kvm_t *kd; 11576bc1e9cdSJohn Baldwin int count; 11586bc1e9cdSJohn Baldwin 11596bc1e9cdSJohn Baldwin kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf); 11606bc1e9cdSJohn Baldwin if (kd == NULL) { 11616bc1e9cdSJohn Baldwin fail_err("kvm_openfiles: %s", errbuf); 11626bc1e9cdSJohn Baldwin return; 11636bc1e9cdSJohn Baldwin } 11646bc1e9cdSJohn Baldwin 11656bc1e9cdSJohn Baldwin if (ksem_init(&id, 0) < 0) { 11666bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 11676bc1e9cdSJohn Baldwin kvm_close(kd); 11686bc1e9cdSJohn Baldwin return; 11696bc1e9cdSJohn Baldwin } 11706bc1e9cdSJohn Baldwin 11716bc1e9cdSJohn Baldwin pid = fork(); 11726bc1e9cdSJohn Baldwin switch (pid) { 11736bc1e9cdSJohn Baldwin case -1: 11746bc1e9cdSJohn Baldwin /* Error. */ 11756bc1e9cdSJohn Baldwin fail_errno("fork"); 11766bc1e9cdSJohn Baldwin ksem_destroy(id); 11776bc1e9cdSJohn Baldwin kvm_close(kd); 11786bc1e9cdSJohn Baldwin return; 11796bc1e9cdSJohn Baldwin case 0: 11806bc1e9cdSJohn Baldwin /* Child. */ 11816bc1e9cdSJohn Baldwin ksem_wait(id); 11826bc1e9cdSJohn Baldwin exit(0); 11836bc1e9cdSJohn Baldwin } 11846bc1e9cdSJohn Baldwin 11856bc1e9cdSJohn Baldwin /* 11866bc1e9cdSJohn Baldwin * Wait for the child process to block on the semaphore. This 11876bc1e9cdSJohn Baldwin * is a bit gross. 11886bc1e9cdSJohn Baldwin */ 11896bc1e9cdSJohn Baldwin for (;;) { 11906bc1e9cdSJohn Baldwin kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); 11916bc1e9cdSJohn Baldwin if (kp == NULL) { 11926bc1e9cdSJohn Baldwin fail_err("kvm_getprocs: %s", kvm_geterr(kd)); 11936bc1e9cdSJohn Baldwin kvm_close(kd); 11946bc1e9cdSJohn Baldwin ksem_destroy(id); 11956bc1e9cdSJohn Baldwin return; 11966bc1e9cdSJohn Baldwin } 11976bc1e9cdSJohn Baldwin if (kp->ki_stat == SSLEEP && 11986bc1e9cdSJohn Baldwin (strcmp(kp->ki_wmesg, "sem") == 0 || 11996bc1e9cdSJohn Baldwin strcmp(kp->ki_wmesg, "ksem") == 0)) 12006bc1e9cdSJohn Baldwin break; 12016bc1e9cdSJohn Baldwin usleep(1000); 12026bc1e9cdSJohn Baldwin } 12036bc1e9cdSJohn Baldwin kvm_close(kd); 12046bc1e9cdSJohn Baldwin 12056bc1e9cdSJohn Baldwin ksem_destroy_should_fail(id, EBUSY); 12066bc1e9cdSJohn Baldwin 12076bc1e9cdSJohn Baldwin /* Cleanup. */ 12086bc1e9cdSJohn Baldwin ksem_post(id); 12096bc1e9cdSJohn Baldwin waitpid(pid, NULL, 0); 12106bc1e9cdSJohn Baldwin ksem_destroy(id); 12116bc1e9cdSJohn Baldwin } 12126bc1e9cdSJohn Baldwin TEST(busy_destroy_test, "destroy unnamed semaphore with waiter"); 12136bc1e9cdSJohn Baldwin 12146bc1e9cdSJohn Baldwin static int 12156bc1e9cdSJohn Baldwin exhaust_unnamed_child(void *arg) 12166bc1e9cdSJohn Baldwin { 12176bc1e9cdSJohn Baldwin semid_t id; 12186bc1e9cdSJohn Baldwin int i, max; 12196bc1e9cdSJohn Baldwin 12206bc1e9cdSJohn Baldwin max = (intptr_t)arg; 12216bc1e9cdSJohn Baldwin for (i = 0; i < max + 1; i++) { 12226bc1e9cdSJohn Baldwin if (ksem_init(&id, 1) < 0) { 12236bc1e9cdSJohn Baldwin if (errno == ENOSPC) 12246bc1e9cdSJohn Baldwin return (CSTAT(0, 0)); 12256bc1e9cdSJohn Baldwin return (CSTAT(1, errno)); 12266bc1e9cdSJohn Baldwin } 12276bc1e9cdSJohn Baldwin } 12286bc1e9cdSJohn Baldwin return (CSTAT(2, 0)); 12296bc1e9cdSJohn Baldwin } 12306bc1e9cdSJohn Baldwin 12316bc1e9cdSJohn Baldwin static void 12326bc1e9cdSJohn Baldwin exhaust_unnamed_sems(void) 12336bc1e9cdSJohn Baldwin { 12346bc1e9cdSJohn Baldwin size_t len; 12356bc1e9cdSJohn Baldwin int nsems_max, stat; 12366bc1e9cdSJohn Baldwin 12376bc1e9cdSJohn Baldwin len = sizeof(nsems_max); 12386bc1e9cdSJohn Baldwin if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) < 12396bc1e9cdSJohn Baldwin 0) { 12406bc1e9cdSJohn Baldwin fail_errno("sysctl(p1003_1b.sem_nsems_max)"); 12416bc1e9cdSJohn Baldwin return; 12426bc1e9cdSJohn Baldwin } 12436bc1e9cdSJohn Baldwin 124431f95703SKonstantin Belousov if (child_worker(exhaust_unnamed_child, (void *)(uintptr_t)nsems_max, 124531f95703SKonstantin Belousov &stat)) 12466bc1e9cdSJohn Baldwin return; 12476bc1e9cdSJohn Baldwin errno = CSTAT_ERROR(stat); 12486bc1e9cdSJohn Baldwin switch (CSTAT_CLASS(stat)) { 12496bc1e9cdSJohn Baldwin case 0: 12506bc1e9cdSJohn Baldwin pass(); 12516bc1e9cdSJohn Baldwin break; 12526bc1e9cdSJohn Baldwin case 1: 12536bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 12546bc1e9cdSJohn Baldwin break; 12556bc1e9cdSJohn Baldwin case 2: 12566bc1e9cdSJohn Baldwin fail_err("Limit of %d semaphores not enforced", nsems_max); 12576bc1e9cdSJohn Baldwin break; 12586bc1e9cdSJohn Baldwin default: 12596bc1e9cdSJohn Baldwin fail_err("bad child state %#x", stat); 12606bc1e9cdSJohn Baldwin break; 12616bc1e9cdSJohn Baldwin } 12626bc1e9cdSJohn Baldwin } 12636bc1e9cdSJohn Baldwin TEST(exhaust_unnamed_sems, "exhaust unnamed semaphores (1)"); 12646bc1e9cdSJohn Baldwin 12656bc1e9cdSJohn Baldwin static int 12666bc1e9cdSJohn Baldwin exhaust_named_child(void *arg) 12676bc1e9cdSJohn Baldwin { 12686bc1e9cdSJohn Baldwin char buffer[64]; 12696bc1e9cdSJohn Baldwin semid_t id; 12706bc1e9cdSJohn Baldwin int i, max; 12716bc1e9cdSJohn Baldwin 12726bc1e9cdSJohn Baldwin max = (intptr_t)arg; 12736bc1e9cdSJohn Baldwin for (i = 0; i < max + 1; i++) { 12746bc1e9cdSJohn Baldwin snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i); 12756bc1e9cdSJohn Baldwin if (ksem_open(&id, buffer, O_CREAT, 0777, 1) < 0) { 12766bc1e9cdSJohn Baldwin if (errno == ENOSPC || errno == EMFILE || 12776bc1e9cdSJohn Baldwin errno == ENFILE) 12786bc1e9cdSJohn Baldwin return (CSTAT(0, 0)); 12796bc1e9cdSJohn Baldwin return (CSTAT(1, errno)); 12806bc1e9cdSJohn Baldwin } 12816bc1e9cdSJohn Baldwin } 12826bc1e9cdSJohn Baldwin return (CSTAT(2, errno)); 12836bc1e9cdSJohn Baldwin } 12846bc1e9cdSJohn Baldwin 12856bc1e9cdSJohn Baldwin static void 12866bc1e9cdSJohn Baldwin exhaust_named_sems(void) 12876bc1e9cdSJohn Baldwin { 12886bc1e9cdSJohn Baldwin char buffer[64]; 12896bc1e9cdSJohn Baldwin size_t len; 12906bc1e9cdSJohn Baldwin int i, nsems_max, stat; 12916bc1e9cdSJohn Baldwin 12926bc1e9cdSJohn Baldwin len = sizeof(nsems_max); 12936bc1e9cdSJohn Baldwin if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) < 12946bc1e9cdSJohn Baldwin 0) { 12956bc1e9cdSJohn Baldwin fail_errno("sysctl(p1003_1b.sem_nsems_max)"); 12966bc1e9cdSJohn Baldwin return; 12976bc1e9cdSJohn Baldwin } 12986bc1e9cdSJohn Baldwin 129931f95703SKonstantin Belousov if (child_worker(exhaust_named_child, (void *)(uintptr_t)nsems_max, 130031f95703SKonstantin Belousov &stat) < 0) 13016bc1e9cdSJohn Baldwin return; 13026bc1e9cdSJohn Baldwin errno = CSTAT_ERROR(stat); 13036bc1e9cdSJohn Baldwin switch (CSTAT_CLASS(stat)) { 13046bc1e9cdSJohn Baldwin case 0: 13056bc1e9cdSJohn Baldwin pass(); 13066bc1e9cdSJohn Baldwin break; 13076bc1e9cdSJohn Baldwin case 1: 13086bc1e9cdSJohn Baldwin fail_errno("ksem_open"); 13096bc1e9cdSJohn Baldwin break; 13106bc1e9cdSJohn Baldwin case 2: 13116bc1e9cdSJohn Baldwin fail_err("Limit of %d semaphores not enforced", nsems_max); 13126bc1e9cdSJohn Baldwin break; 13136bc1e9cdSJohn Baldwin default: 13146bc1e9cdSJohn Baldwin fail_err("bad child state %#x", stat); 13156bc1e9cdSJohn Baldwin break; 13166bc1e9cdSJohn Baldwin } 13176bc1e9cdSJohn Baldwin 13186bc1e9cdSJohn Baldwin /* Cleanup any semaphores created by the child. */ 13196bc1e9cdSJohn Baldwin for (i = 0; i < nsems_max + 1; i++) { 13206bc1e9cdSJohn Baldwin snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i); 13216bc1e9cdSJohn Baldwin ksem_unlink(buffer); 13226bc1e9cdSJohn Baldwin } 13236bc1e9cdSJohn Baldwin } 13246bc1e9cdSJohn Baldwin TEST(exhaust_named_sems, "exhaust named semaphores (1)"); 13256bc1e9cdSJohn Baldwin 13266bc1e9cdSJohn Baldwin static int 13276bc1e9cdSJohn Baldwin fdlimit_set(void *arg) 13286bc1e9cdSJohn Baldwin { 13296bc1e9cdSJohn Baldwin struct rlimit rlim; 13306bc1e9cdSJohn Baldwin int max; 13316bc1e9cdSJohn Baldwin 13326bc1e9cdSJohn Baldwin max = (intptr_t)arg; 13336bc1e9cdSJohn Baldwin if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) 13346bc1e9cdSJohn Baldwin return (CSTAT(3, errno)); 13356bc1e9cdSJohn Baldwin rlim.rlim_cur = max; 13366bc1e9cdSJohn Baldwin if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) 13376bc1e9cdSJohn Baldwin return (CSTAT(4, errno)); 13386bc1e9cdSJohn Baldwin return (0); 13396bc1e9cdSJohn Baldwin } 13406bc1e9cdSJohn Baldwin 13416bc1e9cdSJohn Baldwin static int 13426bc1e9cdSJohn Baldwin fdlimit_unnamed_child(void *arg) 13436bc1e9cdSJohn Baldwin { 13446bc1e9cdSJohn Baldwin int stat; 13456bc1e9cdSJohn Baldwin 13466bc1e9cdSJohn Baldwin stat = fdlimit_set(arg); 13476bc1e9cdSJohn Baldwin if (stat == 0) 13486bc1e9cdSJohn Baldwin stat = exhaust_unnamed_child(arg); 13496bc1e9cdSJohn Baldwin return (stat); 13506bc1e9cdSJohn Baldwin } 13516bc1e9cdSJohn Baldwin 13526bc1e9cdSJohn Baldwin static void 13536bc1e9cdSJohn Baldwin fdlimit_unnamed_sems(void) 13546bc1e9cdSJohn Baldwin { 13556bc1e9cdSJohn Baldwin int nsems_max, stat; 13566bc1e9cdSJohn Baldwin 13576bc1e9cdSJohn Baldwin nsems_max = 10; 135831f95703SKonstantin Belousov if (child_worker(fdlimit_unnamed_child, (void *)(uintptr_t)nsems_max, 135931f95703SKonstantin Belousov &stat)) 13606bc1e9cdSJohn Baldwin return; 13616bc1e9cdSJohn Baldwin errno = CSTAT_ERROR(stat); 13626bc1e9cdSJohn Baldwin switch (CSTAT_CLASS(stat)) { 13636bc1e9cdSJohn Baldwin case 0: 13646bc1e9cdSJohn Baldwin pass(); 13656bc1e9cdSJohn Baldwin break; 13666bc1e9cdSJohn Baldwin case 1: 13676bc1e9cdSJohn Baldwin fail_errno("ksem_init"); 13686bc1e9cdSJohn Baldwin break; 13696bc1e9cdSJohn Baldwin case 2: 13706bc1e9cdSJohn Baldwin fail_err("Limit of %d semaphores not enforced", nsems_max); 13716bc1e9cdSJohn Baldwin break; 13726bc1e9cdSJohn Baldwin case 3: 13736bc1e9cdSJohn Baldwin fail_errno("getrlimit"); 13746bc1e9cdSJohn Baldwin break; 13756bc1e9cdSJohn Baldwin case 4: 13766bc1e9cdSJohn Baldwin fail_errno("getrlimit"); 13776bc1e9cdSJohn Baldwin break; 13786bc1e9cdSJohn Baldwin default: 13796bc1e9cdSJohn Baldwin fail_err("bad child state %#x", stat); 13806bc1e9cdSJohn Baldwin break; 13816bc1e9cdSJohn Baldwin } 13826bc1e9cdSJohn Baldwin } 13836bc1e9cdSJohn Baldwin TEST(fdlimit_unnamed_sems, "exhaust unnamed semaphores (2)"); 13846bc1e9cdSJohn Baldwin 13856bc1e9cdSJohn Baldwin static int 13866bc1e9cdSJohn Baldwin fdlimit_named_child(void *arg) 13876bc1e9cdSJohn Baldwin { 13886bc1e9cdSJohn Baldwin int stat; 13896bc1e9cdSJohn Baldwin 13906bc1e9cdSJohn Baldwin stat = fdlimit_set(arg); 13916bc1e9cdSJohn Baldwin if (stat == 0) 13926bc1e9cdSJohn Baldwin stat = exhaust_named_child(arg); 13936bc1e9cdSJohn Baldwin return (stat); 13946bc1e9cdSJohn Baldwin } 13956bc1e9cdSJohn Baldwin 13966bc1e9cdSJohn Baldwin static void 13976bc1e9cdSJohn Baldwin fdlimit_named_sems(void) 13986bc1e9cdSJohn Baldwin { 13996bc1e9cdSJohn Baldwin char buffer[64]; 14006bc1e9cdSJohn Baldwin int i, nsems_max, stat; 14016bc1e9cdSJohn Baldwin 14026bc1e9cdSJohn Baldwin nsems_max = 10; 140331f95703SKonstantin Belousov if (child_worker(fdlimit_named_child, (void *)(uintptr_t)nsems_max, 140431f95703SKonstantin Belousov &stat) < 0) 14056bc1e9cdSJohn Baldwin return; 14066bc1e9cdSJohn Baldwin errno = CSTAT_ERROR(stat); 14076bc1e9cdSJohn Baldwin switch (CSTAT_CLASS(stat)) { 14086bc1e9cdSJohn Baldwin case 0: 14096bc1e9cdSJohn Baldwin pass(); 14106bc1e9cdSJohn Baldwin break; 14116bc1e9cdSJohn Baldwin case 1: 14126bc1e9cdSJohn Baldwin fail_errno("ksem_open"); 14136bc1e9cdSJohn Baldwin break; 14146bc1e9cdSJohn Baldwin case 2: 14156bc1e9cdSJohn Baldwin fail_err("Limit of %d semaphores not enforced", nsems_max); 14166bc1e9cdSJohn Baldwin break; 14176bc1e9cdSJohn Baldwin case 3: 14186bc1e9cdSJohn Baldwin fail_errno("getrlimit"); 14196bc1e9cdSJohn Baldwin break; 14206bc1e9cdSJohn Baldwin case 4: 14216bc1e9cdSJohn Baldwin fail_errno("getrlimit"); 14226bc1e9cdSJohn Baldwin break; 14236bc1e9cdSJohn Baldwin default: 14246bc1e9cdSJohn Baldwin fail_err("bad child state %#x", stat); 14256bc1e9cdSJohn Baldwin break; 14266bc1e9cdSJohn Baldwin } 14276bc1e9cdSJohn Baldwin 14286bc1e9cdSJohn Baldwin /* Cleanup any semaphores created by the child. */ 14296bc1e9cdSJohn Baldwin for (i = 0; i < nsems_max + 1; i++) { 14306bc1e9cdSJohn Baldwin snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i); 14316bc1e9cdSJohn Baldwin ksem_unlink(buffer); 14326bc1e9cdSJohn Baldwin } 14336bc1e9cdSJohn Baldwin } 14346bc1e9cdSJohn Baldwin TEST(fdlimit_named_sems, "exhaust named semaphores (2)"); 14356bc1e9cdSJohn Baldwin 14366bc1e9cdSJohn Baldwin int 14376bc1e9cdSJohn Baldwin main(int argc, char *argv[]) 14386bc1e9cdSJohn Baldwin { 14396bc1e9cdSJohn Baldwin 14406bc1e9cdSJohn Baldwin signal(SIGSYS, SIG_IGN); 14416bc1e9cdSJohn Baldwin run_tests(); 14426bc1e9cdSJohn Baldwin return (0); 14436bc1e9cdSJohn Baldwin } 1444