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/param.h>
34 #include <sys/queue.h>
35 #include <sys/_semaphore.h>
36 #include <sys/sysctl.h>
45 #include <semaphore.h>
55 #define TEST_PATH "/tmp/posixsem_regression_test"
57 #define ELAPSED(elapsed, limit) (abs((elapsed) - (limit)) < 100)
59 /* Macros for passing child status to parent over a pipe. */
60 #define CSTAT(class, error) ((class) << 16 | (error))
61 #define CSTAT_CLASS(stat) ((stat) >> 16)
62 #define CSTAT_ERROR(stat) ((stat) & 0xffff)
65 * Helper routine for tests that use a child process. This routine
66 * creates a pipe and forks a child process. The child process runs
67 * the 'func' routine which returns a status integer. The status
68 * integer gets written over the pipe to the parent and returned in
69 * '*stat'. If there is an error in pipe(), fork(), or wait() this
70 * returns -1 and fails the test.
73 child_worker(int (*func)(void *arg), void *arg, int *stat)
94 write(pfd[1], &cstat, sizeof(cstat));
98 if (read(pfd[0], stat, sizeof(*stat)) < 0) {
99 fail_errno("read(pipe)");
104 if (waitpid(pid, NULL, 0) < 0) {
116 * Attempt a ksem_open() that should fail with an expected error of
120 ksem_open_should_fail(const char *path, int flags, mode_t mode, unsigned int
125 if (ksem_open(&id, path, flags, mode, value) >= 0) {
126 fail_err("ksem_open() didn't fail");
130 if (errno != error) {
131 fail_errno("ksem_open");
138 * Attempt a ksem_unlink() that should fail with an expected error of
142 ksem_unlink_should_fail(const char *path, int error)
145 if (ksem_unlink(path) >= 0) {
146 fail_err("ksem_unlink() didn't fail");
149 if (errno != error) {
150 fail_errno("ksem_unlink");
157 * Attempt a ksem_close() that should fail with an expected error of
161 ksem_close_should_fail(semid_t id, int error)
164 if (ksem_close(id) >= 0) {
165 fail_err("ksem_close() didn't fail");
168 if (errno != error) {
169 fail_errno("ksem_close");
176 * Attempt a ksem_init() that should fail with an expected error of
180 ksem_init_should_fail(unsigned int value, int error)
184 if (ksem_init(&id, value) >= 0) {
185 fail_err("ksem_init() didn't fail");
189 if (errno != error) {
190 fail_errno("ksem_init");
197 * Attempt a ksem_destroy() that should fail with an expected error of
201 ksem_destroy_should_fail(semid_t id, int error)
204 if (ksem_destroy(id) >= 0) {
205 fail_err("ksem_destroy() didn't fail");
208 if (errno != error) {
209 fail_errno("ksem_destroy");
216 * Attempt a ksem_post() that should fail with an expected error of
220 ksem_post_should_fail(semid_t id, int error)
223 if (ksem_post(id) >= 0) {
224 fail_err("ksem_post() didn't fail");
227 if (errno != error) {
228 fail_errno("ksem_post");
235 open_after_unlink(void)
239 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
240 fail_errno("ksem_open(1)");
245 if (ksem_unlink(TEST_PATH) < 0) {
246 fail_errno("ksem_unlink");
250 ksem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT);
252 TEST(open_after_unlink, "open after unlink");
255 open_invalid_path(void)
258 ksem_open_should_fail("blah", 0, 0777, 1, EINVAL);
260 TEST(open_invalid_path, "open invalid path");
263 open_extra_flags(void)
266 ksem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL);
268 TEST(open_extra_flags, "open with extra flags");
274 (void)ksem_unlink(TEST_PATH);
276 ksem_open_should_fail(TEST_PATH, O_CREAT, 0777, UINT_MAX, EINVAL);
278 TEST(open_bad_value, "open with invalid initial value");
281 open_bad_path_pointer(void)
284 ksem_open_should_fail((char *)1024, O_RDONLY, 0777, 1, EFAULT);
286 TEST(open_bad_path_pointer, "open bad path pointer");
289 open_path_too_long(void)
293 page = malloc(MAXPATHLEN + 1);
294 memset(page, 'a', MAXPATHLEN);
295 page[MAXPATHLEN] = '\0';
296 ksem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG);
299 TEST(open_path_too_long, "open pathname too long");
302 open_nonexisting_semaphore(void)
305 ksem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT);
307 TEST(open_nonexisting_semaphore, "open nonexistent semaphore");
310 exclusive_create_existing_semaphore(void)
314 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
315 fail_errno("ksem_open(O_CREAT)");
320 ksem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST);
322 ksem_unlink(TEST_PATH);
324 TEST(exclusive_create_existing_semaphore, "O_EXCL of existing semaphore");
330 ksem_init_should_fail(UINT_MAX, EINVAL);
332 TEST(init_bad_value, "init with invalid initial value");
335 unlink_bad_path_pointer(void)
338 ksem_unlink_should_fail((char *)1024, EFAULT);
340 TEST(unlink_bad_path_pointer, "unlink bad path pointer");
343 unlink_path_too_long(void)
347 page = malloc(MAXPATHLEN + 1);
348 memset(page, 'a', MAXPATHLEN);
349 page[MAXPATHLEN] = '\0';
350 ksem_unlink_should_fail(page, ENAMETOOLONG);
353 TEST(unlink_path_too_long, "unlink pathname too long");
356 destroy_named_semaphore(void)
360 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
361 fail_errno("ksem_open(O_CREAT)");
365 ksem_destroy_should_fail(id, EINVAL);
368 ksem_unlink(TEST_PATH);
370 TEST(destroy_named_semaphore, "destroy named semaphore");
373 close_unnamed_semaphore(void)
377 if (ksem_init(&id, 1) < 0) {
378 fail_errno("ksem_init");
382 ksem_close_should_fail(id, EINVAL);
386 TEST(close_unnamed_semaphore, "close unnamed semaphore");
389 destroy_invalid_fd(void)
392 ksem_destroy_should_fail(STDERR_FILENO, EINVAL);
394 TEST(destroy_invalid_fd, "destroy non-semaphore file descriptor");
397 close_invalid_fd(void)
400 ksem_close_should_fail(STDERR_FILENO, EINVAL);
402 TEST(close_invalid_fd, "close non-semaphore file descriptor");
405 create_unnamed_semaphore(void)
409 if (ksem_init(&id, 1) < 0) {
410 fail_errno("ksem_init");
414 if (ksem_destroy(id) < 0) {
415 fail_errno("ksem_destroy");
420 TEST(create_unnamed_semaphore, "create unnamed semaphore");
423 open_named_semaphore(void)
427 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
428 fail_errno("ksem_open(O_CREAT)");
432 if (ksem_close(id) < 0) {
433 fail_errno("ksem_close");
437 if (ksem_unlink(TEST_PATH) < 0) {
438 fail_errno("ksem_unlink");
443 TEST(open_named_semaphore, "create named semaphore");
446 getvalue_invalid_semaphore(void)
450 if (ksem_getvalue(STDERR_FILENO, &val) >= 0) {
451 fail_err("ksem_getvalue() didn't fail");
454 if (errno != EINVAL) {
455 fail_errno("ksem_getvalue");
460 TEST(getvalue_invalid_semaphore, "get value of invalid semaphore");
463 post_invalid_semaphore(void)
466 ksem_post_should_fail(STDERR_FILENO, EINVAL);
468 TEST(post_invalid_semaphore, "post of invalid semaphore");
471 wait_invalid_semaphore(void)
474 if (ksem_wait(STDERR_FILENO) >= 0) {
475 fail_err("ksem_wait() didn't fail");
478 if (errno != EINVAL) {
479 fail_errno("ksem_wait");
484 TEST(wait_invalid_semaphore, "wait for invalid semaphore");
487 trywait_invalid_semaphore(void)
490 if (ksem_trywait(STDERR_FILENO) >= 0) {
491 fail_err("ksem_trywait() didn't fail");
494 if (errno != EINVAL) {
495 fail_errno("ksem_trywait");
500 TEST(trywait_invalid_semaphore, "try wait for invalid semaphore");
503 timedwait_invalid_semaphore(void)
506 if (ksem_timedwait(STDERR_FILENO, NULL) >= 0) {
507 fail_err("ksem_timedwait() didn't fail");
510 if (errno != EINVAL) {
511 fail_errno("ksem_timedwait");
516 TEST(timedwait_invalid_semaphore, "timed wait for invalid semaphore");
519 checkvalue(semid_t id, int expected)
523 if (ksem_getvalue(id, &val) < 0) {
524 fail_errno("ksem_getvalue");
527 if (val != expected) {
528 fail_err("sem value should be %d instead of %d", expected, val);
539 if (ksem_init(&id, 1) < 0) {
540 fail_errno("ksem_init");
543 if (checkvalue(id, 1) < 0) {
547 if (ksem_post(id) < 0) {
548 fail_errno("ksem_post");
552 if (checkvalue(id, 2) < 0) {
556 if (ksem_destroy(id) < 0) {
557 fail_errno("ksem_destroy");
562 TEST(post_test, "simple post");
565 use_after_unlink_test(void)
570 * Create named semaphore with value of 1 and then unlink it
571 * while still retaining the initial reference.
573 if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) {
574 fail_errno("ksem_open(O_CREAT | O_EXCL)");
577 if (ksem_unlink(TEST_PATH) < 0) {
578 fail_errno("ksem_unlink");
582 if (checkvalue(id, 1) < 0) {
587 /* Post the semaphore to set its value to 2. */
588 if (ksem_post(id) < 0) {
589 fail_errno("ksem_post");
593 if (checkvalue(id, 2) < 0) {
598 /* Wait on the semaphore which should set its value to 1. */
599 if (ksem_wait(id) < 0) {
600 fail_errno("ksem_wait");
604 if (checkvalue(id, 1) < 0) {
609 if (ksem_close(id) < 0) {
610 fail_errno("ksem_close");
615 TEST(use_after_unlink_test, "use named semaphore after unlink");
618 unlocked_trywait(void)
622 if (ksem_init(&id, 1) < 0) {
623 fail_errno("ksem_init");
627 /* This should succeed and decrement the value to 0. */
628 if (ksem_trywait(id) < 0) {
629 fail_errno("ksem_trywait()");
633 if (checkvalue(id, 0) < 0) {
638 if (ksem_destroy(id) < 0) {
639 fail_errno("ksem_destroy");
644 TEST(unlocked_trywait, "unlocked trywait");
651 if (ksem_init(&id, 0) < 0) {
652 fail_errno("ksem_init");
656 /* This should fail with EAGAIN and leave the value at 0. */
657 if (ksem_trywait(id) >= 0) {
658 fail_err("ksem_trywait() didn't fail");
662 if (errno != EAGAIN) {
663 fail_errno("wrong error from ksem_trywait()");
667 if (checkvalue(id, 0) < 0) {
672 if (ksem_destroy(id) < 0) {
673 fail_errno("ksem_destroy");
678 TEST(locked_trywait, "locked trywait");
681 * Use a timer to post a specific semaphore after a timeout. A timer
682 * is scheduled via schedule_post(). check_alarm() must be called
683 * afterwards to clean up and check for errors.
685 static semid_t alarm_id = -1;
686 static int alarm_errno;
687 static int alarm_handler_installed;
690 alarm_handler(int signo)
693 if (ksem_post(alarm_id) < 0)
698 check_alarm(int just_clear)
702 bzero(&it, sizeof(it));
704 setitimer(ITIMER_REAL, &it, NULL);
709 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
710 fail_errno("setitimer");
713 if (alarm_errno != 0 && !just_clear) {
715 fail_errno("ksem_post() (via timeout)");
725 schedule_post(semid_t id, u_int msec)
729 if (!alarm_handler_installed) {
730 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
731 fail_errno("signal(SIGALRM)");
734 alarm_handler_installed = 1;
736 if (alarm_id != -1) {
737 fail_err("ksem_post() already scheduled");
741 bzero(&it, sizeof(it));
742 it.it_value.tv_sec = msec / 1000;
743 it.it_value.tv_usec = (msec % 1000) * 1000;
744 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
745 fail_errno("setitimer");
752 timedwait(semid_t id, u_int msec, u_int *delta, int error)
754 struct timespec start, end;
756 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
757 fail_errno("clock_gettime(CLOCK_REALTIME)");
760 end.tv_sec = msec / 1000;
761 end.tv_nsec = msec % 1000 * 1000000;
762 timespecadd(&end, &start, &end);
763 if (ksem_timedwait(id, &end) < 0) {
764 if (errno != error) {
765 fail_errno("ksem_timedwait");
768 } else if (error != 0) {
769 fail_err("ksem_timedwait() didn't fail");
772 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
773 fail_errno("clock_gettime(CLOCK_REALTIME)");
776 timespecsub(&end, &start, &end);
777 *delta = end.tv_nsec / 1000000;
778 *delta += end.tv_sec * 1000;
783 unlocked_timedwait(void)
788 if (ksem_init(&id, 1) < 0) {
789 fail_errno("ksem_init");
793 /* This should succeed right away and set the value to 0. */
794 if (timedwait(id, 5000, &elapsed, 0) < 0) {
798 if (!ELAPSED(elapsed, 0)) {
799 fail_err("ksem_timedwait() of unlocked sem took %ums", elapsed);
803 if (checkvalue(id, 0) < 0) {
808 if (ksem_destroy(id) < 0) {
809 fail_errno("ksem_destroy");
814 TEST(unlocked_timedwait, "unlocked timedwait");
817 expired_timedwait(void)
822 if (ksem_init(&id, 0) < 0) {
823 fail_errno("ksem_init");
827 /* This should fail with a timeout and leave the value at 0. */
828 if (timedwait(id, 2500, &elapsed, ETIMEDOUT) < 0) {
832 if (!ELAPSED(elapsed, 2500)) {
834 "ksem_timedwait() of locked sem took %ums instead of 2500ms",
839 if (checkvalue(id, 0) < 0) {
844 if (ksem_destroy(id) < 0) {
845 fail_errno("ksem_destroy");
850 TEST(expired_timedwait, "locked timedwait timeout");
853 locked_timedwait(void)
858 if (ksem_init(&id, 0) < 0) {
859 fail_errno("ksem_init");
864 * Schedule a post to trigger after 1000 ms. The subsequent
865 * timedwait should succeed after 1000 ms as a result w/o
868 if (schedule_post(id, 1000) < 0) {
872 if (timedwait(id, 2000, &elapsed, 0) < 0) {
877 if (!ELAPSED(elapsed, 1000)) {
879 "ksem_timedwait() with delayed post took %ums instead of 1000ms",
885 if (check_alarm(0) < 0) {
890 if (ksem_destroy(id) < 0) {
891 fail_errno("ksem_destroy");
896 TEST(locked_timedwait, "locked timedwait");
899 testwait(semid_t id, u_int *delta)
901 struct timespec start, end;
903 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
904 fail_errno("clock_gettime(CLOCK_REALTIME)");
907 if (ksem_wait(id) < 0) {
908 fail_errno("ksem_wait");
911 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
912 fail_errno("clock_gettime(CLOCK_REALTIME)");
915 timespecsub(&end, &start, &end);
916 *delta = end.tv_nsec / 1000000;
917 *delta += end.tv_sec * 1000;
927 if (ksem_init(&id, 1) < 0) {
928 fail_errno("ksem_init");
932 /* This should succeed right away and set the value to 0. */
933 if (testwait(id, &elapsed) < 0) {
937 if (!ELAPSED(elapsed, 0)) {
938 fail_err("ksem_wait() of unlocked sem took %ums", elapsed);
942 if (checkvalue(id, 0) < 0) {
947 if (ksem_destroy(id) < 0) {
948 fail_errno("ksem_destroy");
953 TEST(unlocked_wait, "unlocked wait");
961 if (ksem_init(&id, 0) < 0) {
962 fail_errno("ksem_init");
967 * Schedule a post to trigger after 1000 ms. The subsequent
968 * wait should succeed after 1000 ms as a result.
970 if (schedule_post(id, 1000) < 0) {
974 if (testwait(id, &elapsed) < 0) {
979 if (!ELAPSED(elapsed, 1000)) {
981 "ksem_wait() with delayed post took %ums instead of 1000ms",
987 if (check_alarm(0) < 0) {
992 if (ksem_destroy(id) < 0) {
993 fail_errno("ksem_destroy");
998 TEST(locked_wait, "locked wait");
1001 * Fork off a child process. The child will open the semaphore via
1002 * the same name. The child will then block on the semaphore waiting
1003 * for the parent to post it.
1006 wait_twoproc_child(void *arg)
1010 if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0)
1011 return (CSTAT(1, errno));
1012 if (ksem_wait(id) < 0)
1013 return (CSTAT(2, errno));
1014 if (ksem_close(id) < 0)
1015 return (CSTAT(3, errno));
1016 return (CSTAT(0, 0));
1020 wait_twoproc_test(void)
1025 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 0)) {
1026 fail_errno("ksem_open");
1030 if (schedule_post(id, 500) < 0) {
1032 ksem_unlink(TEST_PATH);
1036 if (child_worker(wait_twoproc_child, NULL, &stat) < 0) {
1039 ksem_unlink(TEST_PATH);
1043 errno = CSTAT_ERROR(stat);
1044 switch (CSTAT_CLASS(stat)) {
1049 fail_errno("child ksem_open()");
1052 fail_errno("child ksem_wait()");
1055 fail_errno("child ksem_close()");
1058 fail_err("bad child state %#x", stat);
1064 ksem_unlink(TEST_PATH);
1066 TEST(wait_twoproc_test, "two proc wait");
1074 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1075 fail_errno("ksem_init");
1078 if (ksem_getvalue(id, &val) < 0) {
1079 fail_errno("ksem_getvalue");
1083 if (val != SEM_VALUE_MAX) {
1084 fail_err("value %d != SEM_VALUE_MAX");
1089 fail_err("value < 0");
1093 if (ksem_destroy(id) < 0) {
1094 fail_errno("ksem_destroy");
1099 TEST(maxvalue_test, "get value of SEM_VALUE_MAX semaphore");
1102 maxvalue_post_test(void)
1106 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1107 fail_errno("ksem_init");
1111 ksem_post_should_fail(id, EOVERFLOW);
1115 TEST(maxvalue_post_test, "post SEM_VALUE_MAX semaphore");
1118 busy_destroy_test(void)
1120 char errbuf[_POSIX2_LINE_MAX];
1121 struct kinfo_proc *kp;
1127 kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf);
1129 fail_err("kvm_openfiles: %s", errbuf);
1133 if (ksem_init(&id, 0) < 0) {
1134 fail_errno("ksem_init");
1154 * Wait for the child process to block on the semaphore. This
1158 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count);
1160 fail_err("kvm_getprocs: %s", kvm_geterr(kd));
1165 if (kp->ki_stat == SSLEEP &&
1166 (strcmp(kp->ki_wmesg, "sem") == 0 ||
1167 strcmp(kp->ki_wmesg, "ksem") == 0))
1173 ksem_destroy_should_fail(id, EBUSY);
1177 waitpid(pid, NULL, 0);
1180 TEST(busy_destroy_test, "destroy unnamed semaphore with waiter");
1183 exhaust_unnamed_child(void *arg)
1188 max = (intptr_t)arg;
1189 for (i = 0; i < max + 1; i++) {
1190 if (ksem_init(&id, 1) < 0) {
1191 if (errno == ENOSPC)
1192 return (CSTAT(0, 0));
1193 return (CSTAT(1, errno));
1196 return (CSTAT(2, 0));
1200 exhaust_unnamed_sems(void)
1203 int nsems_max, stat;
1205 len = sizeof(nsems_max);
1206 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1208 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1212 if (child_worker(exhaust_unnamed_child, (void *)(uintptr_t)nsems_max,
1215 errno = CSTAT_ERROR(stat);
1216 switch (CSTAT_CLASS(stat)) {
1221 fail_errno("ksem_init");
1224 fail_err("Limit of %d semaphores not enforced", nsems_max);
1227 fail_err("bad child state %#x", stat);
1231 TEST(exhaust_unnamed_sems, "exhaust unnamed semaphores (1)");
1234 exhaust_named_child(void *arg)
1240 max = (intptr_t)arg;
1241 for (i = 0; i < max + 1; i++) {
1242 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1243 if (ksem_open(&id, buffer, O_CREAT, 0777, 1) < 0) {
1244 if (errno == ENOSPC || errno == EMFILE ||
1246 return (CSTAT(0, 0));
1247 return (CSTAT(1, errno));
1250 return (CSTAT(2, errno));
1254 exhaust_named_sems(void)
1258 int i, nsems_max, stat;
1260 len = sizeof(nsems_max);
1261 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1263 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1267 if (child_worker(exhaust_named_child, (void *)(uintptr_t)nsems_max,
1270 errno = CSTAT_ERROR(stat);
1271 switch (CSTAT_CLASS(stat)) {
1276 fail_errno("ksem_open");
1279 fail_err("Limit of %d semaphores not enforced", nsems_max);
1282 fail_err("bad child state %#x", stat);
1286 /* Cleanup any semaphores created by the child. */
1287 for (i = 0; i < nsems_max + 1; i++) {
1288 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1289 ksem_unlink(buffer);
1292 TEST(exhaust_named_sems, "exhaust named semaphores (1)");
1295 fdlimit_set(void *arg)
1300 max = (intptr_t)arg;
1301 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1302 return (CSTAT(3, errno));
1303 rlim.rlim_cur = max;
1304 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
1305 return (CSTAT(4, errno));
1310 fdlimit_unnamed_child(void *arg)
1314 stat = fdlimit_set(arg);
1316 stat = exhaust_unnamed_child(arg);
1321 fdlimit_unnamed_sems(void)
1323 int nsems_max, stat;
1326 if (child_worker(fdlimit_unnamed_child, (void *)(uintptr_t)nsems_max,
1329 errno = CSTAT_ERROR(stat);
1330 switch (CSTAT_CLASS(stat)) {
1335 fail_errno("ksem_init");
1338 fail_err("Limit of %d semaphores not enforced", nsems_max);
1341 fail_errno("getrlimit");
1344 fail_errno("getrlimit");
1347 fail_err("bad child state %#x", stat);
1351 TEST(fdlimit_unnamed_sems, "exhaust unnamed semaphores (2)");
1354 fdlimit_named_child(void *arg)
1358 stat = fdlimit_set(arg);
1360 stat = exhaust_named_child(arg);
1365 fdlimit_named_sems(void)
1368 int i, nsems_max, stat;
1371 if (child_worker(fdlimit_named_child, (void *)(uintptr_t)nsems_max,
1374 errno = CSTAT_ERROR(stat);
1375 switch (CSTAT_CLASS(stat)) {
1380 fail_errno("ksem_open");
1383 fail_err("Limit of %d semaphores not enforced", nsems_max);
1386 fail_errno("getrlimit");
1389 fail_errno("getrlimit");
1392 fail_err("bad child state %#x", stat);
1396 /* Cleanup any semaphores created by the child. */
1397 for (i = 0; i < nsems_max + 1; i++) {
1398 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1399 ksem_unlink(buffer);
1402 TEST(fdlimit_named_sems, "exhaust named semaphores (2)");
1405 main(int argc, char *argv[])
1408 signal(SIGSYS, SIG_IGN);