1*7778e81aSriastradh /* $NetBSD: t_timerfd.c,v 1.11 2024/12/19 23:50:22 riastradh Exp $ */ 2e714af64Sthorpej 3e714af64Sthorpej /*- 4e714af64Sthorpej * Copyright (c) 2020 The NetBSD Foundation, Inc. 5e714af64Sthorpej * All rights reserved. 6e714af64Sthorpej * 7e714af64Sthorpej * Redistribution and use in source and binary forms, with or without 8e714af64Sthorpej * modification, are permitted provided that the following conditions 9e714af64Sthorpej * are met: 10e714af64Sthorpej * 1. Redistributions of source code must retain the above copyright 11e714af64Sthorpej * notice, this list of conditions and the following disclaimer. 12e714af64Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 13e714af64Sthorpej * notice, this list of conditions and the following disclaimer in the 14e714af64Sthorpej * documentation and/or other materials provided with the distribution. 15e714af64Sthorpej * 16e714af64Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17e714af64Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18e714af64Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19e714af64Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20e714af64Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21e714af64Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22e714af64Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23e714af64Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24e714af64Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25e714af64Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26e714af64Sthorpej * POSSIBILITY OF SUCH DAMAGE. 27e714af64Sthorpej */ 28e714af64Sthorpej 29e714af64Sthorpej #include <sys/cdefs.h> 30e714af64Sthorpej __COPYRIGHT("@(#) Copyright (c) 2020\ 31e714af64Sthorpej The NetBSD Foundation, inc. All rights reserved."); 32*7778e81aSriastradh __RCSID("$NetBSD: t_timerfd.c,v 1.11 2024/12/19 23:50:22 riastradh Exp $"); 33e714af64Sthorpej 34e714af64Sthorpej #include <sys/types.h> 35bcd5a23fSriastradh 36e714af64Sthorpej #include <sys/event.h> 37f92afe1eSthorpej #include <sys/ioctl.h> 38e714af64Sthorpej #include <sys/select.h> 39e714af64Sthorpej #include <sys/stat.h> 40e714af64Sthorpej #include <sys/syscall.h> 41e714af64Sthorpej #include <sys/timerfd.h> 42bcd5a23fSriastradh 43e714af64Sthorpej #include <errno.h> 44e714af64Sthorpej #include <poll.h> 45e714af64Sthorpej #include <pthread.h> 46e714af64Sthorpej #include <stdio.h> 47bcd5a23fSriastradh #include <stdlib.h> 48e714af64Sthorpej #include <time.h> 49e714af64Sthorpej #include <unistd.h> 50e714af64Sthorpej 51e714af64Sthorpej #include <atf-c.h> 52e714af64Sthorpej 53bcd5a23fSriastradh #include "h_macros.h" 54f75cd5d6Shannken #include "isqemu.h" 55f75cd5d6Shannken 56e714af64Sthorpej struct helper_context { 57e714af64Sthorpej int fd; 58e714af64Sthorpej 59e714af64Sthorpej pthread_barrier_t barrier; 60e714af64Sthorpej }; 61e714af64Sthorpej 62e714af64Sthorpej static void 63e714af64Sthorpej init_helper_context(struct helper_context * const ctx) 64e714af64Sthorpej { 65e714af64Sthorpej 66e714af64Sthorpej memset(ctx, 0, sizeof(*ctx)); 67e714af64Sthorpej 68e714af64Sthorpej ATF_REQUIRE(pthread_barrier_init(&ctx->barrier, NULL, 2) == 0); 69e714af64Sthorpej } 70e714af64Sthorpej 71e714af64Sthorpej static bool 72e714af64Sthorpej wait_barrier(struct helper_context * const ctx) 73e714af64Sthorpej { 74e714af64Sthorpej int rv = pthread_barrier_wait(&ctx->barrier); 75e714af64Sthorpej 76e714af64Sthorpej return rv == 0 || rv == PTHREAD_BARRIER_SERIAL_THREAD; 77e714af64Sthorpej } 78e714af64Sthorpej 79f75cd5d6Shannken static bool 80f75cd5d6Shannken check_value_against_bounds(uint64_t value, uint64_t lower, uint64_t upper) 81f75cd5d6Shannken { 82f75cd5d6Shannken 83f75cd5d6Shannken /* 84f75cd5d6Shannken * If running under QEMU make sure the upper bound is large 85f75cd5d6Shannken * enough for the effect of kern/43997 86f75cd5d6Shannken */ 87f75cd5d6Shannken if (isQEMU()) { 88f75cd5d6Shannken upper *= 4; 89f75cd5d6Shannken } 90f75cd5d6Shannken 91f75cd5d6Shannken if (value < lower || value > upper) { 92f75cd5d6Shannken printf("val %" PRIu64 " not in [ %" PRIu64 ", %" PRIu64 " ]\n", 93f75cd5d6Shannken value, lower, upper); 94f75cd5d6Shannken } 95f75cd5d6Shannken 96f75cd5d6Shannken return value >= lower && value <= upper; 97f75cd5d6Shannken } 98f75cd5d6Shannken 99e714af64Sthorpej /*****************************************************************************/ 100e714af64Sthorpej 101e714af64Sthorpej static int 102e714af64Sthorpej timerfd_read(int fd, uint64_t *valp) 103e714af64Sthorpej { 104e714af64Sthorpej uint64_t val; 105e714af64Sthorpej 106e714af64Sthorpej switch (read(fd, &val, sizeof(val))) { 107e714af64Sthorpej case -1: 108e714af64Sthorpej return -1; 109e714af64Sthorpej 110e714af64Sthorpej case sizeof(val): 111e714af64Sthorpej *valp = val; 112e714af64Sthorpej return 0; 113e714af64Sthorpej 114e714af64Sthorpej default: 115e714af64Sthorpej /* ?? Should never happen. */ 116e714af64Sthorpej errno = EIO; 117e714af64Sthorpej return -1; 118e714af64Sthorpej } 119e714af64Sthorpej } 120e714af64Sthorpej 121e714af64Sthorpej /*****************************************************************************/ 122e714af64Sthorpej 123e714af64Sthorpej ATF_TC(timerfd_create); 124e714af64Sthorpej ATF_TC_HEAD(timerfd_create, tc) 125e714af64Sthorpej { 126e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates timerfd_create()"); 127e714af64Sthorpej } 128e714af64Sthorpej ATF_TC_BODY(timerfd_create, tc) 129e714af64Sthorpej { 130e714af64Sthorpej int fd; 131e714af64Sthorpej 132e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0); 133e714af64Sthorpej (void) close(fd); 134e714af64Sthorpej 135e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); 136e714af64Sthorpej (void) close(fd); 137e714af64Sthorpej 138e714af64Sthorpej ATF_REQUIRE_ERRNO(EINVAL, 139e714af64Sthorpej (fd = timerfd_create(CLOCK_VIRTUAL, 0)) == -1); 140e714af64Sthorpej 141e714af64Sthorpej ATF_REQUIRE_ERRNO(EINVAL, 142e714af64Sthorpej (fd = timerfd_create(CLOCK_PROF, 0)) == -1); 143e714af64Sthorpej 144e714af64Sthorpej ATF_REQUIRE_ERRNO(EINVAL, 145e714af64Sthorpej (fd = timerfd_create(CLOCK_REALTIME, 146e714af64Sthorpej ~(TFD_CLOEXEC | TFD_NONBLOCK))) == -1); 147e714af64Sthorpej } 148e714af64Sthorpej 149e714af64Sthorpej /*****************************************************************************/ 150e714af64Sthorpej 151bcd5a23fSriastradh ATF_TC(timerfd_write); 152bcd5a23fSriastradh ATF_TC_HEAD(timerfd_write, tc) 153bcd5a23fSriastradh { 154bcd5a23fSriastradh atf_tc_set_md_var(tc, "descr", 155bcd5a23fSriastradh "validates rejection of writes to timerfds"); 156bcd5a23fSriastradh } 157bcd5a23fSriastradh ATF_TC_BODY(timerfd_write, tc) 158bcd5a23fSriastradh { 159bcd5a23fSriastradh int fd; 160bcd5a23fSriastradh char c = 1; 161bcd5a23fSriastradh 162bcd5a23fSriastradh RL(fd = timerfd_create(CLOCK_REALTIME, 0)); 163bcd5a23fSriastradh ATF_CHECK_ERRNO(EBADF, write(fd, &c, 1) == -1); 164bcd5a23fSriastradh RL(close(fd)); 165bcd5a23fSriastradh } 166bcd5a23fSriastradh 167bcd5a23fSriastradh /*****************************************************************************/ 168bcd5a23fSriastradh 169e714af64Sthorpej ATF_TC(timerfd_bogusfd); 170e714af64Sthorpej ATF_TC_HEAD(timerfd_bogusfd, tc) 171e714af64Sthorpej { 172e714af64Sthorpej atf_tc_set_md_var(tc, "descr", 173e714af64Sthorpej "validates rejection of bogus fds by timerfd_{get,set}time()"); 174e714af64Sthorpej } 175e714af64Sthorpej ATF_TC_BODY(timerfd_bogusfd, tc) 176e714af64Sthorpej { 177e714af64Sthorpej struct itimerspec its = { 0 }; 178e714af64Sthorpej int fd; 179e714af64Sthorpej 180e714af64Sthorpej ATF_REQUIRE((fd = kqueue()) >= 0); /* arbitrary fd type */ 181e714af64Sthorpej 182e714af64Sthorpej ATF_REQUIRE_ERRNO(EINVAL, 183e714af64Sthorpej timerfd_gettime(fd, &its) == -1); 184e714af64Sthorpej 185e714af64Sthorpej its.it_value.tv_sec = 5; 186e714af64Sthorpej ATF_REQUIRE_ERRNO(EINVAL, 187e714af64Sthorpej timerfd_settime(fd, 0, &its, NULL) == -1); 188e714af64Sthorpej 189e714af64Sthorpej (void) close(fd); 190e714af64Sthorpej } 191e714af64Sthorpej 192e714af64Sthorpej /*****************************************************************************/ 193e714af64Sthorpej 194bcd5a23fSriastradh ATF_TC(timerfd_invalidtime); 195bcd5a23fSriastradh ATF_TC_HEAD(timerfd_invalidtime, tc) 196bcd5a23fSriastradh { 197bcd5a23fSriastradh atf_tc_set_md_var(tc, "descr", 198bcd5a23fSriastradh "validates rejection of invalid itimerspec by timerfd_settime()"); 199bcd5a23fSriastradh } 200bcd5a23fSriastradh ATF_TC_BODY(timerfd_invalidtime, tc) 201bcd5a23fSriastradh { 202bcd5a23fSriastradh const struct itimerspec einval_its[] = { 203bcd5a23fSriastradh [0] = { .it_value = {-1, 0} }, 204bcd5a23fSriastradh [1] = { .it_value = {0, -1} }, 205bcd5a23fSriastradh [2] = { .it_value = {0, 1000000001} }, 206bcd5a23fSriastradh [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} }, 207bcd5a23fSriastradh [4] = { .it_value = {1, 0}, .it_interval = {0, -1} }, 208bcd5a23fSriastradh [5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} }, 209bcd5a23fSriastradh }; 210bcd5a23fSriastradh struct timespec now; 211bcd5a23fSriastradh unsigned i; 212bcd5a23fSriastradh fd_set readfds; 213bcd5a23fSriastradh uint64_t val; 214bcd5a23fSriastradh int fd; 215bcd5a23fSriastradh 216bcd5a23fSriastradh RL(clock_gettime(CLOCK_MONOTONIC, &now)); 217bcd5a23fSriastradh RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)); 218bcd5a23fSriastradh 219bcd5a23fSriastradh for (i = 0; i < __arraycount(einval_its); i++) { 220bcd5a23fSriastradh struct itimerspec its; 221bcd5a23fSriastradh 222bcd5a23fSriastradh fprintf(stderr, "case %u\n", i); 223bcd5a23fSriastradh 224bcd5a23fSriastradh ATF_CHECK_ERRNO(EINVAL, 225bcd5a23fSriastradh timerfd_settime(fd, 0, &einval_its[i], NULL) == -1); 226bcd5a23fSriastradh 227bcd5a23fSriastradh /* Try the same with an absolute time near now. */ 228bcd5a23fSriastradh its.it_value = einval_its[i].it_value; 229bcd5a23fSriastradh its.it_value.tv_sec += now.tv_sec + 60; 230bcd5a23fSriastradh ATF_CHECK_ERRNO(EINVAL, 231bcd5a23fSriastradh timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == -1); 232bcd5a23fSriastradh } 233bcd5a23fSriastradh 234bcd5a23fSriastradh /* Wait up to 2sec to make sure no timer got set anyway. */ 235bcd5a23fSriastradh FD_ZERO(&readfds); 236bcd5a23fSriastradh FD_SET(fd, &readfds); 237bcd5a23fSriastradh RL(select(fd + 1, &readfds, NULL, NULL, &(struct timeval){2, 0})); 238bcd5a23fSriastradh ATF_CHECK(!FD_ISSET(fd, &readfds)); 239bcd5a23fSriastradh ATF_CHECK_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1); 240bcd5a23fSriastradh 241bcd5a23fSriastradh RL(close(fd)); 242bcd5a23fSriastradh } 243bcd5a23fSriastradh 244bcd5a23fSriastradh /*****************************************************************************/ 245bcd5a23fSriastradh 246bcd5a23fSriastradh ATF_TC(timerfd_past); 247bcd5a23fSriastradh ATF_TC_HEAD(timerfd_past, tc) 248bcd5a23fSriastradh { 249bcd5a23fSriastradh atf_tc_set_md_var(tc, "descr", "validates trigger on past time"); 250bcd5a23fSriastradh } 251bcd5a23fSriastradh ATF_TC_BODY(timerfd_past, tc) 252bcd5a23fSriastradh { 253bcd5a23fSriastradh struct itimerspec its = {.it_value = {-1, 0}, .it_interval = {0, 0}}; 254bcd5a23fSriastradh struct timespec then, now, delta; 255bcd5a23fSriastradh uint64_t val; 256bcd5a23fSriastradh int fd; 257bcd5a23fSriastradh 258bcd5a23fSriastradh RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)); 259bcd5a23fSriastradh 260bcd5a23fSriastradh RL(clock_gettime(CLOCK_MONOTONIC, &then)); 261bcd5a23fSriastradh timespecadd(&then, &its.it_value, &its.it_value); 262bcd5a23fSriastradh RL(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL)); 263bcd5a23fSriastradh 264bcd5a23fSriastradh /* 265bcd5a23fSriastradh * Wait for one tick to pass. 266bcd5a23fSriastradh * 267bcd5a23fSriastradh * XXX Having to do this seems silly, but it matches Linux, so. 268bcd5a23fSriastradh */ 269bcd5a23fSriastradh RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &(const struct timespec){0, 1}, 270bcd5a23fSriastradh NULL)); 271bcd5a23fSriastradh 272bcd5a23fSriastradh RL(timerfd_read(fd, &val)); 273bcd5a23fSriastradh RL(clock_gettime(CLOCK_MONOTONIC, &now)); 274bcd5a23fSriastradh ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); 275bcd5a23fSriastradh 276bcd5a23fSriastradh timespecsub(&now, &then, &delta); 277bcd5a23fSriastradh ATF_CHECK_MSG(check_value_against_bounds(delta.tv_sec, 0, 0), 278bcd5a23fSriastradh "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu", 279bcd5a23fSriastradh (intmax_t)then.tv_sec, then.tv_nsec, 280bcd5a23fSriastradh (intmax_t)now.tv_sec, now.tv_nsec, 281bcd5a23fSriastradh (intmax_t)delta.tv_sec, delta.tv_nsec); 282bcd5a23fSriastradh 283bcd5a23fSriastradh RL(close(fd)); 284bcd5a23fSriastradh } 285bcd5a23fSriastradh 286bcd5a23fSriastradh /*****************************************************************************/ 287bcd5a23fSriastradh 288e714af64Sthorpej ATF_TC(timerfd_block); 289e714af64Sthorpej ATF_TC_HEAD(timerfd_block, tc) 290e714af64Sthorpej { 291e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates blocking behavior"); 292e714af64Sthorpej } 293e714af64Sthorpej ATF_TC_BODY(timerfd_block, tc) 294e714af64Sthorpej { 295e714af64Sthorpej struct timespec then, now, delta; 296e714af64Sthorpej uint64_t val; 297e714af64Sthorpej int fd; 298e714af64Sthorpej 299e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); 300e714af64Sthorpej 301f196a069Sriastradh struct itimerspec oits; 302e714af64Sthorpej const struct itimerspec its = { 303e714af64Sthorpej .it_value = { .tv_sec = 1, .tv_nsec = 0 }, 304e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 305e714af64Sthorpej }; 306e714af64Sthorpej 307e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 308e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 309f196a069Sriastradh ATF_REQUIRE(timerfd_settime(fd, 0, &its, &oits) == 0); 310f196a069Sriastradh ATF_CHECK_MSG(timespeccmp(&oits.it_value, &its.it_value, <=), 311f196a069Sriastradh "timerfd_settime returned %jd.%09lu remaining," 312f196a069Sriastradh " expected at most %jd.%09lu", 313f196a069Sriastradh (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec, 314f196a069Sriastradh (intmax_t)its.it_value.tv_sec, its.it_value.tv_nsec); 315e714af64Sthorpej ATF_REQUIRE(timerfd_read(fd, &val) == 0); 316e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 317f75cd5d6Shannken ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); 318e714af64Sthorpej 319e714af64Sthorpej timespecsub(&now, &then, &delta); 320d60bdbc1Sriastradh ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1), 321d60bdbc1Sriastradh "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu", 322d60bdbc1Sriastradh (intmax_t)then.tv_sec, then.tv_nsec, 323d60bdbc1Sriastradh (intmax_t)now.tv_sec, now.tv_nsec, 324d60bdbc1Sriastradh (intmax_t)delta.tv_sec, delta.tv_nsec); 325e714af64Sthorpej 326e714af64Sthorpej (void) close(fd); 327e714af64Sthorpej } 328e714af64Sthorpej 329e714af64Sthorpej /*****************************************************************************/ 330e714af64Sthorpej 331e714af64Sthorpej ATF_TC(timerfd_repeating); 332e714af64Sthorpej ATF_TC_HEAD(timerfd_repeating, tc) 333e714af64Sthorpej { 334e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates repeating timer behavior"); 335e714af64Sthorpej } 336e714af64Sthorpej ATF_TC_BODY(timerfd_repeating, tc) 337e714af64Sthorpej { 338e714af64Sthorpej struct timespec then, now, delta; 339e714af64Sthorpej uint64_t val; 340e714af64Sthorpej int fd; 341e714af64Sthorpej 342e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 343e714af64Sthorpej TFD_NONBLOCK)) >= 0); 344e714af64Sthorpej 345e714af64Sthorpej const struct itimerspec its = { 346e714af64Sthorpej .it_value = { .tv_sec = 0, .tv_nsec = 200000000 }, 347e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 200000000 }, 348e714af64Sthorpej }; 349e714af64Sthorpej 350e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 351e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 352e714af64Sthorpej ATF_REQUIRE(sleep(1) == 0); 353e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 354e714af64Sthorpej ATF_REQUIRE(timerfd_read(fd, &val) == 0); 355f75cd5d6Shannken /* allow some slop */ 356f75cd5d6Shannken ATF_REQUIRE(check_value_against_bounds(val, 3, 5)); 357e714af64Sthorpej 358e714af64Sthorpej timespecsub(&now, &then, &delta); 359d60bdbc1Sriastradh ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1), 360d60bdbc1Sriastradh "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu", 361d60bdbc1Sriastradh (intmax_t)then.tv_sec, then.tv_nsec, 362d60bdbc1Sriastradh (intmax_t)now.tv_sec, now.tv_nsec, 363d60bdbc1Sriastradh (intmax_t)delta.tv_sec, delta.tv_nsec); 364e714af64Sthorpej 365e714af64Sthorpej (void) close(fd); 366e714af64Sthorpej } 367e714af64Sthorpej 368e714af64Sthorpej /*****************************************************************************/ 369e714af64Sthorpej 370e714af64Sthorpej ATF_TC(timerfd_abstime); 371e714af64Sthorpej ATF_TC_HEAD(timerfd_abstime, tc) 372e714af64Sthorpej { 373e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates specifying abstime"); 374e714af64Sthorpej } 375e714af64Sthorpej ATF_TC_BODY(timerfd_abstime, tc) 376e714af64Sthorpej { 377e714af64Sthorpej struct timespec then, now, delta; 378e714af64Sthorpej uint64_t val; 379e714af64Sthorpej int fd; 380e714af64Sthorpej 381e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); 382e714af64Sthorpej 383f196a069Sriastradh struct itimerspec oits, its = { 384e714af64Sthorpej .it_value = { .tv_sec = 0, .tv_nsec = 0 }, 385e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 386e714af64Sthorpej }; 387e714af64Sthorpej 388e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 389f196a069Sriastradh delta = (struct timespec){1, 0}; 390f196a069Sriastradh timespecadd(&then, &delta, &its.it_value); 391e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == 0); 392f196a069Sriastradh ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, &oits) == 0); 393f196a069Sriastradh timespecadd(&delta, (&(const struct timespec){2, 0}), /* tick slop */ 394f196a069Sriastradh &delta); 395f196a069Sriastradh ATF_CHECK_MSG(timespeccmp(&oits.it_value, &delta, <=), 396f196a069Sriastradh "timerfd_settime returned %jd.%09lu remaining," 397f196a069Sriastradh " expected at most %jd.%09lu", 398f196a069Sriastradh (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec, 399f196a069Sriastradh (intmax_t)delta.tv_sec, delta.tv_nsec); 400e714af64Sthorpej ATF_REQUIRE(timerfd_read(fd, &val) == 0); 401e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 402f75cd5d6Shannken ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); 403e714af64Sthorpej 404e714af64Sthorpej timespecsub(&now, &then, &delta); 405d60bdbc1Sriastradh ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1), 406d60bdbc1Sriastradh "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu", 407d60bdbc1Sriastradh (intmax_t)then.tv_sec, then.tv_nsec, 408d60bdbc1Sriastradh (intmax_t)now.tv_sec, now.tv_nsec, 409d60bdbc1Sriastradh (intmax_t)delta.tv_sec, delta.tv_nsec); 410e714af64Sthorpej 411e714af64Sthorpej (void) close(fd); 412e714af64Sthorpej } 413e714af64Sthorpej 414e714af64Sthorpej /*****************************************************************************/ 415e714af64Sthorpej 416e714af64Sthorpej ATF_TC(timerfd_cancel_on_set_immed); 417e714af64Sthorpej ATF_TC_HEAD(timerfd_cancel_on_set_immed, tc) 418e714af64Sthorpej { 419e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - immediate"); 420e714af64Sthorpej atf_tc_set_md_var(tc, "require.user", "root"); 421e714af64Sthorpej } 422e714af64Sthorpej ATF_TC_BODY(timerfd_cancel_on_set_immed, tc) 423e714af64Sthorpej { 424e714af64Sthorpej struct timespec now; 425e714af64Sthorpej uint64_t val; 426e714af64Sthorpej int fd; 427e714af64Sthorpej 428e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0); 429e714af64Sthorpej 430e714af64Sthorpej const struct itimerspec its = { 431e714af64Sthorpej .it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 }, 432e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 433e714af64Sthorpej }; 434e714af64Sthorpej 435e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0); 436e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET, 437e714af64Sthorpej &its, NULL) == 0); 438e714af64Sthorpej ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0); 439e714af64Sthorpej ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1); 440e714af64Sthorpej 441e714af64Sthorpej (void) close(fd); 442e714af64Sthorpej } 443e714af64Sthorpej 444e714af64Sthorpej /*****************************************************************************/ 445e714af64Sthorpej 446e714af64Sthorpej static void * 447e714af64Sthorpej timerfd_cancel_on_set_block_helper(void * const v) 448e714af64Sthorpej { 449e714af64Sthorpej struct helper_context * const ctx = v; 450e714af64Sthorpej struct timespec now; 451e714af64Sthorpej 452e714af64Sthorpej ATF_REQUIRE(wait_barrier(ctx)); 453e714af64Sthorpej 454e714af64Sthorpej ATF_REQUIRE(sleep(2) == 0); 455e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0); 456e714af64Sthorpej ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0); 457e714af64Sthorpej 458e714af64Sthorpej return NULL; 459e714af64Sthorpej } 460e714af64Sthorpej 461e714af64Sthorpej ATF_TC(timerfd_cancel_on_set_block); 462e714af64Sthorpej ATF_TC_HEAD(timerfd_cancel_on_set_block, tc) 463e714af64Sthorpej { 464e714af64Sthorpej atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - blocking"); 465e714af64Sthorpej atf_tc_set_md_var(tc, "require.user", "root"); 466e714af64Sthorpej } 467e714af64Sthorpej ATF_TC_BODY(timerfd_cancel_on_set_block, tc) 468e714af64Sthorpej { 469e714af64Sthorpej struct helper_context ctx; 470e714af64Sthorpej pthread_t helper; 471e714af64Sthorpej void *join_val; 472e714af64Sthorpej uint64_t val; 473e714af64Sthorpej int fd; 474e714af64Sthorpej 475e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0); 476e714af64Sthorpej 477e714af64Sthorpej const struct itimerspec its = { 478e714af64Sthorpej .it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 }, 479e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 480e714af64Sthorpej }; 481e714af64Sthorpej 482e714af64Sthorpej init_helper_context(&ctx); 483e714af64Sthorpej 484e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET, 485e714af64Sthorpej &its, NULL) == 0); 486e714af64Sthorpej ATF_REQUIRE(pthread_create(&helper, NULL, 487e714af64Sthorpej timerfd_cancel_on_set_block_helper, &ctx) == 0); 488e714af64Sthorpej ATF_REQUIRE(wait_barrier(&ctx)); 489e714af64Sthorpej ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1); 490e714af64Sthorpej 491e714af64Sthorpej ATF_REQUIRE(pthread_join(helper, &join_val) == 0); 492e714af64Sthorpej 493e714af64Sthorpej (void) close(fd); 494e714af64Sthorpej } 495e714af64Sthorpej 496e714af64Sthorpej /*****************************************************************************/ 497e714af64Sthorpej 498e714af64Sthorpej ATF_TC(timerfd_select_poll_kevent_immed); 499e714af64Sthorpej ATF_TC_HEAD(timerfd_select_poll_kevent_immed, tc) 500e714af64Sthorpej { 501e714af64Sthorpej atf_tc_set_md_var(tc, "descr", 502e714af64Sthorpej "validates select/poll/kevent behavior - immediate return"); 503e714af64Sthorpej } 504e714af64Sthorpej ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc) 505e714af64Sthorpej { 506e714af64Sthorpej const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; 507e714af64Sthorpej struct itimerspec its; 508e714af64Sthorpej struct timeval tv; 509e714af64Sthorpej struct stat st; 510e714af64Sthorpej struct pollfd fds[1]; 511e714af64Sthorpej uint64_t val; 512e714af64Sthorpej fd_set readfds, writefds, exceptfds; 513e714af64Sthorpej int fd; 514e714af64Sthorpej int kq; 515e714af64Sthorpej struct kevent kev[1]; 516e714af64Sthorpej 517e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0); 518e714af64Sthorpej 519e714af64Sthorpej ATF_REQUIRE((kq = kqueue()) >= 0); 520e714af64Sthorpej EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL); 521e714af64Sthorpej ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0); 5228843a0bfSriastradh EV_SET(&kev[0], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); 5238843a0bfSriastradh ATF_CHECK_ERRNO(EINVAL, kevent(kq, kev, 1, NULL, 0, &ts) == -1); 524e714af64Sthorpej 525e714af64Sthorpej /* 52654cb252aSriastradh * fd should not be ready for anything. Pass all of the event 52754cb252aSriastradh * bits; we should get back nothing. 528e714af64Sthorpej */ 529e714af64Sthorpej fds[0].fd = fd; 530e714af64Sthorpej fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | 531e714af64Sthorpej POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP; 532e714af64Sthorpej fds[0].revents = 0; 5338843a0bfSriastradh ATF_REQUIRE(poll(fds, 1, 0) == 0); 534e714af64Sthorpej 535e714af64Sthorpej /* 53654cb252aSriastradh * As above; fd should not be set on return from the select() 53754cb252aSriastradh * call. 538e714af64Sthorpej */ 539e714af64Sthorpej FD_ZERO(&readfds); 540e714af64Sthorpej FD_ZERO(&writefds); 541e714af64Sthorpej FD_ZERO(&exceptfds); 542e714af64Sthorpej tv.tv_sec = 0; 543e714af64Sthorpej tv.tv_usec = 0; 544e714af64Sthorpej FD_SET(fd, &readfds); 545e714af64Sthorpej FD_SET(fd, &writefds); 546e714af64Sthorpej FD_SET(fd, &exceptfds); 5478843a0bfSriastradh ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 0); 548e714af64Sthorpej ATF_REQUIRE(!FD_ISSET(fd, &readfds)); 54954cb252aSriastradh ATF_REQUIRE(!FD_ISSET(fd, &writefds)); 550e714af64Sthorpej ATF_REQUIRE(!FD_ISSET(fd, &exceptfds)); 551e714af64Sthorpej 552e714af64Sthorpej /* 553e714af64Sthorpej * Now set a one-shot half-second timer, wait for it to expire, and 554e714af64Sthorpej * then check again. 555e714af64Sthorpej */ 556e714af64Sthorpej memset(&its, 0, sizeof(its)); 557e714af64Sthorpej its.it_value.tv_sec = 0; 558e714af64Sthorpej its.it_value.tv_nsec = 500000000; 559e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 560e714af64Sthorpej ATF_REQUIRE(sleep(2) == 0); 561e714af64Sthorpej 562e714af64Sthorpej /* Verify it actually fired via the stat() back-channel. */ 563e714af64Sthorpej ATF_REQUIRE(fstat(fd, &st) == 0); 564e714af64Sthorpej ATF_REQUIRE(st.st_size == 1); 565e714af64Sthorpej 566e714af64Sthorpej fds[0].fd = fd; 567e714af64Sthorpej fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | 568e714af64Sthorpej POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP; 569e714af64Sthorpej fds[0].revents = 0; 570e714af64Sthorpej ATF_REQUIRE(poll(fds, 1, 0) == 1); 57154cb252aSriastradh ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM)); 572e714af64Sthorpej 573e714af64Sthorpej FD_ZERO(&readfds); 574e714af64Sthorpej FD_ZERO(&writefds); 575e714af64Sthorpej FD_ZERO(&exceptfds); 576e714af64Sthorpej tv.tv_sec = 0; 577e714af64Sthorpej tv.tv_usec = 0; 578e714af64Sthorpej FD_SET(fd, &readfds); 579e714af64Sthorpej FD_SET(fd, &writefds); 580e714af64Sthorpej FD_SET(fd, &exceptfds); 5818843a0bfSriastradh ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1); 582e714af64Sthorpej ATF_REQUIRE(FD_ISSET(fd, &readfds)); 58354cb252aSriastradh ATF_REQUIRE(!FD_ISSET(fd, &writefds)); 584e714af64Sthorpej ATF_REQUIRE(!FD_ISSET(fd, &exceptfds)); 585e714af64Sthorpej 586e714af64Sthorpej /* 587e714af64Sthorpej * Check that we get an EVFILT_READ event on fd. 588e714af64Sthorpej */ 589e714af64Sthorpej memset(kev, 0, sizeof(kev)); 590e714af64Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, &ts) == 1); 591e714af64Sthorpej ATF_REQUIRE(kev[0].ident == (uintptr_t)fd); 592e714af64Sthorpej ATF_REQUIRE(kev[0].filter == EVFILT_READ); 593e714af64Sthorpej ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0); 594e714af64Sthorpej ATF_REQUIRE(kev[0].data == 1); 595e714af64Sthorpej 596e714af64Sthorpej /* 597e714af64Sthorpej * Read the timerfd to ensure we get the correct numnber of 598e714af64Sthorpej * expirations. 599e714af64Sthorpej */ 600e714af64Sthorpej ATF_REQUIRE(timerfd_read(fd, &val) == 0); 601e714af64Sthorpej ATF_REQUIRE(val == 1); 602e714af64Sthorpej 603e714af64Sthorpej /* And ensure that we would block if we tried again. */ 604e714af64Sthorpej ATF_REQUIRE_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1); 605e714af64Sthorpej 606e714af64Sthorpej (void) close(kq); 607e714af64Sthorpej (void) close(fd); 608e714af64Sthorpej } 609e714af64Sthorpej 610e714af64Sthorpej /*****************************************************************************/ 611e714af64Sthorpej 612e714af64Sthorpej ATF_TC(timerfd_select_poll_kevent_block); 613e714af64Sthorpej ATF_TC_HEAD(timerfd_select_poll_kevent_block, tc) 614e714af64Sthorpej { 615e714af64Sthorpej atf_tc_set_md_var(tc, "descr", 616e714af64Sthorpej "validates select/poll/kevent behavior - blocking"); 617e714af64Sthorpej } 618e714af64Sthorpej ATF_TC_BODY(timerfd_select_poll_kevent_block, tc) 619e714af64Sthorpej { 620e714af64Sthorpej const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; 621e714af64Sthorpej struct timespec then, now; 622e714af64Sthorpej struct pollfd fds[1]; 623e714af64Sthorpej fd_set readfds; 624e714af64Sthorpej int fd; 625e714af64Sthorpej int kq; 626e714af64Sthorpej struct kevent kev[1]; 627e714af64Sthorpej 628e714af64Sthorpej ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0); 629e714af64Sthorpej 630e714af64Sthorpej ATF_REQUIRE((kq = kqueue()) >= 0); 631e714af64Sthorpej EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL); 632e714af64Sthorpej ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0); 633e714af64Sthorpej 634e714af64Sthorpej /* 635e714af64Sthorpej * For each of these tests, we do the following: 636e714af64Sthorpej * 637e714af64Sthorpej * - Get the current time. 638e714af64Sthorpej * - Set a 1-second one-shot timer. 639e714af64Sthorpej * - Block in the multiplexing call. 640e714af64Sthorpej * - Get the current time and verify that the timer expiration 641e714af64Sthorpej * interval has passed. 642e714af64Sthorpej */ 643e714af64Sthorpej 644e714af64Sthorpej const struct itimerspec its = { 645e714af64Sthorpej .it_value = { .tv_sec = 1, .tv_nsec = 0 }, 646e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 647e714af64Sthorpej }; 648e714af64Sthorpej 649e714af64Sthorpej /* poll(2) */ 650e714af64Sthorpej fds[0].fd = fd; 651e714af64Sthorpej fds[0].events = POLLIN | POLLRDNORM; 652e714af64Sthorpej fds[0].revents = 0; 653e714af64Sthorpej 654e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 655e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 656e714af64Sthorpej ATF_REQUIRE(poll(fds, 1, INFTIM) == 1); 657e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 658e714af64Sthorpej ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM)); 659e714af64Sthorpej ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1); 660e714af64Sthorpej 661e714af64Sthorpej /* select(2) */ 662e714af64Sthorpej FD_ZERO(&readfds); 663e714af64Sthorpej FD_SET(fd, &readfds); 664e714af64Sthorpej 665e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 666e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 667e714af64Sthorpej ATF_REQUIRE(select(fd + 1, &readfds, NULL, NULL, NULL) == 1); 668e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 669e714af64Sthorpej ATF_REQUIRE(FD_ISSET(fd, &readfds)); 670e714af64Sthorpej ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1); 671e714af64Sthorpej 672e714af64Sthorpej /* kevent(2) */ 673e714af64Sthorpej memset(kev, 0, sizeof(kev)); 674e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 675e714af64Sthorpej ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); 676e714af64Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, NULL) == 1); 677e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 678e714af64Sthorpej ATF_REQUIRE(kev[0].ident == (uintptr_t)fd); 679e714af64Sthorpej ATF_REQUIRE(kev[0].filter == EVFILT_READ); 680e714af64Sthorpej ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0); 681e714af64Sthorpej ATF_REQUIRE(kev[0].data == 1); 682e714af64Sthorpej 683e714af64Sthorpej (void) close(kq); 684e714af64Sthorpej (void) close(fd); 685e714af64Sthorpej } 686e714af64Sthorpej 687e714af64Sthorpej /*****************************************************************************/ 688e714af64Sthorpej 689e714af64Sthorpej static void * 690e714af64Sthorpej timerfd_restart_helper(void * const v) 691e714af64Sthorpej { 692e714af64Sthorpej struct helper_context * const ctx = v; 693e714af64Sthorpej 694e714af64Sthorpej ATF_REQUIRE(wait_barrier(ctx)); 695e714af64Sthorpej 696e714af64Sthorpej /* 697e714af64Sthorpej * Wait 5 seconds (that should give the main thread time to 698e714af64Sthorpej * block), and then close the descriptor. 699e714af64Sthorpej */ 700e714af64Sthorpej ATF_REQUIRE(sleep(5) == 0); 701e714af64Sthorpej ATF_REQUIRE(close(ctx->fd) == 0); 702e714af64Sthorpej 703e714af64Sthorpej return NULL; 704e714af64Sthorpej } 705e714af64Sthorpej 706e714af64Sthorpej ATF_TC(timerfd_restart); 707e714af64Sthorpej ATF_TC_HEAD(timerfd_restart, tc) 708e714af64Sthorpej { 709e714af64Sthorpej atf_tc_set_md_var(tc, "descr", 710e714af64Sthorpej "exercises the 'restart' fileop code path"); 711e714af64Sthorpej } 712e714af64Sthorpej ATF_TC_BODY(timerfd_restart, tc) 713e714af64Sthorpej { 714e714af64Sthorpej struct timespec then, now, delta; 715e714af64Sthorpej struct helper_context ctx; 716e714af64Sthorpej uint64_t val; 717e714af64Sthorpej pthread_t helper; 718e714af64Sthorpej void *join_val; 719e714af64Sthorpej 720e714af64Sthorpej init_helper_context(&ctx); 721e714af64Sthorpej 722e714af64Sthorpej ATF_REQUIRE((ctx.fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); 723e714af64Sthorpej 724e714af64Sthorpej const struct itimerspec its = { 725e714af64Sthorpej .it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 }, 726e714af64Sthorpej .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, 727e714af64Sthorpej }; 728e714af64Sthorpej ATF_REQUIRE(timerfd_settime(ctx.fd, 0, &its, NULL) == 0); 729e714af64Sthorpej 730e714af64Sthorpej 731e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); 732e714af64Sthorpej ATF_REQUIRE(pthread_create(&helper, NULL, 733e714af64Sthorpej timerfd_restart_helper, &ctx) == 0); 734e714af64Sthorpej 735e714af64Sthorpej /* 736e714af64Sthorpej * Wait for the helper to be ready, and then immediately block 737e714af64Sthorpej * in read(). The helper will close the file, and we should get 738e714af64Sthorpej * EBADF after a few seconds. 739e714af64Sthorpej */ 740e714af64Sthorpej ATF_REQUIRE(wait_barrier(&ctx)); 741e714af64Sthorpej ATF_REQUIRE_ERRNO(EBADF, timerfd_read(ctx.fd, &val) == -1); 742e714af64Sthorpej ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 743e714af64Sthorpej 744e714af64Sthorpej timespecsub(&now, &then, &delta); 745e714af64Sthorpej ATF_REQUIRE(delta.tv_sec >= 5); 746e714af64Sthorpej 747e714af64Sthorpej /* Reap the helper. */ 748e714af64Sthorpej ATF_REQUIRE(pthread_join(helper, &join_val) == 0); 749e714af64Sthorpej } 750e714af64Sthorpej 751e714af64Sthorpej /*****************************************************************************/ 752e714af64Sthorpej 753f92afe1eSthorpej ATF_TC(timerfd_fcntl); 754f92afe1eSthorpej ATF_TC_HEAD(timerfd_fcntl, tc) 755f92afe1eSthorpej { 756f92afe1eSthorpej atf_tc_set_md_var(tc, "descr", 757f92afe1eSthorpej "validates fcntl behavior"); 758f92afe1eSthorpej } 759f92afe1eSthorpej 760f92afe1eSthorpej ATF_TC_BODY(timerfd_fcntl, tc) 761f92afe1eSthorpej { 762f92afe1eSthorpej int tfd; 763f92afe1eSthorpej int val; 764f92afe1eSthorpej 765f92afe1eSthorpej ATF_REQUIRE((tfd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); 766f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFL) & O_NONBLOCK) == 0); 767f92afe1eSthorpej ATF_REQUIRE(fcntl(tfd, F_SETFL, O_NONBLOCK) == 0); 768f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFL) & O_NONBLOCK) != 0); 769f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) == 0); 770f92afe1eSthorpej 771f92afe1eSthorpej /* If the timer hasn't fired, there is no readable data. */ 772f92afe1eSthorpej ATF_REQUIRE(ioctl(tfd, FIONREAD, &val) == 0); 773f92afe1eSthorpej ATF_REQUIRE(val == 0); 774f92afe1eSthorpej 775f92afe1eSthorpej ATF_REQUIRE_ERRNO(ENOTTY, ioctl(tfd, FIONWRITE, &val) == -1); 776f92afe1eSthorpej ATF_REQUIRE_ERRNO(ENOTTY, ioctl(tfd, FIONSPACE, &val) == -1); 777f92afe1eSthorpej (void)close(tfd); 778f92afe1eSthorpej 779f92afe1eSthorpej ATF_REQUIRE((tfd = timerfd_create(CLOCK_MONOTONIC, 780f92afe1eSthorpej TFD_NONBLOCK | TFD_CLOEXEC)) >= 0); 781f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFL) & ~O_ACCMODE) == O_NONBLOCK); 782f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) != 0); 783f92afe1eSthorpej ATF_REQUIRE(fcntl(tfd, F_SETFD, 0) == 0); 784f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) == 0); 785f92afe1eSthorpej ATF_REQUIRE(fcntl(tfd, F_SETFD, FD_CLOEXEC) == 0); 786f92afe1eSthorpej ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) != 0); 787f92afe1eSthorpej (void)close(tfd); 788f92afe1eSthorpej } 789f92afe1eSthorpej 790f92afe1eSthorpej /*****************************************************************************/ 791f92afe1eSthorpej 792e714af64Sthorpej ATF_TP_ADD_TCS(tp) 793e714af64Sthorpej { 794bcd5a23fSriastradh 795e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_create); 796bcd5a23fSriastradh ATF_TP_ADD_TC(tp, timerfd_write); 797e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_bogusfd); 798bcd5a23fSriastradh ATF_TP_ADD_TC(tp, timerfd_invalidtime); 799bcd5a23fSriastradh ATF_TP_ADD_TC(tp, timerfd_past); 800e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_block); 801e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_repeating); 802e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_abstime); 803e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_block); 804e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_immed); 805e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_immed); 806e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_block); 807e714af64Sthorpej ATF_TP_ADD_TC(tp, timerfd_restart); 808f92afe1eSthorpej ATF_TP_ADD_TC(tp, timerfd_fcntl); 809e714af64Sthorpej 810e714af64Sthorpej return atf_no_error(); 811e714af64Sthorpej } 812