linux/tools/testing/selftests/timens/timerfd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3#include <sched.h>
   4
   5#include <sys/timerfd.h>
   6#include <sys/syscall.h>
   7#include <sys/types.h>
   8#include <sys/wait.h>
   9#include <time.h>
  10#include <unistd.h>
  11#include <stdlib.h>
  12#include <stdio.h>
  13#include <stdint.h>
  14
  15#include "log.h"
  16#include "timens.h"
  17
  18static int tclock_gettime(clock_t clockid, struct timespec *now)
  19{
  20        if (clockid == CLOCK_BOOTTIME_ALARM)
  21                clockid = CLOCK_BOOTTIME;
  22        return clock_gettime(clockid, now);
  23}
  24
  25int run_test(int clockid, struct timespec now)
  26{
  27        struct itimerspec new_value;
  28        long long elapsed;
  29        int fd, i;
  30
  31        if (check_skip(clockid))
  32                return 0;
  33
  34        if (tclock_gettime(clockid, &now))
  35                return pr_perror("clock_gettime(%d)", clockid);
  36
  37        for (i = 0; i < 2; i++) {
  38                int flags = 0;
  39
  40                new_value.it_value.tv_sec = 3600;
  41                new_value.it_value.tv_nsec = 0;
  42                new_value.it_interval.tv_sec = 1;
  43                new_value.it_interval.tv_nsec = 0;
  44
  45                if (i == 1) {
  46                        new_value.it_value.tv_sec += now.tv_sec;
  47                        new_value.it_value.tv_nsec += now.tv_nsec;
  48                }
  49
  50                fd = timerfd_create(clockid, 0);
  51                if (fd == -1)
  52                        return pr_perror("timerfd_create(%d)", clockid);
  53
  54                if (i == 1)
  55                        flags |= TFD_TIMER_ABSTIME;
  56
  57                if (timerfd_settime(fd, flags, &new_value, NULL))
  58                        return pr_perror("timerfd_settime(%d)", clockid);
  59
  60                if (timerfd_gettime(fd, &new_value))
  61                        return pr_perror("timerfd_gettime(%d)", clockid);
  62
  63                elapsed = new_value.it_value.tv_sec;
  64                if (abs(elapsed - 3600) > 60) {
  65                        ksft_test_result_fail("clockid: %d elapsed: %lld\n",
  66                                              clockid, elapsed);
  67                        return 1;
  68                }
  69
  70                close(fd);
  71        }
  72
  73        ksft_test_result_pass("clockid=%d\n", clockid);
  74
  75        return 0;
  76}
  77
  78int main(int argc, char *argv[])
  79{
  80        int ret, status, len, fd;
  81        char buf[4096];
  82        pid_t pid;
  83        struct timespec btime_now, mtime_now;
  84
  85        nscheck();
  86
  87        check_supported_timers();
  88
  89        ksft_set_plan(3);
  90
  91        clock_gettime(CLOCK_MONOTONIC, &mtime_now);
  92        clock_gettime(CLOCK_BOOTTIME, &btime_now);
  93
  94        if (unshare_timens())
  95                return 1;
  96
  97        len = snprintf(buf, sizeof(buf), "%d %d 0\n%d %d 0",
  98                        CLOCK_MONOTONIC, 70 * 24 * 3600,
  99                        CLOCK_BOOTTIME, 9 * 24 * 3600);
 100        fd = open("/proc/self/timens_offsets", O_WRONLY);
 101        if (fd < 0)
 102                return pr_perror("/proc/self/timens_offsets");
 103
 104        if (write(fd, buf, len) != len)
 105                return pr_perror("/proc/self/timens_offsets");
 106
 107        close(fd);
 108        mtime_now.tv_sec += 70 * 24 * 3600;
 109        btime_now.tv_sec += 9 * 24 * 3600;
 110
 111        pid = fork();
 112        if (pid < 0)
 113                return pr_perror("Unable to fork");
 114        if (pid == 0) {
 115                ret = 0;
 116                ret |= run_test(CLOCK_BOOTTIME, btime_now);
 117                ret |= run_test(CLOCK_MONOTONIC, mtime_now);
 118                ret |= run_test(CLOCK_BOOTTIME_ALARM, btime_now);
 119
 120                if (ret)
 121                        ksft_exit_fail();
 122                ksft_exit_pass();
 123                return ret;
 124        }
 125
 126        if (waitpid(pid, &status, 0) != pid)
 127                return pr_perror("Unable to wait the child process");
 128
 129        if (WIFEXITED(status))
 130                return WEXITSTATUS(status);
 131
 132        return 1;
 133}
 134