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 /* Cut and pasted from kernel header, bah! */
60 /* Operations on timespecs */
61 #define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0)
62 #define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec)
63 #define timespeccmp(tvp, uvp, cmp) \
64 (((tvp)->tv_sec == (uvp)->tv_sec) ? \
65 ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
66 ((tvp)->tv_sec cmp (uvp)->tv_sec))
67 #define timespecadd(vvp, uvp) \
69 (vvp)->tv_sec += (uvp)->tv_sec; \
70 (vvp)->tv_nsec += (uvp)->tv_nsec; \
71 if ((vvp)->tv_nsec >= 1000000000) { \
73 (vvp)->tv_nsec -= 1000000000; \
76 #define timespecsub(vvp, uvp) \
78 (vvp)->tv_sec -= (uvp)->tv_sec; \
79 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
80 if ((vvp)->tv_nsec < 0) { \
82 (vvp)->tv_nsec += 1000000000; \
87 #define TEST_PATH "/tmp/posixsem_regression_test"
89 #define ELAPSED(elapsed, limit) (abs((elapsed) - (limit)) < 100)
91 /* Macros for passing child status to parent over a pipe. */
92 #define CSTAT(class, error) ((class) << 16 | (error))
93 #define CSTAT_CLASS(stat) ((stat) >> 16)
94 #define CSTAT_ERROR(stat) ((stat) & 0xffff)
97 * Helper routine for tests that use a child process. This routine
98 * creates a pipe and forks a child process. The child process runs
99 * the 'func' routine which returns a status integer. The status
100 * integer gets written over the pipe to the parent and returned in
101 * '*stat'. If there is an error in pipe(), fork(), or wait() this
102 * returns -1 and fails the test.
105 child_worker(int (*func)(void *arg), void *arg, int *stat)
126 write(pfd[1], &cstat, sizeof(cstat));
130 if (read(pfd[0], stat, sizeof(*stat)) < 0) {
131 fail_errno("read(pipe)");
136 if (waitpid(pid, NULL, 0) < 0) {
148 * Attempt a ksem_open() that should fail with an expected error of
152 ksem_open_should_fail(const char *path, int flags, mode_t mode, unsigned int
157 if (ksem_open(&id, path, flags, mode, value) >= 0) {
158 fail_err("ksem_open() didn't fail");
162 if (errno != error) {
163 fail_errno("ksem_open");
170 * Attempt a ksem_unlink() that should fail with an expected error of
174 ksem_unlink_should_fail(const char *path, int error)
177 if (ksem_unlink(path) >= 0) {
178 fail_err("ksem_unlink() didn't fail");
181 if (errno != error) {
182 fail_errno("ksem_unlink");
189 * Attempt a ksem_close() that should fail with an expected error of
193 ksem_close_should_fail(semid_t id, int error)
196 if (ksem_close(id) >= 0) {
197 fail_err("ksem_close() didn't fail");
200 if (errno != error) {
201 fail_errno("ksem_close");
208 * Attempt a ksem_init() that should fail with an expected error of
212 ksem_init_should_fail(unsigned int value, int error)
216 if (ksem_init(&id, value) >= 0) {
217 fail_err("ksem_init() didn't fail");
221 if (errno != error) {
222 fail_errno("ksem_init");
229 * Attempt a ksem_destroy() that should fail with an expected error of
233 ksem_destroy_should_fail(semid_t id, int error)
236 if (ksem_destroy(id) >= 0) {
237 fail_err("ksem_destroy() didn't fail");
240 if (errno != error) {
241 fail_errno("ksem_destroy");
248 * Attempt a ksem_post() that should fail with an expected error of
252 ksem_post_should_fail(semid_t id, int error)
255 if (ksem_post(id) >= 0) {
256 fail_err("ksem_post() didn't fail");
259 if (errno != error) {
260 fail_errno("ksem_post");
267 open_after_unlink(void)
271 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
272 fail_errno("ksem_open(1)");
277 if (ksem_unlink(TEST_PATH) < 0) {
278 fail_errno("ksem_unlink");
282 ksem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT);
284 TEST(open_after_unlink, "open after unlink");
287 open_invalid_path(void)
290 ksem_open_should_fail("blah", 0, 0777, 1, EINVAL);
292 TEST(open_invalid_path, "open invalid path");
295 open_extra_flags(void)
298 ksem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL);
300 TEST(open_extra_flags, "open with extra flags");
306 (void)ksem_unlink(TEST_PATH);
308 ksem_open_should_fail(TEST_PATH, O_CREAT, 0777, UINT_MAX, EINVAL);
310 TEST(open_bad_value, "open with invalid initial value");
313 open_bad_path_pointer(void)
316 ksem_open_should_fail((char *)1024, O_RDONLY, 0777, 1, EFAULT);
318 TEST(open_bad_path_pointer, "open bad path pointer");
321 open_path_too_long(void)
325 page = malloc(MAXPATHLEN + 1);
326 memset(page, 'a', MAXPATHLEN);
327 page[MAXPATHLEN] = '\0';
328 ksem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG);
331 TEST(open_path_too_long, "open pathname too long");
334 open_nonexisting_semaphore(void)
337 ksem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT);
339 TEST(open_nonexisting_semaphore, "open nonexistent semaphore");
342 exclusive_create_existing_semaphore(void)
346 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
347 fail_errno("ksem_open(O_CREAT)");
352 ksem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST);
354 ksem_unlink(TEST_PATH);
356 TEST(exclusive_create_existing_semaphore, "O_EXCL of existing semaphore");
362 ksem_init_should_fail(UINT_MAX, EINVAL);
364 TEST(init_bad_value, "init with invalid initial value");
367 unlink_bad_path_pointer(void)
370 ksem_unlink_should_fail((char *)1024, EFAULT);
372 TEST(unlink_bad_path_pointer, "unlink bad path pointer");
375 unlink_path_too_long(void)
379 page = malloc(MAXPATHLEN + 1);
380 memset(page, 'a', MAXPATHLEN);
381 page[MAXPATHLEN] = '\0';
382 ksem_unlink_should_fail(page, ENAMETOOLONG);
385 TEST(unlink_path_too_long, "unlink pathname too long");
388 destroy_named_semaphore(void)
392 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
393 fail_errno("ksem_open(O_CREAT)");
397 ksem_destroy_should_fail(id, EINVAL);
400 ksem_unlink(TEST_PATH);
402 TEST(destroy_named_semaphore, "destroy named semaphore");
405 close_unnamed_semaphore(void)
409 if (ksem_init(&id, 1) < 0) {
410 fail_errno("ksem_init");
414 ksem_close_should_fail(id, EINVAL);
418 TEST(close_unnamed_semaphore, "close unnamed semaphore");
421 destroy_invalid_fd(void)
424 ksem_destroy_should_fail(STDERR_FILENO, EINVAL);
426 TEST(destroy_invalid_fd, "destroy non-semaphore file descriptor");
429 close_invalid_fd(void)
432 ksem_close_should_fail(STDERR_FILENO, EINVAL);
434 TEST(close_invalid_fd, "close non-semaphore file descriptor");
437 create_unnamed_semaphore(void)
441 if (ksem_init(&id, 1) < 0) {
442 fail_errno("ksem_init");
446 if (ksem_destroy(id) < 0) {
447 fail_errno("ksem_destroy");
452 TEST(create_unnamed_semaphore, "create unnamed semaphore");
455 open_named_semaphore(void)
459 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 1) < 0) {
460 fail_errno("ksem_open(O_CREAT)");
464 if (ksem_close(id) < 0) {
465 fail_errno("ksem_close");
469 if (ksem_unlink(TEST_PATH) < 0) {
470 fail_errno("ksem_unlink");
475 TEST(open_named_semaphore, "create named semaphore");
478 getvalue_invalid_semaphore(void)
482 if (ksem_getvalue(STDERR_FILENO, &val) >= 0) {
483 fail_err("ksem_getvalue() didn't fail");
486 if (errno != EINVAL) {
487 fail_errno("ksem_getvalue");
492 TEST(getvalue_invalid_semaphore, "get value of invalid semaphore");
495 post_invalid_semaphore(void)
498 ksem_post_should_fail(STDERR_FILENO, EINVAL);
500 TEST(post_invalid_semaphore, "post of invalid semaphore");
503 wait_invalid_semaphore(void)
506 if (ksem_wait(STDERR_FILENO) >= 0) {
507 fail_err("ksem_wait() didn't fail");
510 if (errno != EINVAL) {
511 fail_errno("ksem_wait");
516 TEST(wait_invalid_semaphore, "wait for invalid semaphore");
519 trywait_invalid_semaphore(void)
522 if (ksem_trywait(STDERR_FILENO) >= 0) {
523 fail_err("ksem_trywait() didn't fail");
526 if (errno != EINVAL) {
527 fail_errno("ksem_trywait");
532 TEST(trywait_invalid_semaphore, "try wait for invalid semaphore");
535 timedwait_invalid_semaphore(void)
538 if (ksem_timedwait(STDERR_FILENO, NULL) >= 0) {
539 fail_err("ksem_timedwait() didn't fail");
542 if (errno != EINVAL) {
543 fail_errno("ksem_timedwait");
548 TEST(timedwait_invalid_semaphore, "timed wait for invalid semaphore");
551 checkvalue(semid_t id, int expected)
555 if (ksem_getvalue(id, &val) < 0) {
556 fail_errno("ksem_getvalue");
559 if (val != expected) {
560 fail_err("sem value should be %d instead of %d", expected, val);
571 if (ksem_init(&id, 1) < 0) {
572 fail_errno("ksem_init");
575 if (checkvalue(id, 1) < 0) {
579 if (ksem_post(id) < 0) {
580 fail_errno("ksem_post");
584 if (checkvalue(id, 2) < 0) {
588 if (ksem_destroy(id) < 0) {
589 fail_errno("ksem_destroy");
594 TEST(post_test, "simple post");
597 use_after_unlink_test(void)
602 * Create named semaphore with value of 1 and then unlink it
603 * while still retaining the initial reference.
605 if (ksem_open(&id, TEST_PATH, O_CREAT | O_EXCL, 0777, 1) < 0) {
606 fail_errno("ksem_open(O_CREAT | O_EXCL)");
609 if (ksem_unlink(TEST_PATH) < 0) {
610 fail_errno("ksem_unlink");
614 if (checkvalue(id, 1) < 0) {
619 /* Post the semaphore to set its value to 2. */
620 if (ksem_post(id) < 0) {
621 fail_errno("ksem_post");
625 if (checkvalue(id, 2) < 0) {
630 /* Wait on the semaphore which should set its value to 1. */
631 if (ksem_wait(id) < 0) {
632 fail_errno("ksem_wait");
636 if (checkvalue(id, 1) < 0) {
641 if (ksem_close(id) < 0) {
642 fail_errno("ksem_close");
647 TEST(use_after_unlink_test, "use named semaphore after unlink");
650 unlocked_trywait(void)
654 if (ksem_init(&id, 1) < 0) {
655 fail_errno("ksem_init");
659 /* This should succeed and decrement the value to 0. */
660 if (ksem_trywait(id) < 0) {
661 fail_errno("ksem_trywait()");
665 if (checkvalue(id, 0) < 0) {
670 if (ksem_destroy(id) < 0) {
671 fail_errno("ksem_destroy");
676 TEST(unlocked_trywait, "unlocked trywait");
683 if (ksem_init(&id, 0) < 0) {
684 fail_errno("ksem_init");
688 /* This should fail with EAGAIN and leave the value at 0. */
689 if (ksem_trywait(id) >= 0) {
690 fail_err("ksem_trywait() didn't fail");
694 if (errno != EAGAIN) {
695 fail_errno("wrong error from ksem_trywait()");
699 if (checkvalue(id, 0) < 0) {
704 if (ksem_destroy(id) < 0) {
705 fail_errno("ksem_destroy");
710 TEST(locked_trywait, "locked trywait");
713 * Use a timer to post a specific semaphore after a timeout. A timer
714 * is scheduled via schedule_post(). check_alarm() must be called
715 * afterwards to clean up and check for errors.
717 static semid_t alarm_id = -1;
718 static int alarm_errno;
719 static int alarm_handler_installed;
722 alarm_handler(int signo)
725 if (ksem_post(alarm_id) < 0)
730 check_alarm(int just_clear)
734 bzero(&it, sizeof(it));
736 setitimer(ITIMER_REAL, &it, NULL);
741 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
742 fail_errno("setitimer");
745 if (alarm_errno != 0 && !just_clear) {
747 fail_errno("ksem_post() (via timeout)");
757 schedule_post(semid_t id, u_int msec)
761 if (!alarm_handler_installed) {
762 if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
763 fail_errno("signal(SIGALRM)");
766 alarm_handler_installed = 1;
768 if (alarm_id != -1) {
769 fail_err("ksem_post() already scheduled");
773 bzero(&it, sizeof(it));
774 it.it_value.tv_sec = msec / 1000;
775 it.it_value.tv_usec = (msec % 1000) * 1000;
776 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
777 fail_errno("setitimer");
784 timedwait(semid_t id, u_int msec, u_int *delta, int error)
786 struct timespec start, end;
788 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
789 fail_errno("clock_gettime(CLOCK_REALTIME)");
792 end.tv_sec = msec / 1000;
793 end.tv_nsec = msec % 1000 * 1000000;
794 timespecadd(&end, &start);
795 if (ksem_timedwait(id, &end) < 0) {
796 if (errno != error) {
797 fail_errno("ksem_timedwait");
800 } else if (error != 0) {
801 fail_err("ksem_timedwait() didn't fail");
804 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
805 fail_errno("clock_gettime(CLOCK_REALTIME)");
808 timespecsub(&end, &start);
809 *delta = end.tv_nsec / 1000000;
810 *delta += end.tv_sec * 1000;
815 unlocked_timedwait(void)
820 if (ksem_init(&id, 1) < 0) {
821 fail_errno("ksem_init");
825 /* This should succeed right away and set the value to 0. */
826 if (timedwait(id, 5000, &elapsed, 0) < 0) {
830 if (!ELAPSED(elapsed, 0)) {
831 fail_err("ksem_timedwait() of unlocked sem took %ums", elapsed);
835 if (checkvalue(id, 0) < 0) {
840 if (ksem_destroy(id) < 0) {
841 fail_errno("ksem_destroy");
846 TEST(unlocked_timedwait, "unlocked timedwait");
849 expired_timedwait(void)
854 if (ksem_init(&id, 0) < 0) {
855 fail_errno("ksem_init");
859 /* This should fail with a timeout and leave the value at 0. */
860 if (timedwait(id, 2500, &elapsed, ETIMEDOUT) < 0) {
864 if (!ELAPSED(elapsed, 2500)) {
866 "ksem_timedwait() of locked sem took %ums instead of 2500ms",
871 if (checkvalue(id, 0) < 0) {
876 if (ksem_destroy(id) < 0) {
877 fail_errno("ksem_destroy");
882 TEST(expired_timedwait, "locked timedwait timeout");
885 locked_timedwait(void)
890 if (ksem_init(&id, 0) < 0) {
891 fail_errno("ksem_init");
896 * Schedule a post to trigger after 1000 ms. The subsequent
897 * timedwait should succeed after 1000 ms as a result w/o
900 if (schedule_post(id, 1000) < 0) {
904 if (timedwait(id, 2000, &elapsed, 0) < 0) {
909 if (!ELAPSED(elapsed, 1000)) {
911 "ksem_timedwait() with delayed post took %ums instead of 1000ms",
917 if (check_alarm(0) < 0) {
922 if (ksem_destroy(id) < 0) {
923 fail_errno("ksem_destroy");
928 TEST(locked_timedwait, "locked timedwait");
931 testwait(semid_t id, u_int *delta)
933 struct timespec start, end;
935 if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
936 fail_errno("clock_gettime(CLOCK_REALTIME)");
939 if (ksem_wait(id) < 0) {
940 fail_errno("ksem_wait");
943 if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
944 fail_errno("clock_gettime(CLOCK_REALTIME)");
947 timespecsub(&end, &start);
948 *delta = end.tv_nsec / 1000000;
949 *delta += end.tv_sec * 1000;
959 if (ksem_init(&id, 1) < 0) {
960 fail_errno("ksem_init");
964 /* This should succeed right away and set the value to 0. */
965 if (testwait(id, &elapsed) < 0) {
969 if (!ELAPSED(elapsed, 0)) {
970 fail_err("ksem_wait() of unlocked sem took %ums", elapsed);
974 if (checkvalue(id, 0) < 0) {
979 if (ksem_destroy(id) < 0) {
980 fail_errno("ksem_destroy");
985 TEST(unlocked_wait, "unlocked wait");
993 if (ksem_init(&id, 0) < 0) {
994 fail_errno("ksem_init");
999 * Schedule a post to trigger after 1000 ms. The subsequent
1000 * wait should succeed after 1000 ms as a result.
1002 if (schedule_post(id, 1000) < 0) {
1006 if (testwait(id, &elapsed) < 0) {
1011 if (!ELAPSED(elapsed, 1000)) {
1013 "ksem_wait() with delayed post took %ums instead of 1000ms",
1019 if (check_alarm(0) < 0) {
1024 if (ksem_destroy(id) < 0) {
1025 fail_errno("ksem_destroy");
1030 TEST(locked_wait, "locked wait");
1033 * Fork off a child process. The child will open the semaphore via
1034 * the same name. The child will then block on the semaphore waiting
1035 * for the parent to post it.
1038 wait_twoproc_child(void *arg)
1042 if (ksem_open(&id, TEST_PATH, 0, 0, 0) < 0)
1043 return (CSTAT(1, errno));
1044 if (ksem_wait(id) < 0)
1045 return (CSTAT(2, errno));
1046 if (ksem_close(id) < 0)
1047 return (CSTAT(3, errno));
1048 return (CSTAT(0, 0));
1052 wait_twoproc_test(void)
1057 if (ksem_open(&id, TEST_PATH, O_CREAT, 0777, 0)) {
1058 fail_errno("ksem_open");
1062 if (schedule_post(id, 500) < 0) {
1064 ksem_unlink(TEST_PATH);
1068 if (child_worker(wait_twoproc_child, NULL, &stat) < 0) {
1071 ksem_unlink(TEST_PATH);
1075 errno = CSTAT_ERROR(stat);
1076 switch (CSTAT_CLASS(stat)) {
1081 fail_errno("child ksem_open()");
1084 fail_errno("child ksem_wait()");
1087 fail_errno("child ksem_close()");
1090 fail_err("bad child state %#x", stat);
1096 ksem_unlink(TEST_PATH);
1098 TEST(wait_twoproc_test, "two proc wait");
1106 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1107 fail_errno("ksem_init");
1110 if (ksem_getvalue(id, &val) < 0) {
1111 fail_errno("ksem_getvalue");
1115 if (val != SEM_VALUE_MAX) {
1116 fail_err("value %d != SEM_VALUE_MAX");
1121 fail_err("value < 0");
1125 if (ksem_destroy(id) < 0) {
1126 fail_errno("ksem_destroy");
1131 TEST(maxvalue_test, "get value of SEM_VALUE_MAX semaphore");
1134 maxvalue_post_test(void)
1138 if (ksem_init(&id, SEM_VALUE_MAX) < 0) {
1139 fail_errno("ksem_init");
1143 ksem_post_should_fail(id, EOVERFLOW);
1147 TEST(maxvalue_post_test, "post SEM_VALUE_MAX semaphore");
1150 busy_destroy_test(void)
1152 char errbuf[_POSIX2_LINE_MAX];
1153 struct kinfo_proc *kp;
1159 kd = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf);
1161 fail_err("kvm_openfiles: %s", errbuf);
1165 if (ksem_init(&id, 0) < 0) {
1166 fail_errno("ksem_init");
1186 * Wait for the child process to block on the semaphore. This
1190 kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &count);
1192 fail_err("kvm_getprocs: %s", kvm_geterr(kd));
1197 if (kp->ki_stat == SSLEEP &&
1198 (strcmp(kp->ki_wmesg, "sem") == 0 ||
1199 strcmp(kp->ki_wmesg, "ksem") == 0))
1205 ksem_destroy_should_fail(id, EBUSY);
1209 waitpid(pid, NULL, 0);
1212 TEST(busy_destroy_test, "destroy unnamed semaphore with waiter");
1215 exhaust_unnamed_child(void *arg)
1220 max = (intptr_t)arg;
1221 for (i = 0; i < max + 1; i++) {
1222 if (ksem_init(&id, 1) < 0) {
1223 if (errno == ENOSPC)
1224 return (CSTAT(0, 0));
1225 return (CSTAT(1, errno));
1228 return (CSTAT(2, 0));
1232 exhaust_unnamed_sems(void)
1235 int nsems_max, stat;
1237 len = sizeof(nsems_max);
1238 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1240 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1244 if (child_worker(exhaust_unnamed_child, (void *)(uintptr_t)nsems_max,
1247 errno = CSTAT_ERROR(stat);
1248 switch (CSTAT_CLASS(stat)) {
1253 fail_errno("ksem_init");
1256 fail_err("Limit of %d semaphores not enforced", nsems_max);
1259 fail_err("bad child state %#x", stat);
1263 TEST(exhaust_unnamed_sems, "exhaust unnamed semaphores (1)");
1266 exhaust_named_child(void *arg)
1272 max = (intptr_t)arg;
1273 for (i = 0; i < max + 1; i++) {
1274 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1275 if (ksem_open(&id, buffer, O_CREAT, 0777, 1) < 0) {
1276 if (errno == ENOSPC || errno == EMFILE ||
1278 return (CSTAT(0, 0));
1279 return (CSTAT(1, errno));
1282 return (CSTAT(2, errno));
1286 exhaust_named_sems(void)
1290 int i, nsems_max, stat;
1292 len = sizeof(nsems_max);
1293 if (sysctlbyname("p1003_1b.sem_nsems_max", &nsems_max, &len, NULL, 0) <
1295 fail_errno("sysctl(p1003_1b.sem_nsems_max)");
1299 if (child_worker(exhaust_named_child, (void *)(uintptr_t)nsems_max,
1302 errno = CSTAT_ERROR(stat);
1303 switch (CSTAT_CLASS(stat)) {
1308 fail_errno("ksem_open");
1311 fail_err("Limit of %d semaphores not enforced", nsems_max);
1314 fail_err("bad child state %#x", stat);
1318 /* Cleanup any semaphores created by the child. */
1319 for (i = 0; i < nsems_max + 1; i++) {
1320 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1321 ksem_unlink(buffer);
1324 TEST(exhaust_named_sems, "exhaust named semaphores (1)");
1327 fdlimit_set(void *arg)
1332 max = (intptr_t)arg;
1333 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1334 return (CSTAT(3, errno));
1335 rlim.rlim_cur = max;
1336 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
1337 return (CSTAT(4, errno));
1342 fdlimit_unnamed_child(void *arg)
1346 stat = fdlimit_set(arg);
1348 stat = exhaust_unnamed_child(arg);
1353 fdlimit_unnamed_sems(void)
1355 int nsems_max, stat;
1358 if (child_worker(fdlimit_unnamed_child, (void *)(uintptr_t)nsems_max,
1361 errno = CSTAT_ERROR(stat);
1362 switch (CSTAT_CLASS(stat)) {
1367 fail_errno("ksem_init");
1370 fail_err("Limit of %d semaphores not enforced", nsems_max);
1373 fail_errno("getrlimit");
1376 fail_errno("getrlimit");
1379 fail_err("bad child state %#x", stat);
1383 TEST(fdlimit_unnamed_sems, "exhaust unnamed semaphores (2)");
1386 fdlimit_named_child(void *arg)
1390 stat = fdlimit_set(arg);
1392 stat = exhaust_named_child(arg);
1397 fdlimit_named_sems(void)
1400 int i, nsems_max, stat;
1403 if (child_worker(fdlimit_named_child, (void *)(uintptr_t)nsems_max,
1406 errno = CSTAT_ERROR(stat);
1407 switch (CSTAT_CLASS(stat)) {
1412 fail_errno("ksem_open");
1415 fail_err("Limit of %d semaphores not enforced", nsems_max);
1418 fail_errno("getrlimit");
1421 fail_errno("getrlimit");
1424 fail_err("bad child state %#x", stat);
1428 /* Cleanup any semaphores created by the child. */
1429 for (i = 0; i < nsems_max + 1; i++) {
1430 snprintf(buffer, sizeof(buffer), "%s%d", TEST_PATH, i);
1431 ksem_unlink(buffer);
1434 TEST(fdlimit_named_sems, "exhaust named semaphores (2)");
1437 main(int argc, char *argv[])
1440 signal(SIGSYS, SIG_IGN);