1*a4fd8414SAndrei Vagin // SPDX-License-Identifier: GPL-2.0 2*a4fd8414SAndrei Vagin #define _GNU_SOURCE 3*a4fd8414SAndrei Vagin #include <sched.h> 4*a4fd8414SAndrei Vagin 5*a4fd8414SAndrei Vagin #include <linux/unistd.h> 6*a4fd8414SAndrei Vagin #include <linux/futex.h> 7*a4fd8414SAndrei Vagin #include <stdio.h> 8*a4fd8414SAndrei Vagin #include <string.h> 9*a4fd8414SAndrei Vagin #include <sys/syscall.h> 10*a4fd8414SAndrei Vagin #include <sys/types.h> 11*a4fd8414SAndrei Vagin #include <sys/wait.h> 12*a4fd8414SAndrei Vagin #include <time.h> 13*a4fd8414SAndrei Vagin #include <unistd.h> 14*a4fd8414SAndrei Vagin 15*a4fd8414SAndrei Vagin #include "log.h" 16*a4fd8414SAndrei Vagin #include "timens.h" 17*a4fd8414SAndrei Vagin 18*a4fd8414SAndrei Vagin #define NSEC_PER_SEC 1000000000ULL 19*a4fd8414SAndrei Vagin 20*a4fd8414SAndrei Vagin static int run_test(int clockid) 21*a4fd8414SAndrei Vagin { 22*a4fd8414SAndrei Vagin int futex_op = FUTEX_WAIT_BITSET; 23*a4fd8414SAndrei Vagin struct timespec timeout, end; 24*a4fd8414SAndrei Vagin int val = 0; 25*a4fd8414SAndrei Vagin 26*a4fd8414SAndrei Vagin if (clockid == CLOCK_REALTIME) 27*a4fd8414SAndrei Vagin futex_op |= FUTEX_CLOCK_REALTIME; 28*a4fd8414SAndrei Vagin 29*a4fd8414SAndrei Vagin clock_gettime(clockid, &timeout); 30*a4fd8414SAndrei Vagin timeout.tv_nsec += NSEC_PER_SEC / 10; // 100ms 31*a4fd8414SAndrei Vagin if (timeout.tv_nsec > NSEC_PER_SEC) { 32*a4fd8414SAndrei Vagin timeout.tv_sec++; 33*a4fd8414SAndrei Vagin timeout.tv_nsec -= NSEC_PER_SEC; 34*a4fd8414SAndrei Vagin } 35*a4fd8414SAndrei Vagin 36*a4fd8414SAndrei Vagin if (syscall(__NR_futex, &val, futex_op, 0, 37*a4fd8414SAndrei Vagin &timeout, 0, FUTEX_BITSET_MATCH_ANY) >= 0) { 38*a4fd8414SAndrei Vagin ksft_test_result_fail("futex didn't return ETIMEDOUT\n"); 39*a4fd8414SAndrei Vagin return 1; 40*a4fd8414SAndrei Vagin } 41*a4fd8414SAndrei Vagin 42*a4fd8414SAndrei Vagin if (errno != ETIMEDOUT) { 43*a4fd8414SAndrei Vagin ksft_test_result_fail("futex didn't return ETIMEDOUT: %s\n", 44*a4fd8414SAndrei Vagin strerror(errno)); 45*a4fd8414SAndrei Vagin return 1; 46*a4fd8414SAndrei Vagin } 47*a4fd8414SAndrei Vagin 48*a4fd8414SAndrei Vagin clock_gettime(clockid, &end); 49*a4fd8414SAndrei Vagin 50*a4fd8414SAndrei Vagin if (end.tv_sec < timeout.tv_sec || 51*a4fd8414SAndrei Vagin (end.tv_sec == timeout.tv_sec && end.tv_nsec < timeout.tv_nsec)) { 52*a4fd8414SAndrei Vagin ksft_test_result_fail("futex slept less than 100ms\n"); 53*a4fd8414SAndrei Vagin return 1; 54*a4fd8414SAndrei Vagin } 55*a4fd8414SAndrei Vagin 56*a4fd8414SAndrei Vagin 57*a4fd8414SAndrei Vagin ksft_test_result_pass("futex with the %d clockid\n", clockid); 58*a4fd8414SAndrei Vagin 59*a4fd8414SAndrei Vagin return 0; 60*a4fd8414SAndrei Vagin } 61*a4fd8414SAndrei Vagin 62*a4fd8414SAndrei Vagin int main(int argc, char *argv[]) 63*a4fd8414SAndrei Vagin { 64*a4fd8414SAndrei Vagin int status, len, fd; 65*a4fd8414SAndrei Vagin char buf[4096]; 66*a4fd8414SAndrei Vagin pid_t pid; 67*a4fd8414SAndrei Vagin struct timespec mtime_now; 68*a4fd8414SAndrei Vagin 69*a4fd8414SAndrei Vagin nscheck(); 70*a4fd8414SAndrei Vagin 71*a4fd8414SAndrei Vagin ksft_set_plan(2); 72*a4fd8414SAndrei Vagin 73*a4fd8414SAndrei Vagin clock_gettime(CLOCK_MONOTONIC, &mtime_now); 74*a4fd8414SAndrei Vagin 75*a4fd8414SAndrei Vagin if (unshare_timens()) 76*a4fd8414SAndrei Vagin return 1; 77*a4fd8414SAndrei Vagin 78*a4fd8414SAndrei Vagin len = snprintf(buf, sizeof(buf), "%d %d 0", 79*a4fd8414SAndrei Vagin CLOCK_MONOTONIC, 70 * 24 * 3600); 80*a4fd8414SAndrei Vagin fd = open("/proc/self/timens_offsets", O_WRONLY); 81*a4fd8414SAndrei Vagin if (fd < 0) 82*a4fd8414SAndrei Vagin return pr_perror("/proc/self/timens_offsets"); 83*a4fd8414SAndrei Vagin 84*a4fd8414SAndrei Vagin if (write(fd, buf, len) != len) 85*a4fd8414SAndrei Vagin return pr_perror("/proc/self/timens_offsets"); 86*a4fd8414SAndrei Vagin 87*a4fd8414SAndrei Vagin close(fd); 88*a4fd8414SAndrei Vagin 89*a4fd8414SAndrei Vagin pid = fork(); 90*a4fd8414SAndrei Vagin if (pid < 0) 91*a4fd8414SAndrei Vagin return pr_perror("Unable to fork"); 92*a4fd8414SAndrei Vagin if (pid == 0) { 93*a4fd8414SAndrei Vagin int ret = 0; 94*a4fd8414SAndrei Vagin 95*a4fd8414SAndrei Vagin ret |= run_test(CLOCK_REALTIME); 96*a4fd8414SAndrei Vagin ret |= run_test(CLOCK_MONOTONIC); 97*a4fd8414SAndrei Vagin if (ret) 98*a4fd8414SAndrei Vagin ksft_exit_fail(); 99*a4fd8414SAndrei Vagin ksft_exit_pass(); 100*a4fd8414SAndrei Vagin return 0; 101*a4fd8414SAndrei Vagin } 102*a4fd8414SAndrei Vagin 103*a4fd8414SAndrei Vagin if (waitpid(pid, &status, 0) != pid) 104*a4fd8414SAndrei Vagin return pr_perror("Unable to wait the child process"); 105*a4fd8414SAndrei Vagin 106*a4fd8414SAndrei Vagin if (WIFEXITED(status)) 107*a4fd8414SAndrei Vagin return WEXITSTATUS(status); 108*a4fd8414SAndrei Vagin 109*a4fd8414SAndrei Vagin return 1; 110*a4fd8414SAndrei Vagin } 111