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
run_test(int clockid)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
main(int argc,char * argv[])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