aboutsummaryrefslogtreecommitdiff
path: root/contrib/netbsd-tests/lib/librt/t_sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/netbsd-tests/lib/librt/t_sem.c')
-rw-r--r--contrib/netbsd-tests/lib/librt/t_sem.c149
1 files changed, 148 insertions, 1 deletions
diff --git a/contrib/netbsd-tests/lib/librt/t_sem.c b/contrib/netbsd-tests/lib/librt/t_sem.c
index 0541ae57113a..4bf379bd1fb1 100644
--- a/contrib/netbsd-tests/lib/librt/t_sem.c
+++ b/contrib/netbsd-tests/lib/librt/t_sem.c
@@ -60,18 +60,24 @@ __COPYRIGHT("@(#) Copyright (c) 2008, 2010\
The NetBSD Foundation, inc. All rights reserved.");
__RCSID("$NetBSD: t_sem.c,v 1.3 2017/01/14 20:58:20 christos Exp $");
+#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <semaphore.h>
+#include <signal.h>
#include <stdio.h>
+#include <time.h>
#include <unistd.h>
#include <atf-c.h>
#define NCHILDREN 10
+#define SEM_REQUIRE(x) \
+ ATF_REQUIRE_EQ_MSG(x, 0, "%s", strerror(errno))
+
ATF_TC_WITH_CLEANUP(basic);
ATF_TC_HEAD(basic, tc)
{
@@ -118,6 +124,7 @@ ATF_TC_HEAD(child, tc)
{
atf_tc_set_md_var(tc, "descr", "Checks using semaphores to synchronize "
"parent with multiple child processes");
+ atf_tc_set_md_var(tc, "timeout", "5");
}
ATF_TC_BODY(child, tc)
{
@@ -153,7 +160,7 @@ ATF_TC_BODY(child, tc)
}
for (i = 0; i < NCHILDREN; i++) {
- sleep(1);
+ usleep(100000);
printf("main loop %d: posting...\n", j);
ATF_REQUIRE_EQ(sem_post(sem_a), 0);
}
@@ -173,11 +180,151 @@ ATF_TC_CLEANUP(child, tc)
(void)sem_unlink("/sem_a");
}
+static inline void
+timespec_add_ms(struct timespec *ts, int ms)
+{
+ ts->tv_nsec += ms * 1000*1000;
+ if (ts->tv_nsec > 1000*1000*1000) {
+ ts->tv_sec++;
+ ts->tv_nsec -= 1000*1000*1000;
+ }
+}
+
+volatile sig_atomic_t got_sigalrm = 0;
+
+static void
+sigalrm_handler(int sig __unused)
+{
+ got_sigalrm = 1;
+}
+
+ATF_TC(timedwait);
+ATF_TC_HEAD(timedwait, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests sem_timedwait(3)"
+#ifdef __FreeBSD__
+ " and sem_clockwait_np(3)"
+#endif
+ );
+ atf_tc_set_md_var(tc, "timeout", "20");
+}
+ATF_TC_BODY(timedwait, tc)
+{
+ struct timespec ts;
+ sem_t sem;
+ int result;
+
+ SEM_REQUIRE(sem_init(&sem, 0, 0));
+ SEM_REQUIRE(sem_post(&sem));
+ ATF_REQUIRE_MSG(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+ "%s", strerror(errno));
+ timespec_add_ms(&ts, 100);
+ SEM_REQUIRE(sem_timedwait(&sem, &ts));
+ ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&sem, &ts));
+ ts.tv_sec--;
+ ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&sem, &ts));
+ SEM_REQUIRE(sem_post(&sem));
+ SEM_REQUIRE(sem_timedwait(&sem, &ts));
+
+ /* timespec validation, in the past */
+ ts.tv_nsec += 1000*1000*1000;
+ ATF_REQUIRE_ERRNO(EINVAL, sem_timedwait(&sem, &ts));
+ ts.tv_nsec = -1;
+ ATF_REQUIRE_ERRNO(EINVAL, sem_timedwait(&sem, &ts));
+ /* timespec validation, in the future */
+ ATF_REQUIRE_MSG(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+ "%s", strerror(errno));
+ ts.tv_sec++;
+ ts.tv_nsec = 1000*1000*1000;
+ ATF_REQUIRE_ERRNO(EINVAL, sem_timedwait(&sem, &ts));
+ ts.tv_nsec = -1;
+ ATF_REQUIRE_ERRNO(EINVAL, sem_timedwait(&sem, &ts));
+
+ /* EINTR */
+ struct sigaction act = {
+ .sa_handler = sigalrm_handler,
+ .sa_flags = 0 /* not SA_RESTART */
+ };
+ ATF_REQUIRE_MSG(sigemptyset(&act.sa_mask) == 0,
+ "%s", strerror(errno));
+ ATF_REQUIRE_MSG(sigaction(SIGALRM, &act, NULL) == 0,
+ "%s", strerror(errno));
+ struct itimerval it = {
+ .it_value.tv_usec = 50*1000
+ };
+ ATF_REQUIRE_MSG(setitimer(ITIMER_REAL, &it, NULL) == 0,
+ "%s", strerror(errno));
+ ATF_REQUIRE_MSG(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+ "%s", strerror(errno));
+ timespec_add_ms(&ts, 100);
+ ATF_REQUIRE_ERRNO(EINTR, sem_timedwait(&sem, &ts));
+ ATF_REQUIRE_MSG(got_sigalrm, "did not get SIGALRM");
+
+#ifdef __FreeBSD__
+ /* CLOCK_MONOTONIC, absolute */
+ SEM_REQUIRE(sem_post(&sem));
+ ATF_REQUIRE_MSG(clock_gettime(CLOCK_MONOTONIC, &ts) == 0,
+ "%s", strerror(errno));
+ timespec_add_ms(&ts, 100);
+ SEM_REQUIRE(sem_clockwait_np(&sem, CLOCK_MONOTONIC, TIMER_ABSTIME,
+ &ts, NULL));
+ ATF_REQUIRE_ERRNO(ETIMEDOUT,
+ sem_clockwait_np(&sem, CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL));
+
+ /* CLOCK_MONOTONIC, relative */
+ SEM_REQUIRE(sem_post(&sem));
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100*1000*1000;
+ SEM_REQUIRE(sem_clockwait_np(&sem, CLOCK_MONOTONIC, 0,
+ &ts, NULL));
+ ATF_REQUIRE_ERRNO(ETIMEDOUT,
+ sem_clockwait_np(&sem, CLOCK_MONOTONIC, 0, &ts, NULL));
+
+ /* absolute does not update remaining time on EINTR */
+ struct timespec remain = {42, 1000*1000*1000};
+ got_sigalrm = 0;
+ it.it_value.tv_usec = 50*1000;
+ ATF_REQUIRE_MSG(setitimer(ITIMER_REAL, &it, NULL) == 0,
+ "%s", strerror(errno));
+ ATF_REQUIRE_MSG(clock_gettime(CLOCK_MONOTONIC, &ts) == 0,
+ "%s", strerror(errno));
+ timespec_add_ms(&ts, 100);
+ ATF_REQUIRE_ERRNO(EINTR, sem_clockwait_np(&sem, CLOCK_MONOTONIC,
+ TIMER_ABSTIME, &ts, &remain));
+ ATF_REQUIRE_MSG(got_sigalrm, "did not get SIGALRM");
+ ATF_REQUIRE_MSG(remain.tv_sec == 42 && remain.tv_nsec == 1000*1000*1000,
+ "an absolute clockwait modified the remaining time on EINTR");
+
+ /* relative updates remaining time on EINTR */
+ remain.tv_sec = 42;
+ remain.tv_nsec = 1000*1000*1000;
+ got_sigalrm = 0;
+ it.it_value.tv_usec = 50*1000;
+ ATF_REQUIRE_MSG(setitimer(ITIMER_REAL, &it, NULL) == 0,
+ "%s", strerror(errno));
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100*1000*1000;
+ ATF_REQUIRE_ERRNO(EINTR, sem_clockwait_np(&sem, CLOCK_MONOTONIC, 0, &ts,
+ &remain));
+ ATF_REQUIRE_MSG(got_sigalrm, "did not get SIGALRM");
+ /*
+ * If this nsec comparison turns out to be unreliable due to timing,
+ * it could simply check that nsec < 100 ms.
+ */
+ ATF_REQUIRE_MSG(remain.tv_sec == 0 &&
+ remain.tv_nsec >= 25*1000*1000 &&
+ remain.tv_nsec <= 75*1000*1000,
+ "the remaining time was not as expected when a relative clockwait"
+ " got EINTR" );
+#endif
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, basic);
ATF_TP_ADD_TC(tp, child);
+ ATF_TP_ADD_TC(tp, timedwait);
return atf_no_error();
}