linux/tools/testing/selftests/timens/futex.c
<<
>>
Prefs
   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}
 111