xref: /freebsd/tools/regression/posixsem/posixsem.c (revision 8a16b7a18f5d0b031f09832fd7752fba717e2a97)
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