1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) 4 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 5 * Copyright (C) 2012-2014 Cisco Systems 6 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) 7 */ 8 9 #include <stddef.h> 10 #include <unistd.h> 11 #include <errno.h> 12 #include <signal.h> 13 #include <time.h> 14 #include <sys/time.h> 15 #include <kern_util.h> 16 #include <os.h> 17 #include <string.h> 18 19 static timer_t event_high_res_timer = 0; 20 21 static inline long long timespec_to_ns(const struct timespec *ts) 22 { 23 return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec; 24 } 25 26 long long os_persistent_clock_emulation(void) 27 { 28 struct timespec realtime_tp; 29 30 clock_gettime(CLOCK_REALTIME, &realtime_tp); 31 return timespec_to_ns(&realtime_tp); 32 } 33 34 /** 35 * os_timer_create() - create an new posix (interval) timer 36 */ 37 int os_timer_create(void) 38 { 39 timer_t *t = &event_high_res_timer; 40 41 if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 42 return -1; 43 44 return 0; 45 } 46 47 int os_timer_set_interval(unsigned long long nsecs) 48 { 49 struct itimerspec its; 50 51 its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC; 52 its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC; 53 54 its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 55 its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 56 57 if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 58 return -errno; 59 60 return 0; 61 } 62 63 int os_timer_one_shot(unsigned long long nsecs) 64 { 65 struct itimerspec its = { 66 .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, 67 .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC, 68 69 .it_interval.tv_sec = 0, 70 .it_interval.tv_nsec = 0, // we cheat here 71 }; 72 73 timer_settime(event_high_res_timer, 0, &its, NULL); 74 return 0; 75 } 76 77 /** 78 * os_timer_disable() - disable the posix (interval) timer 79 */ 80 void os_timer_disable(void) 81 { 82 struct itimerspec its; 83 84 memset(&its, 0, sizeof(struct itimerspec)); 85 timer_settime(event_high_res_timer, 0, &its, NULL); 86 } 87 88 long long os_nsecs(void) 89 { 90 struct timespec ts; 91 92 clock_gettime(CLOCK_MONOTONIC,&ts); 93 return timespec_to_ns(&ts); 94 } 95 96 /** 97 * os_idle_sleep() - sleep until interrupted 98 */ 99 void os_idle_sleep(void) 100 { 101 struct itimerspec its; 102 sigset_t set, old; 103 104 /* block SIGALRM while we analyze the timer state */ 105 sigemptyset(&set); 106 sigaddset(&set, SIGALRM); 107 sigprocmask(SIG_BLOCK, &set, &old); 108 109 /* check the timer, and if it'll fire then wait for it */ 110 timer_gettime(event_high_res_timer, &its); 111 if (its.it_value.tv_sec || its.it_value.tv_nsec) 112 sigsuspend(&old); 113 /* either way, restore the signal mask */ 114 sigprocmask(SIG_UNBLOCK, &set, NULL); 115 } 116