2 * Copyright (c) 2008 Yahoo!, Inc.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/_semaphore.h>
37 #include <sys/sysctl.h>
46 #include <semaphore.h>
56 /* Cut and pasted from kernel header, bah! */
58 /* Operations on timespecs */
59 #define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0)
60 #define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec)
61 #define timespeccmp(tvp, uvp, cmp) \
62 (((tvp)->tv_sec == (uvp)->tv_sec) ? \
63 ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
64 ((tvp)->tv_sec cmp (uvp)->tv_sec))
65 #define timespecadd(vvp, uvp) \
67 (vvp)->tv_sec += (uvp)->tv_sec; \
68 (vvp)->tv_nsec += (uvp)->tv_nsec; \
69 if ((vvp)->tv_nsec >= 1000000000) { \
71 (vvp)->tv_nsec -= 1000000000; \
74 #define timespecsub(vvp, uvp) \
76 (vvp)->tv_sec -= (uvp)->tv_sec; \
77 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
78 if ((vvp)->tv_nsec < 0) { \
80 (vvp)->tv_nsec += 1000000000; \
85 #define TEST_PATH "/tmp/posixsem_regression_test"
87 #define ELAPSED(elapsed, limit) (abs((elapsed) - (limit)) < 100)
89 /* Macros for passing child status to parent over a pipe. */
90 #define CSTAT(class, error) ((class) << 16 | (error))
91 #define CSTAT_CLASS(stat) ((stat) >> 16)
92 #define CSTAT_ERROR(stat) ((stat) & 0xffff)
95 * Helper routine for tests that use a child process. This routine
96 * creates a pipe and forks a child process. The child process runs
97 * the 'func' routine which returns a status integer. The status
98 * integer gets written over the pipe to the parent and returned in
99 * '*stat'. If there is an error in pipe(), fork(), or wait() this
100 * returns -1 and fails the test.
103 child_worker(int (*func)(void *arg), void *arg, int *stat)
124 write(pfd[1], &cstat, sizeof(cstat));
128 if (read(pfd[0], stat, sizeof(*stat)) < 0) {
129 fail_errno("read(pipe)");
134 if (waitpid(pid, NULL, 0) < 0) {
146 * Attempt a ksem_open() that should fail with an expected error of
150 ksem_open_should_fail(const char *path, int flags, mode_t mode, unsigned int
155 if (ksem_open(&id, path, flags, mode, value) >= 0) {
156 fail_err("ksem_open() didn't fail");
160 if (errno != error) {
161 fail_errno("ksem_open");
168 * Attempt a ksem_unlink() that should fail with an expected error of
172 ksem_unlink_should_fail(const char *path, int error)
175 if (ksem_unlink(path) >= 0) {
176 fail_err("ksem_unlink() didn't fail");
179 if (errno != error) {
180 fail_errno("ksem_unlink");
187 * Attempt a ksem_close() that should fail with an expected error of
191 ksem_close_should_fail(semid_t id, int error)
194 if (ksem_close(id) >= 0) {
195 fail_err("ksem_close() didn't fail");
198 if (errno != error) {
199 fail_errno("ksem_close");
206 * Attempt a ksem_init() that should fail with an expected error of
210 ksem_init_should_fail(unsigned int value, int error)
214 if (ksem_init(&id, value) >= 0) {
215 fail_err("ksem_init() didn't fail");
219 if (errno != error) {
220 fail_errno("ksem_init");
227 * Attempt a ksem_destroy() that should fail with an expected error of
231 ksem_destroy_should_fail(semid_t id, int error)
234 if (ksem_destroy(id) >= 0) {
235 fail_err("ksem_destroy() didn't fail");
238 if (errno != error) {
239 fail_errno("ksem_destroy");
246 * Attempt a ksem_post() that should fail with an expected error of
250 ksem_post_should_fail(semid_t id, int error)
253 if (ksem_post(id) >= 0) {
254 fail_err("ksem_post() didn't fail");
257 if (errno != error) {
258 fail_errno("ksem_post");
265 open_after_unlink(void)
269 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
270 fail_errno("ksem_open(1)");
275 if (ksem_unlink(TEST_PATH) < 0) {
276 fail_errno("ksem_unlink");
280 ksem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT);
282 TEST(open_after_unlink, "open after unlink");
285 open_invalid_path(void)
288 ksem_open_should_fail("blah", 0, 0777, 1, EINVAL);
290 TEST(open_invalid_path, "open invalid path");
293 open_extra_flags(void)
296 ksem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL);
298 TEST(open_extra_flags, "open with extra flags");
304 (void)ksem_unlink(TEST_PATH);
306 ksem_open_should_fail(TEST_PATH, O_CREAT, 0777, UINT_MAX, EINVAL);
308 TEST(open_bad_value, "open with invalid initial value");
311 open_bad_path_pointer(void)
314 ksem_open_should_fail((char *)1024, O_RDONLY, 0777, 1, EFAULT);
316 TEST(open_bad_path_pointer, "open bad path pointer");
319 open_path_too_long(void)
323 page = malloc(MAXPATHLEN + 1);
324 memset(page, 'a', MAXPATHLEN);
325 page[MAXPATHLEN] = '\0';
326 ksem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG);
329 TEST(open_path_too_long, "open pathname too long");
332 open_nonexisting_semaphore(void)
335 ksem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT);
337 TEST(open_nonexisting_semaphore, "open nonexistent semaphore");
340 exclusive_create_existing_semaphore(void)
344 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
345 fail_errno("ksem_open(O_CREAT)");
350 ksem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST);
352 ksem_unlink(TEST_PATH);
354 TEST(exclusive_create_existing_semaphore, "O_EXCL of existing semaphore");
360 ksem_init_should_fail(UINT_MAX, EINVAL);
362 TEST(init_bad_value, "init with invalid initial value");
365 unlink_bad_path_pointer(void)
368 ksem_unlink_should_fail((char *)1024, EFAULT);
370 TEST(unlink_bad_path_pointer, "unlink bad path pointer");
373 unlink_path_too_long(void)
377 page = malloc(MAXPATHLEN + 1);
378 memset(page, 'a', MAXPATHLEN);
379 page[MAXPATHLEN] = '\0';
380 ksem_unlink_should_fail(page, ENAMETOOLONG);
383 TEST(unlink_path_too_long, "unlink pathname too long");
386 destroy_named_semaphore(void)
390 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
391 fail_errno("ksem_open(O_CREAT)");
395 ksem_destroy_should_fail(id, EINVAL);
398 ksem_unlink(TEST_PATH);
400 TEST(destroy_named_semaphore, "destroy named semaphore");
403 close_unnamed_semaphore(void)
407 if (ksem_init(&id, 1) < 0) {
408 fail_errno("ksem_init");
412 ksem_close_should_fail(id, EINVAL);
416 TEST(close_unnamed_semaphore, "close unnamed semaphore");
419 destroy_invalid_fd(void)
422 ksem_destroy_should_fail(STDERR_FILENO, EINVAL);
424 TEST(destroy_invalid_fd, "destroy non-semaphore file descriptor");
427 close_invalid_fd(void)
430 ksem_close_should_fail(STDERR_FILENO, EINVAL);
432 TEST(close_invalid_fd, "close non-semaphore file descriptor");
435 create_unnamed_semaphore(void)
439 if (ksem_init(&id, 1) < 0) {
440 fail_errno("ksem_init");
444 if (ksem_destroy(id) < 0) {
445 fail_errno("ksem_destroy");
450 TEST(create_unnamed_semaphore, "create unnamed semaphore");
453 open_named_semaphore(void)
457 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
458 fail_errno("ksem_open(O_CREAT)");
462 if (ksem_close(id) < 0) {
463 fail_errno("ksem_close");
467 if (ksem_unlink(TEST_PATH) < 0) {
468 fail_errno("ksem_unlink");
473 TEST(open_named_semaphore, "create named semaphore");
476 getvalue_invalid_semaphore(void)
480 if (ksem_getvalue(STDERR_FILENO, &val) >= 0) {
481 fail_err("ksem_getvalue() didn't fail");
484 if (errno != EINVAL) {
485 fail_errno("ksem_getvalue");
490 TEST(getvalue_invalid_semaphore, "get value of invalid semaphore");
493 post_invalid_semaphore(void)
496 ksem_post_should_fail(STDERR_FILENO, EINVAL);
498 TEST(post_invalid_semaphore, "post of invalid semaphore");
501 wait_invalid_semaphore(void)
504 if (ksem_wait(STDERR_FILENO) >= 0) {
505 fail_err("ksem_wait() didn't fail");
508 if (errno != EINVAL) {
509 fail_errno("ksem_wait");
514 TEST(wait_invalid_semaphore, "wait for invalid semaphore");
517 trywait_invalid_semaphore(void)
520 if (ksem_trywait(STDERR_FILENO) >= 0) {
521 fail_err("ksem_trywait() didn't fail");
524 if (errno != EINVAL) {
525 fail_errno("ksem_trywait");
530 TEST(trywait_invalid_semaphore, "try wait for invalid semaphore");
533 timedwait_invalid_semaphore(void)
536 if (ksem_timedwait(STDERR_FILENO, NULL) >= 0) {
537 fail_err("ksem_timedwait() didn't fail");
540 if (errno != EINVAL) {
541 fail_errno("ksem_timedwait");
546 TEST(timedwait_invalid_semaphore, "timed wait for invalid semaphore");
549 checkvalue(semid_t id, int expected)
553 if (ksem_getvalue(id, &val) < 0) {
554 fail_errno("ksem_getvalue");
557 if (val != expected) {
558 fail_err("sem value should be %d instead of %d", expected, val);
569 if (ksem_init(&id, 1) < 0) {
570 fail_errno("ksem_init");
573 if (checkvalue(id, 1) < 0) {
577 if (ksem_post(id) < 0) {
578 fail_errno("ksem_post");
582 if (checkvalue(id, 2) < 0) {
586 if (ksem_destroy(id) < 0) {
587 fail_errno("ksem_destroy");
592 TEST(post_test, "simple post");
595 use_after_unlink_test(void)
600 * Create named semaphore with value of 1 and then unlink it
601 * while still retaining the initial reference.
603 if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) {
604 fail_errno("ksem_open(O_CREAT | O_EXCL)");
607 if (ksem_unlink(TEST_PATH) < 0) {
608 fail_errno("ksem_unlink");
612 if (checkvalue(id, 1) < 0) {
617 /* Post the semaphore to set its value to 2. */
618 if (ksem_post(id) < 0) {
619 fail_errno("ksem_post");
623 if (checkvalue(id, 2) < 0) {
628 /* Wait on the semaphore which should set its value to 1. */
629 if (ksem_wait(id) < 0) {
630 fail_errno("ksem_wait");
634 if (checkvalue(id, 1) < 0) {
639 if (ksem_close(id) < 0) {
640 fail_errno("ksem_close");
645 TEST(use_after_unlink_test, "use named semaphore after unlink");
648 unlocked_trywait(void)
652 if (ksem_init(&id, 1) < 0) {
653 fail_errno("ksem_init");
657 /* This should succeed and decrement the value to 0. */
658 if (ksem_trywait(id) < 0) {
659 fail_errno("ksem_trywait()");
663 if (checkvalue(id, 0) < 0) {
668 if (ksem_destroy(id) < 0) {
669 fail_errno("ksem_destroy");
674 TEST(unlocked_trywait, "unlocked trywait");
681 if (ksem_init(&id, 0) < 0) {
682 fail_errno("ksem_init");
686 /* This should fail with EAGAIN and leave the value at 0. */
687 if (ksem_trywait(id) >= 0) {
688 fail_err("ksem_trywait() didn't fail");
692 if (errno != EAGAIN) {
693 fail_errno("wrong error from ksem_trywait()");
697 if (checkvalue(id, 0) < 0) {
702 if (ksem_destroy(id) < 0) {
703 fail_errno("ksem_destroy");
708 TEST(locked_trywait, "locked trywait");
711 * Use a timer to post a specific semaphore after a timeout. A timer
712 * is scheduled via schedule_post(). check_alarm() must be called
713 * afterwards to clean up and check for errors.
715 static semid_t alarm_id = -1;
716 static int alarm_errno;
717 static int alarm_handler_installed;
720 alarm_handler(int signo)
723 if (ksem_post(alarm_id) < 0)
728 check_alarm(int just_clear)
732 bzero(&it, sizeof(it));
734 setitimer(ITIMER_REAL, &it, NULL);
739 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
740 fail_errno("setitimer");
743 if (alarm_errno != 0 && !just_clear) {
745 fail_errno("ksem_post() (via timeout)");
755 schedule_post(semid_t id, u_int msec)
759 if (!alarm_handler_installed) {
760 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
761 fail_errno("signal(SIGALRM)");
764 alarm_handler_installed = 1;
766 if (alarm_id != -1) {
767 fail_err("ksem_post() already scheduled");
771 bzero(&it, sizeof(it));
772 it.it_value.tv_sec = msec / 1000;
773 it.it_value.tv_usec = (msec % 1000) * 1000;
774 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
775 fail_errno("setitimer");
782 timedwait(semid_t id, u_int msec, u_int *delta, int error)
784 struct timespec start, end;
786 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
787 fail_errno("clock_gettime(CLOCK_REALTIME)");
790 end.tv_sec = msec / 1000;
791 end.tv_nsec = msec % 1000 * 1000000;
792 timespecadd(&end, &start);
793 if (ksem_timedwait(id, &end) < 0) {
794 if (errno != error) {
795 fail_errno("ksem_timedwait");
798 } else if (error != 0) {
799 fail_err("ksem_timedwait() didn't fail");
802 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
803 fail_errno("clock_gettime(CLOCK_REALTIME)");
806 timespecsub(&end, &start);
807 *delta = end.tv_nsec / 1000000;
808 *delta += end.tv_sec * 1000;
813 unlocked_timedwait(void)
818 if (ksem_init(&id, 1) < 0) {
819 fail_errno("ksem_init");
823 /* This should succeed right away and set the value to 0. */
824 if (timedwait(id, 5000, &elapsed, 0) < 0) {
828 if (!ELAPSED(elapsed, 0)) {
829 fail_err("ksem_timedwait() of unlocked sem took %ums", elapsed);
833 if (checkvalue(id, 0) < 0) {
838 if (ksem_destroy(id) < 0) {
839 fail_errno("ksem_destroy");
844 TEST(unlocked_timedwait, "unlocked timedwait");
847 expired_timedwait(void)
852 if (ksem_init(&id, 0) < 0) {
853 fail_errno("ksem_init");
857 /* This should fail with a timeout and leave the value at 0. */
858 if (timedwait(id, 2500, &elapsed, ETIMEDOUT) < 0) {
862 if (!ELAPSED(elapsed, 2500)) {
864 "ksem_timedwait() of locked sem took %ums instead of 2500ms",
869 if (checkvalue(id, 0) < 0) {
874 if (ksem_destroy(id) < 0) {
875 fail_errno("ksem_destroy");
880 TEST(expired_timedwait, "locked timedwait timeout");
883 locked_timedwait(void)
888 if (ksem_init(&id, 0) < 0) {
889 fail_errno("ksem_init");
894 * Schedule a post to trigger after 1000 ms. The subsequent
895 * timedwait should succeed after 1000 ms as a result w/o
898 if (schedule_post(id, 1000) < 0) {
902 if (timedwait(id, 2000, &elapsed, 0) < 0) {
907 if (!ELAPSED(elapsed, 1000)) {
909 "ksem_timedwait() with delayed post took %ums instead of 1000ms",
915 if (check_alarm(0) < 0) {
920 if (ksem_destroy(id) < 0) {
921 fail_errno("ksem_destroy");
926 TEST(locked_timedwait, "locked timedwait");
929 testwait(semid_t id, u_int *delta)
931 struct timespec start, end;
933 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
934 fail_errno("clock_gettime(CLOCK_REALTIME)");
937 if (ksem_wait(id) < 0) {
938 fail_errno("ksem_wait");
941 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
942 fail_errno("clock_gettime(CLOCK_REALTIME)");
945 timespecsub(&end, &start);
946 *delta = end.tv_nsec / 1000000;
947 *delta += end.tv_sec * 1000;
957 if (ksem_init(&id, 1) < 0) {
958 fail_errno("ksem_init");
962 /* This should succeed right away and set the value to 0. */
963 if (testwait(id, &elapsed) < 0) {
967 if (!ELAPSED(elapsed, 0)) {
968 fail_err("ksem_wait() of unlocked sem took %ums", elapsed);
972 if (checkvalue(id, 0) < 0) {
977 if (ksem_destroy(id) < 0) {
978 fail_errno("ksem_destroy");
983 TEST(unlocked_wait, "unlocked wait");
991 if (ksem_init(&id, 0) < 0) {
992 fail_errno("ksem_init");
997 * Schedule a post to trigger after 1000 ms. The subsequent
998 * wait should succeed after 1000 ms as a result.
1000 if (schedule_post(id, 1000) < 0) {
1004 if (testwait(id, &elapsed) < 0) {
1009 if (!ELAPSED(elapsed, 1000)) {
1011 "ksem_wait() with delayed post took %ums instead of 1000ms",
1017 if (check_alarm(0) < 0) {
1022 if (ksem_destroy(id) < 0) {
1023 fail_errno("ksem_destroy");
1028 TEST(locked_wait, "locked wait");
1031 * Fork off a child process. The child will open the semaphore via
1032 * the same name. The child will then block on the semaphore waiting
1033 * for the parent to post it.
1036 wait_twoproc_child(void *arg)
1040 if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0)
1041 return (CSTAT(1, errno));
1042 if (ksem_wait(id) < 0)
1043 return (CSTAT(2, errno));
1044 if (ksem_close(id) < 0)
1045 return (CSTAT(3, errno));
1046 return (CSTAT(0, 0));
1050 wait_twoproc_test(void)
1055 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 0)) {
1056 fail_errno("ksem_open");
1060 if (schedule_post(id, 500) < 0) {
1062 ksem_unlink(TEST_PATH);
1066 if (child_worker(wait_twoproc_child, NULL, &stat) < 0) {
1069 ksem_unlink(TEST_PATH);
1073 errno = CSTAT_ERROR(stat);
1074 switch (CSTAT_CLASS(stat)) {
1079 fail_errno("child ksem_open()");
1082 fail_errno("child ksem_wait()");
1085 fail_errno("child ksem_close()");
1088 fail_err("bad child state %#x", stat);
1094 ksem_unlink(TEST_PATH);
1096 TEST(wait_twoproc_test, "two proc wait");
1104 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1105 fail_errno("ksem_init");
1108 if (ksem_getvalue(id, &val) < 0) {
1109 fail_errno("ksem_getvalue");
1113 if (val != SEM_VALUE_MAX) {
1114 fail_err("value %d != SEM_VALUE_MAX");
1119 fail_err("value < 0");
1123 if (ksem_destroy(id) < 0) {
1124 fail_errno("ksem_destroy");
1129 TEST(maxvalue_test, "get value of SEM_VALUE_MAX semaphore");
1132 maxvalue_post_test(void)
1136 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1137 fail_errno("ksem_init");
1141 ksem_post_should_fail(id, EOVERFLOW);
1145 TEST(maxvalue_post_test, "post SEM_VALUE_MAX semaphore");
1148 busy_destroy_test(void)
1150 char errbuf[_POSIX2_LINE_MAX];
1151 struct kinfo_proc *kp;
1157 kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf);
1159 fail_err("kvm_openfiles: %s", errbuf);
1163 if (ksem_init(&id, 0) < 0) {
1164 fail_errno("ksem_init");
1184 * Wait for the child process to block on the semaphore. This
1188 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count);
1190 fail_err("kvm_getprocs: %s", kvm_geterr(kd));
1195 if (kp->ki_stat == SSLEEP &&
1196 (strcmp(kp->ki_wmesg, "sem") == 0 ||
1197 strcmp(kp->ki_wmesg, "ksem") == 0))
1203 ksem_destroy_should_fail(id, EBUSY);
1207 waitpid(pid, NULL, 0);
1210 TEST(busy_destroy_test, "destroy unnamed semaphore with waiter");
1213 exhaust_unnamed_child(void *arg)
1218 max = (intptr_t)arg;
1219 for (i = 0; i < max + 1; i++) {
1220 if (ksem_init(&id, 1) < 0) {
1221 if (errno == ENOSPC)
1222 return (CSTAT(0, 0));
1223 return (CSTAT(1, errno));
1226 return (CSTAT(2, 0));
1230 exhaust_unnamed_sems(void)
1233 int nsems_max, stat;
1235 len = sizeof(nsems_max);
1236 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1238 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1242 if (child_worker(exhaust_unnamed_child, (void *)(uintptr_t)nsems_max,
1245 errno = CSTAT_ERROR(stat);
1246 switch (CSTAT_CLASS(stat)) {
1251 fail_errno("ksem_init");
1254 fail_err("Limit of %d semaphores not enforced", nsems_max);
1257 fail_err("bad child state %#x", stat);
1261 TEST(exhaust_unnamed_sems, "exhaust unnamed semaphores (1)");
1264 exhaust_named_child(void *arg)
1270 max = (intptr_t)arg;
1271 for (i = 0; i < max + 1; i++) {
1272 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1273 if (ksem_open(&id, buffer, O_CREAT, 0777, 1) < 0) {
1274 if (errno == ENOSPC || errno == EMFILE ||
1276 return (CSTAT(0, 0));
1277 return (CSTAT(1, errno));
1280 return (CSTAT(2, errno));
1284 exhaust_named_sems(void)
1288 int i, nsems_max, stat;
1290 len = sizeof(nsems_max);
1291 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1293 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1297 if (child_worker(exhaust_named_child, (void *)(uintptr_t)nsems_max,
1300 errno = CSTAT_ERROR(stat);
1301 switch (CSTAT_CLASS(stat)) {
1306 fail_errno("ksem_open");
1309 fail_err("Limit of %d semaphores not enforced", nsems_max);
1312 fail_err("bad child state %#x", stat);
1316 /* Cleanup any semaphores created by the child. */
1317 for (i = 0; i < nsems_max + 1; i++) {
1318 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1319 ksem_unlink(buffer);
1322 TEST(exhaust_named_sems, "exhaust named semaphores (1)");
1325 fdlimit_set(void *arg)
1330 max = (intptr_t)arg;
1331 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1332 return (CSTAT(3, errno));
1333 rlim.rlim_cur = max;
1334 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
1335 return (CSTAT(4, errno));
1340 fdlimit_unnamed_child(void *arg)
1344 stat = fdlimit_set(arg);
1346 stat = exhaust_unnamed_child(arg);
1351 fdlimit_unnamed_sems(void)
1353 int nsems_max, stat;
1356 if (child_worker(fdlimit_unnamed_child, (void *)(uintptr_t)nsems_max,
1359 errno = CSTAT_ERROR(stat);
1360 switch (CSTAT_CLASS(stat)) {
1365 fail_errno("ksem_init");
1368 fail_err("Limit of %d semaphores not enforced", nsems_max);
1371 fail_errno("getrlimit");
1374 fail_errno("getrlimit");
1377 fail_err("bad child state %#x", stat);
1381 TEST(fdlimit_unnamed_sems, "exhaust unnamed semaphores (2)");
1384 fdlimit_named_child(void *arg)
1388 stat = fdlimit_set(arg);
1390 stat = exhaust_named_child(arg);
1395 fdlimit_named_sems(void)
1398 int i, nsems_max, stat;
1401 if (child_worker(fdlimit_named_child, (void *)(uintptr_t)nsems_max,
1404 errno = CSTAT_ERROR(stat);
1405 switch (CSTAT_CLASS(stat)) {
1410 fail_errno("ksem_open");
1413 fail_err("Limit of %d semaphores not enforced", nsems_max);
1416 fail_errno("getrlimit");
1419 fail_errno("getrlimit");
1422 fail_err("bad child state %#x", stat);
1426 /* Cleanup any semaphores created by the child. */
1427 for (i = 0; i < nsems_max + 1; i++) {
1428 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1429 ksem_unlink(buffer);
1432 TEST(fdlimit_named_sems, "exhaust named semaphores (2)");
1435 main(int argc, char *argv[])
1438 signal(SIGSYS, SIG_IGN);