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