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