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