diff options
Diffstat (limited to 'contrib/netbsd-tests/lib/librt/t_sem.c')
| -rw-r--r-- | contrib/netbsd-tests/lib/librt/t_sem.c | 149 |
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(); } |
