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

source code of linux/tools/testing/selftests/timens/futex.c