Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE #include <sched.h> #include <sys/timerfd.h> #include <sys/syscall.h> #include <time.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <pthread.h> #include <signal.h> #include <string.h> #include "log.h" #include "timens.h" void test_sig(int sig) { if (sig == SIGUSR2) pthread_exit(NULL); } struct thread_args { struct timespec *now, *rem; pthread_mutex_t *lock; int clockid; int abs; }; void *call_nanosleep(void *_args) { struct thread_args *args = _args; clock_nanosleep(args->clockid, args->abs ? TIMER_ABSTIME : 0, args->now, args->rem); pthread_mutex_unlock(args->lock); return NULL; } int run_test(int clockid, int abs) { struct timespec now = {}, rem; struct thread_args args = { .now = &now, .rem = &rem, .clockid = clockid}; struct timespec start; pthread_mutex_t lock; pthread_t thread; int j, ok, ret; signal(SIGUSR1, test_sig); signal(SIGUSR2, test_sig); pthread_mutex_init(&lock, NULL); pthread_mutex_lock(&lock); if (clock_gettime(clockid, &start) == -1) { if (errno == EINVAL && check_skip(clockid)) return 0; return pr_perror("clock_gettime"); } if (abs) { now.tv_sec = start.tv_sec; now.tv_nsec = start.tv_nsec; } now.tv_sec += 3600; args.abs = abs; args.lock = &lock; ret = pthread_create(&thread, NULL, call_nanosleep, &args); if (ret != 0) { pr_err("Unable to create a thread: %s", strerror(ret)); return 1; } /* Wait when the thread will call clock_nanosleep(). */ ok = 0; for (j = 0; j < 8; j++) { /* The maximum timeout is about 5 seconds. */ usleep(10000 << j); /* Try to interrupt clock_nanosleep(). */ pthread_kill(thread, SIGUSR1); usleep(10000 << j); /* Check whether clock_nanosleep() has been interrupted or not. */ if (pthread_mutex_trylock(&lock) == 0) { /**/ ok = 1; break; } } if (!ok) pthread_kill(thread, SIGUSR2); pthread_join(thread, NULL); pthread_mutex_destroy(&lock); if (!ok) { ksft_test_result_pass("clockid: %d abs:%d timeout\n", clockid, abs); return 1; } if (rem.tv_sec < 3300 || rem.tv_sec > 3900) { pr_fail("clockid: %d abs: %d remain: %ld\n", clockid, abs, rem.tv_sec); return 1; } ksft_test_result_pass("clockid: %d abs:%d\n", clockid, abs); return 0; } int main(int argc, char *argv[]) { int ret, nsfd; nscheck(); ksft_set_plan(4); check_supported_timers(); if (unshare_timens()) return 1; if (_settime(CLOCK_MONOTONIC, 7 * 24 * 3600)) return 1; if (_settime(CLOCK_BOOTTIME, 9 * 24 * 3600)) return 1; nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); if (nsfd < 0) return pr_perror("Unable to open timens_for_children"); if (setns(nsfd, CLONE_NEWTIME)) return pr_perror("Unable to set timens"); ret = 0; ret |= run_test(CLOCK_MONOTONIC, 0); ret |= run_test(CLOCK_MONOTONIC, 1); ret |= run_test(CLOCK_BOOTTIME_ALARM, 0); ret |= run_test(CLOCK_BOOTTIME_ALARM, 1); if (ret) ksft_exit_fail(); ksft_exit_pass(); return ret; } |