111 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#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 1000000000ULL19 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; // 100ms31 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}111