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