18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#define _GNU_SOURCE 38c2ecf20Sopenharmony_ci#include <sched.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <sys/timerfd.h> 68c2ecf20Sopenharmony_ci#include <sys/syscall.h> 78c2ecf20Sopenharmony_ci#include <time.h> 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <stdio.h> 118c2ecf20Sopenharmony_ci#include <stdint.h> 128c2ecf20Sopenharmony_ci#include <pthread.h> 138c2ecf20Sopenharmony_ci#include <signal.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "log.h" 178c2ecf20Sopenharmony_ci#include "timens.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_civoid test_sig(int sig) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci if (sig == SIGUSR2) 228c2ecf20Sopenharmony_ci pthread_exit(NULL); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct thread_args { 268c2ecf20Sopenharmony_ci struct timespec *now, *rem; 278c2ecf20Sopenharmony_ci pthread_mutex_t *lock; 288c2ecf20Sopenharmony_ci int clockid; 298c2ecf20Sopenharmony_ci int abs; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid *call_nanosleep(void *_args) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct thread_args *args = _args; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci clock_nanosleep(args->clockid, args->abs ? TIMER_ABSTIME : 0, args->now, args->rem); 378c2ecf20Sopenharmony_ci pthread_mutex_unlock(args->lock); 388c2ecf20Sopenharmony_ci return NULL; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint run_test(int clockid, int abs) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct timespec now = {}, rem; 448c2ecf20Sopenharmony_ci struct thread_args args = { .now = &now, .rem = &rem, .clockid = clockid}; 458c2ecf20Sopenharmony_ci struct timespec start; 468c2ecf20Sopenharmony_ci pthread_mutex_t lock; 478c2ecf20Sopenharmony_ci pthread_t thread; 488c2ecf20Sopenharmony_ci int j, ok, ret; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci signal(SIGUSR1, test_sig); 518c2ecf20Sopenharmony_ci signal(SIGUSR2, test_sig); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci pthread_mutex_init(&lock, NULL); 548c2ecf20Sopenharmony_ci pthread_mutex_lock(&lock); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (clock_gettime(clockid, &start) == -1) { 578c2ecf20Sopenharmony_ci if (errno == EINVAL && check_skip(clockid)) 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci return pr_perror("clock_gettime"); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (abs) { 648c2ecf20Sopenharmony_ci now.tv_sec = start.tv_sec; 658c2ecf20Sopenharmony_ci now.tv_nsec = start.tv_nsec; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci now.tv_sec += 3600; 698c2ecf20Sopenharmony_ci args.abs = abs; 708c2ecf20Sopenharmony_ci args.lock = &lock; 718c2ecf20Sopenharmony_ci ret = pthread_create(&thread, NULL, call_nanosleep, &args); 728c2ecf20Sopenharmony_ci if (ret != 0) { 738c2ecf20Sopenharmony_ci pr_err("Unable to create a thread: %s", strerror(ret)); 748c2ecf20Sopenharmony_ci return 1; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Wait when the thread will call clock_nanosleep(). */ 788c2ecf20Sopenharmony_ci ok = 0; 798c2ecf20Sopenharmony_ci for (j = 0; j < 8; j++) { 808c2ecf20Sopenharmony_ci /* The maximum timeout is about 5 seconds. */ 818c2ecf20Sopenharmony_ci usleep(10000 << j); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Try to interrupt clock_nanosleep(). */ 848c2ecf20Sopenharmony_ci pthread_kill(thread, SIGUSR1); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci usleep(10000 << j); 878c2ecf20Sopenharmony_ci /* Check whether clock_nanosleep() has been interrupted or not. */ 888c2ecf20Sopenharmony_ci if (pthread_mutex_trylock(&lock) == 0) { 898c2ecf20Sopenharmony_ci /**/ 908c2ecf20Sopenharmony_ci ok = 1; 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci if (!ok) 958c2ecf20Sopenharmony_ci pthread_kill(thread, SIGUSR2); 968c2ecf20Sopenharmony_ci pthread_join(thread, NULL); 978c2ecf20Sopenharmony_ci pthread_mutex_destroy(&lock); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!ok) { 1008c2ecf20Sopenharmony_ci ksft_test_result_pass("clockid: %d abs:%d timeout\n", clockid, abs); 1018c2ecf20Sopenharmony_ci return 1; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (rem.tv_sec < 3300 || rem.tv_sec > 3900) { 1058c2ecf20Sopenharmony_ci pr_fail("clockid: %d abs: %d remain: %ld\n", 1068c2ecf20Sopenharmony_ci clockid, abs, rem.tv_sec); 1078c2ecf20Sopenharmony_ci return 1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci ksft_test_result_pass("clockid: %d abs:%d\n", clockid, abs); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci int ret, nsfd; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci nscheck(); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ksft_set_plan(4); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci check_supported_timers(); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (unshare_timens()) 1258c2ecf20Sopenharmony_ci return 1; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (_settime(CLOCK_MONOTONIC, 7 * 24 * 3600)) 1288c2ecf20Sopenharmony_ci return 1; 1298c2ecf20Sopenharmony_ci if (_settime(CLOCK_BOOTTIME, 9 * 24 * 3600)) 1308c2ecf20Sopenharmony_ci return 1; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); 1338c2ecf20Sopenharmony_ci if (nsfd < 0) 1348c2ecf20Sopenharmony_ci return pr_perror("Unable to open timens_for_children"); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (setns(nsfd, CLONE_NEWTIME)) 1378c2ecf20Sopenharmony_ci return pr_perror("Unable to set timens"); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci ret = 0; 1408c2ecf20Sopenharmony_ci ret |= run_test(CLOCK_MONOTONIC, 0); 1418c2ecf20Sopenharmony_ci ret |= run_test(CLOCK_MONOTONIC, 1); 1428c2ecf20Sopenharmony_ci ret |= run_test(CLOCK_BOOTTIME_ALARM, 0); 1438c2ecf20Sopenharmony_ci ret |= run_test(CLOCK_BOOTTIME_ALARM, 1); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (ret) 1468c2ecf20Sopenharmony_ci ksft_exit_fail(); 1478c2ecf20Sopenharmony_ci ksft_exit_pass(); 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 150