162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
462306a36Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
562306a36Sopenharmony_ci * Copyright (C) 2012-2014 Cisco Systems
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <stddef.h>
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <signal.h>
1362306a36Sopenharmony_ci#include <time.h>
1462306a36Sopenharmony_ci#include <sys/time.h>
1562306a36Sopenharmony_ci#include <kern_util.h>
1662306a36Sopenharmony_ci#include <os.h>
1762306a36Sopenharmony_ci#include <string.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic timer_t event_high_res_timer = 0;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic inline long long timespec_to_ns(const struct timespec *ts)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cilong long os_persistent_clock_emulation(void)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct timespec realtime_tp;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	clock_gettime(CLOCK_REALTIME, &realtime_tp);
3162306a36Sopenharmony_ci	return timespec_to_ns(&realtime_tp);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * os_timer_create() - create an new posix (interval) timer
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ciint os_timer_create(void)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	timer_t *t = &event_high_res_timer;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1)
4262306a36Sopenharmony_ci		return -1;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return 0;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciint os_timer_set_interval(unsigned long long nsecs)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct itimerspec its;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
5262306a36Sopenharmony_ci	its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
5562306a36Sopenharmony_ci	its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1)
5862306a36Sopenharmony_ci		return -errno;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciint os_timer_one_shot(unsigned long long nsecs)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct itimerspec its = {
6662306a36Sopenharmony_ci		.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
6762306a36Sopenharmony_ci		.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		.it_interval.tv_sec = 0,
7062306a36Sopenharmony_ci		.it_interval.tv_nsec = 0, // we cheat here
7162306a36Sopenharmony_ci	};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	timer_settime(event_high_res_timer, 0, &its, NULL);
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/**
7862306a36Sopenharmony_ci * os_timer_disable() - disable the posix (interval) timer
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_civoid os_timer_disable(void)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct itimerspec its;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	memset(&its, 0, sizeof(struct itimerspec));
8562306a36Sopenharmony_ci	timer_settime(event_high_res_timer, 0, &its, NULL);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cilong long os_nsecs(void)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct timespec ts;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC,&ts);
9362306a36Sopenharmony_ci	return timespec_to_ns(&ts);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/**
9762306a36Sopenharmony_ci * os_idle_sleep() - sleep until interrupted
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_civoid os_idle_sleep(void)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct itimerspec its;
10262306a36Sopenharmony_ci	sigset_t set, old;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* block SIGALRM while we analyze the timer state */
10562306a36Sopenharmony_ci	sigemptyset(&set);
10662306a36Sopenharmony_ci	sigaddset(&set, SIGALRM);
10762306a36Sopenharmony_ci	sigprocmask(SIG_BLOCK, &set, &old);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* check the timer, and if it'll fire then wait for it */
11062306a36Sopenharmony_ci	timer_gettime(event_high_res_timer, &its);
11162306a36Sopenharmony_ci	if (its.it_value.tv_sec || its.it_value.tv_nsec)
11262306a36Sopenharmony_ci		sigsuspend(&old);
11362306a36Sopenharmony_ci	/* either way, restore the signal mask */
11462306a36Sopenharmony_ci	sigprocmask(SIG_UNBLOCK, &set, NULL);
11562306a36Sopenharmony_ci}
116