2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2008 Yahoo!, Inc.
6 * Written by: John Baldwin <jhb@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/_semaphore.h>
39 #include <sys/sysctl.h>
48 #include <semaphore.h>
58 #define TEST_PATH "/tmp/posixsem_regression_test"
60 #define ELAPSED(elapsed, limit) (abs((elapsed) - (limit)) < 100)
62 /* Macros for passing child status to parent over a pipe. */
63 #define CSTAT(class, error) ((class) << 16 | (error))
64 #define CSTAT_CLASS(stat) ((stat) >> 16)
65 #define CSTAT_ERROR(stat) ((stat) & 0xffff)
68 * Helper routine for tests that use a child process. This routine
69 * creates a pipe and forks a child process. The child process runs
70 * the 'func' routine which returns a status integer. The status
71 * integer gets written over the pipe to the parent and returned in
72 * '*stat'. If there is an error in pipe(), fork(), or wait() this
73 * returns -1 and fails the test.
76 child_worker(int (*func)(void *arg), void *arg, int *stat)
97 write(pfd[1], &cstat, sizeof(cstat));
101 if (read(pfd[0], stat, sizeof(*stat)) < 0) {
102 fail_errno("read(pipe)");
107 if (waitpid(pid, NULL, 0) < 0) {
119 * Attempt a ksem_open() that should fail with an expected error of
123 ksem_open_should_fail(const char *path, int flags, mode_t mode, unsigned int
128 if (ksem_open(&id, path, flags, mode, value) >= 0) {
129 fail_err("ksem_open() didn't fail");
133 if (errno != error) {
134 fail_errno("ksem_open");
141 * Attempt a ksem_unlink() that should fail with an expected error of
145 ksem_unlink_should_fail(const char *path, int error)
148 if (ksem_unlink(path) >= 0) {
149 fail_err("ksem_unlink() didn't fail");
152 if (errno != error) {
153 fail_errno("ksem_unlink");
160 * Attempt a ksem_close() that should fail with an expected error of
164 ksem_close_should_fail(semid_t id, int error)
167 if (ksem_close(id) >= 0) {
168 fail_err("ksem_close() didn't fail");
171 if (errno != error) {
172 fail_errno("ksem_close");
179 * Attempt a ksem_init() that should fail with an expected error of
183 ksem_init_should_fail(unsigned int value, int error)
187 if (ksem_init(&id, value) >= 0) {
188 fail_err("ksem_init() didn't fail");
192 if (errno != error) {
193 fail_errno("ksem_init");
200 * Attempt a ksem_destroy() that should fail with an expected error of
204 ksem_destroy_should_fail(semid_t id, int error)
207 if (ksem_destroy(id) >= 0) {
208 fail_err("ksem_destroy() didn't fail");
211 if (errno != error) {
212 fail_errno("ksem_destroy");
219 * Attempt a ksem_post() that should fail with an expected error of
223 ksem_post_should_fail(semid_t id, int error)
226 if (ksem_post(id) >= 0) {
227 fail_err("ksem_post() didn't fail");
230 if (errno != error) {
231 fail_errno("ksem_post");
238 open_after_unlink(void)
242 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
243 fail_errno("ksem_open(1)");
248 if (ksem_unlink(TEST_PATH) < 0) {
249 fail_errno("ksem_unlink");
253 ksem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT);
255 TEST(open_after_unlink, "open after unlink");
258 open_invalid_path(void)
261 ksem_open_should_fail("blah", 0, 0777, 1, EINVAL);
263 TEST(open_invalid_path, "open invalid path");
266 open_extra_flags(void)
269 ksem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL);
271 TEST(open_extra_flags, "open with extra flags");
277 (void)ksem_unlink(TEST_PATH);
279 ksem_open_should_fail(TEST_PATH, O_CREAT, 0777, UINT_MAX, EINVAL);
281 TEST(open_bad_value, "open with invalid initial value");
284 open_bad_path_pointer(void)
287 ksem_open_should_fail((char *)1024, O_RDONLY, 0777, 1, EFAULT);
289 TEST(open_bad_path_pointer, "open bad path pointer");
292 open_path_too_long(void)
296 page = malloc(MAXPATHLEN + 1);
297 memset(page, 'a', MAXPATHLEN);
298 page[MAXPATHLEN] = '\0';
299 ksem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG);
302 TEST(open_path_too_long, "open pathname too long");
305 open_nonexisting_semaphore(void)
308 ksem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT);
310 TEST(open_nonexisting_semaphore, "open nonexistent semaphore");
313 exclusive_create_existing_semaphore(void)
317 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
318 fail_errno("ksem_open(O_CREAT)");
323 ksem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST);
325 ksem_unlink(TEST_PATH);
327 TEST(exclusive_create_existing_semaphore, "O_EXCL of existing semaphore");
333 ksem_init_should_fail(UINT_MAX, EINVAL);
335 TEST(init_bad_value, "init with invalid initial value");
338 unlink_bad_path_pointer(void)
341 ksem_unlink_should_fail((char *)1024, EFAULT);
343 TEST(unlink_bad_path_pointer, "unlink bad path pointer");
346 unlink_path_too_long(void)
350 page = malloc(MAXPATHLEN + 1);
351 memset(page, 'a', MAXPATHLEN);
352 page[MAXPATHLEN] = '\0';
353 ksem_unlink_should_fail(page, ENAMETOOLONG);
356 TEST(unlink_path_too_long, "unlink pathname too long");
359 destroy_named_semaphore(void)
363 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
364 fail_errno("ksem_open(O_CREAT)");
368 ksem_destroy_should_fail(id, EINVAL);
371 ksem_unlink(TEST_PATH);
373 TEST(destroy_named_semaphore, "destroy named semaphore");
376 close_unnamed_semaphore(void)
380 if (ksem_init(&id, 1) < 0) {
381 fail_errno("ksem_init");
385 ksem_close_should_fail(id, EINVAL);
389 TEST(close_unnamed_semaphore, "close unnamed semaphore");
392 destroy_invalid_fd(void)
395 ksem_destroy_should_fail(STDERR_FILENO, EINVAL);
397 TEST(destroy_invalid_fd, "destroy non-semaphore file descriptor");
400 close_invalid_fd(void)
403 ksem_close_should_fail(STDERR_FILENO, EINVAL);
405 TEST(close_invalid_fd, "close non-semaphore file descriptor");
408 create_unnamed_semaphore(void)
412 if (ksem_init(&id, 1) < 0) {
413 fail_errno("ksem_init");
417 if (ksem_destroy(id) < 0) {
418 fail_errno("ksem_destroy");
423 TEST(create_unnamed_semaphore, "create unnamed semaphore");
426 open_named_semaphore(void)
430 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
431 fail_errno("ksem_open(O_CREAT)");
435 if (ksem_close(id) < 0) {
436 fail_errno("ksem_close");
440 if (ksem_unlink(TEST_PATH) < 0) {
441 fail_errno("ksem_unlink");
446 TEST(open_named_semaphore, "create named semaphore");
449 getvalue_invalid_semaphore(void)
453 if (ksem_getvalue(STDERR_FILENO, &val) >= 0) {
454 fail_err("ksem_getvalue() didn't fail");
457 if (errno != EINVAL) {
458 fail_errno("ksem_getvalue");
463 TEST(getvalue_invalid_semaphore, "get value of invalid semaphore");
466 post_invalid_semaphore(void)
469 ksem_post_should_fail(STDERR_FILENO, EINVAL);
471 TEST(post_invalid_semaphore, "post of invalid semaphore");
474 wait_invalid_semaphore(void)
477 if (ksem_wait(STDERR_FILENO) >= 0) {
478 fail_err("ksem_wait() didn't fail");
481 if (errno != EINVAL) {
482 fail_errno("ksem_wait");
487 TEST(wait_invalid_semaphore, "wait for invalid semaphore");
490 trywait_invalid_semaphore(void)
493 if (ksem_trywait(STDERR_FILENO) >= 0) {
494 fail_err("ksem_trywait() didn't fail");
497 if (errno != EINVAL) {
498 fail_errno("ksem_trywait");
503 TEST(trywait_invalid_semaphore, "try wait for invalid semaphore");
506 timedwait_invalid_semaphore(void)
509 if (ksem_timedwait(STDERR_FILENO, NULL) >= 0) {
510 fail_err("ksem_timedwait() didn't fail");
513 if (errno != EINVAL) {
514 fail_errno("ksem_timedwait");
519 TEST(timedwait_invalid_semaphore, "timed wait for invalid semaphore");
522 checkvalue(semid_t id, int expected)
526 if (ksem_getvalue(id, &val) < 0) {
527 fail_errno("ksem_getvalue");
530 if (val != expected) {
531 fail_err("sem value should be %d instead of %d", expected, val);
542 if (ksem_init(&id, 1) < 0) {
543 fail_errno("ksem_init");
546 if (checkvalue(id, 1) < 0) {
550 if (ksem_post(id) < 0) {
551 fail_errno("ksem_post");
555 if (checkvalue(id, 2) < 0) {
559 if (ksem_destroy(id) < 0) {
560 fail_errno("ksem_destroy");
565 TEST(post_test, "simple post");
568 use_after_unlink_test(void)
573 * Create named semaphore with value of 1 and then unlink it
574 * while still retaining the initial reference.
576 if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) {
577 fail_errno("ksem_open(O_CREAT | O_EXCL)");
580 if (ksem_unlink(TEST_PATH) < 0) {
581 fail_errno("ksem_unlink");
585 if (checkvalue(id, 1) < 0) {
590 /* Post the semaphore to set its value to 2. */
591 if (ksem_post(id) < 0) {
592 fail_errno("ksem_post");
596 if (checkvalue(id, 2) < 0) {
601 /* Wait on the semaphore which should set its value to 1. */
602 if (ksem_wait(id) < 0) {
603 fail_errno("ksem_wait");
607 if (checkvalue(id, 1) < 0) {
612 if (ksem_close(id) < 0) {
613 fail_errno("ksem_close");
618 TEST(use_after_unlink_test, "use named semaphore after unlink");
621 unlocked_trywait(void)
625 if (ksem_init(&id, 1) < 0) {
626 fail_errno("ksem_init");
630 /* This should succeed and decrement the value to 0. */
631 if (ksem_trywait(id) < 0) {
632 fail_errno("ksem_trywait()");
636 if (checkvalue(id, 0) < 0) {
641 if (ksem_destroy(id) < 0) {
642 fail_errno("ksem_destroy");
647 TEST(unlocked_trywait, "unlocked trywait");
654 if (ksem_init(&id, 0) < 0) {
655 fail_errno("ksem_init");
659 /* This should fail with EAGAIN and leave the value at 0. */
660 if (ksem_trywait(id) >= 0) {
661 fail_err("ksem_trywait() didn't fail");
665 if (errno != EAGAIN) {
666 fail_errno("wrong error from ksem_trywait()");
670 if (checkvalue(id, 0) < 0) {
675 if (ksem_destroy(id) < 0) {
676 fail_errno("ksem_destroy");
681 TEST(locked_trywait, "locked trywait");
684 * Use a timer to post a specific semaphore after a timeout. A timer
685 * is scheduled via schedule_post(). check_alarm() must be called
686 * afterwards to clean up and check for errors.
688 static semid_t alarm_id = -1;
689 static int alarm_errno;
690 static int alarm_handler_installed;
693 alarm_handler(int signo)
696 if (ksem_post(alarm_id) < 0)
701 check_alarm(int just_clear)
705 bzero(&it, sizeof(it));
707 setitimer(ITIMER_REAL, &it, NULL);
712 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
713 fail_errno("setitimer");
716 if (alarm_errno != 0 && !just_clear) {
718 fail_errno("ksem_post() (via timeout)");
728 schedule_post(semid_t id, u_int msec)
732 if (!alarm_handler_installed) {
733 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
734 fail_errno("signal(SIGALRM)");
737 alarm_handler_installed = 1;
739 if (alarm_id != -1) {
740 fail_err("ksem_post() already scheduled");
744 bzero(&it, sizeof(it));
745 it.it_value.tv_sec = msec / 1000;
746 it.it_value.tv_usec = (msec % 1000) * 1000;
747 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
748 fail_errno("setitimer");
755 timedwait(semid_t id, u_int msec, u_int *delta, int error)
757 struct timespec start, end;
759 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
760 fail_errno("clock_gettime(CLOCK_REALTIME)");
763 end.tv_sec = msec / 1000;
764 end.tv_nsec = msec % 1000 * 1000000;
765 timespecadd(&end, &start, &end);
766 if (ksem_timedwait(id, &end) < 0) {
767 if (errno != error) {
768 fail_errno("ksem_timedwait");
771 } else if (error != 0) {
772 fail_err("ksem_timedwait() didn't fail");
775 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
776 fail_errno("clock_gettime(CLOCK_REALTIME)");
779 timespecsub(&end, &start, &end);
780 *delta = end.tv_nsec / 1000000;
781 *delta += end.tv_sec * 1000;
786 unlocked_timedwait(void)
791 if (ksem_init(&id, 1) < 0) {
792 fail_errno("ksem_init");
796 /* This should succeed right away and set the value to 0. */
797 if (timedwait(id, 5000, &elapsed, 0) < 0) {
801 if (!ELAPSED(elapsed, 0)) {
802 fail_err("ksem_timedwait() of unlocked sem took %ums", elapsed);
806 if (checkvalue(id, 0) < 0) {
811 if (ksem_destroy(id) < 0) {
812 fail_errno("ksem_destroy");
817 TEST(unlocked_timedwait, "unlocked timedwait");
820 expired_timedwait(void)
825 if (ksem_init(&id, 0) < 0) {
826 fail_errno("ksem_init");
830 /* This should fail with a timeout and leave the value at 0. */
831 if (timedwait(id, 2500, &elapsed, ETIMEDOUT) < 0) {
835 if (!ELAPSED(elapsed, 2500)) {
837 "ksem_timedwait() of locked sem took %ums instead of 2500ms",
842 if (checkvalue(id, 0) < 0) {
847 if (ksem_destroy(id) < 0) {
848 fail_errno("ksem_destroy");
853 TEST(expired_timedwait, "locked timedwait timeout");
856 locked_timedwait(void)
861 if (ksem_init(&id, 0) < 0) {
862 fail_errno("ksem_init");
867 * Schedule a post to trigger after 1000 ms. The subsequent
868 * timedwait should succeed after 1000 ms as a result w/o
871 if (schedule_post(id, 1000) < 0) {
875 if (timedwait(id, 2000, &elapsed, 0) < 0) {
880 if (!ELAPSED(elapsed, 1000)) {
882 "ksem_timedwait() with delayed post took %ums instead of 1000ms",
888 if (check_alarm(0) < 0) {
893 if (ksem_destroy(id) < 0) {
894 fail_errno("ksem_destroy");
899 TEST(locked_timedwait, "locked timedwait");
902 testwait(semid_t id, u_int *delta)
904 struct timespec start, end;
906 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
907 fail_errno("clock_gettime(CLOCK_REALTIME)");
910 if (ksem_wait(id) < 0) {
911 fail_errno("ksem_wait");
914 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
915 fail_errno("clock_gettime(CLOCK_REALTIME)");
918 timespecsub(&end, &start, &end);
919 *delta = end.tv_nsec / 1000000;
920 *delta += end.tv_sec * 1000;
930 if (ksem_init(&id, 1) < 0) {
931 fail_errno("ksem_init");
935 /* This should succeed right away and set the value to 0. */
936 if (testwait(id, &elapsed) < 0) {
940 if (!ELAPSED(elapsed, 0)) {
941 fail_err("ksem_wait() of unlocked sem took %ums", elapsed);
945 if (checkvalue(id, 0) < 0) {
950 if (ksem_destroy(id) < 0) {
951 fail_errno("ksem_destroy");
956 TEST(unlocked_wait, "unlocked wait");
964 if (ksem_init(&id, 0) < 0) {
965 fail_errno("ksem_init");
970 * Schedule a post to trigger after 1000 ms. The subsequent
971 * wait should succeed after 1000 ms as a result.
973 if (schedule_post(id, 1000) < 0) {
977 if (testwait(id, &elapsed) < 0) {
982 if (!ELAPSED(elapsed, 1000)) {
984 "ksem_wait() with delayed post took %ums instead of 1000ms",
990 if (check_alarm(0) < 0) {
995 if (ksem_destroy(id) < 0) {
996 fail_errno("ksem_destroy");
1001 TEST(locked_wait, "locked wait");
1004 * Fork off a child process. The child will open the semaphore via
1005 * the same name. The child will then block on the semaphore waiting
1006 * for the parent to post it.
1009 wait_twoproc_child(void *arg)
1013 if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0)
1014 return (CSTAT(1, errno));
1015 if (ksem_wait(id) < 0)
1016 return (CSTAT(2, errno));
1017 if (ksem_close(id) < 0)
1018 return (CSTAT(3, errno));
1019 return (CSTAT(0, 0));
1023 wait_twoproc_test(void)
1028 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 0)) {
1029 fail_errno("ksem_open");
1033 if (schedule_post(id, 500) < 0) {
1035 ksem_unlink(TEST_PATH);
1039 if (child_worker(wait_twoproc_child, NULL, &stat) < 0) {
1042 ksem_unlink(TEST_PATH);
1046 errno = CSTAT_ERROR(stat);
1047 switch (CSTAT_CLASS(stat)) {
1052 fail_errno("child ksem_open()");
1055 fail_errno("child ksem_wait()");
1058 fail_errno("child ksem_close()");
1061 fail_err("bad child state %#x", stat);
1067 ksem_unlink(TEST_PATH);
1069 TEST(wait_twoproc_test, "two proc wait");
1077 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1078 fail_errno("ksem_init");
1081 if (ksem_getvalue(id, &val) < 0) {
1082 fail_errno("ksem_getvalue");
1086 if (val != SEM_VALUE_MAX) {
1087 fail_err("value %d != SEM_VALUE_MAX");
1092 fail_err("value < 0");
1096 if (ksem_destroy(id) < 0) {
1097 fail_errno("ksem_destroy");
1102 TEST(maxvalue_test, "get value of SEM_VALUE_MAX semaphore");
1105 maxvalue_post_test(void)
1109 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1110 fail_errno("ksem_init");
1114 ksem_post_should_fail(id, EOVERFLOW);
1118 TEST(maxvalue_post_test, "post SEM_VALUE_MAX semaphore");
1121 busy_destroy_test(void)
1123 char errbuf[_POSIX2_LINE_MAX];
1124 struct kinfo_proc *kp;
1130 kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf);
1132 fail_err("kvm_openfiles: %s", errbuf);
1136 if (ksem_init(&id, 0) < 0) {
1137 fail_errno("ksem_init");
1157 * Wait for the child process to block on the semaphore. This
1161 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count);
1163 fail_err("kvm_getprocs: %s", kvm_geterr(kd));
1168 if (kp->ki_stat == SSLEEP &&
1169 (strcmp(kp->ki_wmesg, "sem") == 0 ||
1170 strcmp(kp->ki_wmesg, "ksem") == 0))
1176 ksem_destroy_should_fail(id, EBUSY);
1180 waitpid(pid, NULL, 0);
1183 TEST(busy_destroy_test, "destroy unnamed semaphore with waiter");
1186 exhaust_unnamed_child(void *arg)
1191 max = (intptr_t)arg;
1192 for (i = 0; i < max + 1; i++) {
1193 if (ksem_init(&id, 1) < 0) {
1194 if (errno == ENOSPC)
1195 return (CSTAT(0, 0));
1196 return (CSTAT(1, errno));
1199 return (CSTAT(2, 0));
1203 exhaust_unnamed_sems(void)
1206 int nsems_max, stat;
1208 len = sizeof(nsems_max);
1209 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1211 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1215 if (child_worker(exhaust_unnamed_child, (void *)(uintptr_t)nsems_max,
1218 errno = CSTAT_ERROR(stat);
1219 switch (CSTAT_CLASS(stat)) {
1224 fail_errno("ksem_init");
1227 fail_err("Limit of %d semaphores not enforced", nsems_max);
1230 fail_err("bad child state %#x", stat);
1234 TEST(exhaust_unnamed_sems, "exhaust unnamed semaphores (1)");
1237 exhaust_named_child(void *arg)
1243 max = (intptr_t)arg;
1244 for (i = 0; i < max + 1; i++) {
1245 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1246 if (ksem_open(&id, buffer, O_CREAT, 0777, 1) < 0) {
1247 if (errno == ENOSPC || errno == EMFILE ||
1249 return (CSTAT(0, 0));
1250 return (CSTAT(1, errno));
1253 return (CSTAT(2, errno));
1257 exhaust_named_sems(void)
1261 int i, nsems_max, stat;
1263 len = sizeof(nsems_max);
1264 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1266 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1270 if (child_worker(exhaust_named_child, (void *)(uintptr_t)nsems_max,
1273 errno = CSTAT_ERROR(stat);
1274 switch (CSTAT_CLASS(stat)) {
1279 fail_errno("ksem_open");
1282 fail_err("Limit of %d semaphores not enforced", nsems_max);
1285 fail_err("bad child state %#x", stat);
1289 /* Cleanup any semaphores created by the child. */
1290 for (i = 0; i < nsems_max + 1; i++) {
1291 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1292 ksem_unlink(buffer);
1295 TEST(exhaust_named_sems, "exhaust named semaphores (1)");
1298 fdlimit_set(void *arg)
1303 max = (intptr_t)arg;
1304 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1305 return (CSTAT(3, errno));
1306 rlim.rlim_cur = max;
1307 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
1308 return (CSTAT(4, errno));
1313 fdlimit_unnamed_child(void *arg)
1317 stat = fdlimit_set(arg);
1319 stat = exhaust_unnamed_child(arg);
1324 fdlimit_unnamed_sems(void)
1326 int nsems_max, stat;
1329 if (child_worker(fdlimit_unnamed_child, (void *)(uintptr_t)nsems_max,
1332 errno = CSTAT_ERROR(stat);
1333 switch (CSTAT_CLASS(stat)) {
1338 fail_errno("ksem_init");
1341 fail_err("Limit of %d semaphores not enforced", nsems_max);
1344 fail_errno("getrlimit");
1347 fail_errno("getrlimit");
1350 fail_err("bad child state %#x", stat);
1354 TEST(fdlimit_unnamed_sems, "exhaust unnamed semaphores (2)");
1357 fdlimit_named_child(void *arg)
1361 stat = fdlimit_set(arg);
1363 stat = exhaust_named_child(arg);
1368 fdlimit_named_sems(void)
1371 int i, nsems_max, stat;
1374 if (child_worker(fdlimit_named_child, (void *)(uintptr_t)nsems_max,
1377 errno = CSTAT_ERROR(stat);
1378 switch (CSTAT_CLASS(stat)) {
1383 fail_errno("ksem_open");
1386 fail_err("Limit of %d semaphores not enforced", nsems_max);
1389 fail_errno("getrlimit");
1392 fail_errno("getrlimit");
1395 fail_err("bad child state %#x", stat);
1399 /* Cleanup any semaphores created by the child. */
1400 for (i = 0; i < nsems_max + 1; i++) {
1401 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1402 ksem_unlink(buffer);
1405 TEST(fdlimit_named_sems, "exhaust named semaphores (2)");
1408 main(int argc, char *argv[])
1411 signal(SIGSYS, SIG_IGN);