123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // 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;
- }
|