futex.c (2235B)
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("futex didn't return ETIMEDOUT\n"); 39 return 1; 40 } 41 42 if (errno != ETIMEDOUT) { 43 ksft_test_result_fail("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("futex slept less than 100ms\n"); 53 return 1; 54 } 55 56 57 ksft_test_result_pass("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(2); 72 73 clock_gettime(CLOCK_MONOTONIC, &mtime_now); 74 75 if (unshare_timens()) 76 return 1; 77 78 len = snprintf(buf, sizeof(buf), "%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}