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 timeval_to_ns(const struct timeval *tv) 22 { 23 return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + 24 tv->tv_usec * UM_NSEC_PER_USEC; 25 } 26 27 static inline long long timespec_to_ns(const struct timespec *ts) 28 { 29 return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec; 30 } 31 32 long long os_persistent_clock_emulation(void) 33 { 34 struct timespec realtime_tp; 35 36 clock_gettime(CLOCK_REALTIME, &realtime_tp); 37 return timespec_to_ns(&realtime_tp); 38 } 39 40 /** 41 * os_timer_create() - create an new posix (interval) timer 42 */ 43 int os_timer_create(void) 44 { 45 timer_t *t = &event_high_res_timer; 46 47 if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 48 return -1; 49 50 return 0; 51 } 52 53 int os_timer_set_interval(unsigned long long nsecs) 54 { 55 struct itimerspec its; 56 57 its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC; 58 its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC; 59 60 its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 61 its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 62 63 if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 64 return -errno; 65 66 return 0; 67 } 68 69 int os_timer_one_shot(unsigned long long nsecs) 70 { 71 struct itimerspec its = { 72 .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, 73 .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC, 74 75 .it_interval.tv_sec = 0, 76 .it_interval.tv_nsec = 0, // we cheat here 77 }; 78 79 timer_settime(event_high_res_timer, 0, &its, NULL); 80 return 0; 81 } 82 83 /** 84 * os_timer_disable() - disable the posix (interval) timer 85 */ 86 void os_timer_disable(void) 87 { 88 struct itimerspec its; 89 90 memset(&its, 0, sizeof(struct itimerspec)); 91 timer_settime(event_high_res_timer, 0, &its, NULL); 92 } 93 94 long long os_nsecs(void) 95 { 96 struct timespec ts; 97 98 clock_gettime(CLOCK_MONOTONIC,&ts); 99 return timespec_to_ns(&ts); 100 } 101 102 /** 103 * os_idle_sleep() - sleep until interrupted 104 */ 105 void os_idle_sleep(void) 106 { 107 struct itimerspec its; 108 sigset_t set, old; 109 110 /* block SIGALRM while we analyze the timer state */ 111 sigemptyset(&set); 112 sigaddset(&set, SIGALRM); 113 sigprocmask(SIG_BLOCK, &set, &old); 114 115 /* check the timer, and if it'll fire then wait for it */ 116 timer_gettime(event_high_res_timer, &its); 117 if (its.it_value.tv_sec || its.it_value.tv_nsec) 118 sigsuspend(&old); 119 /* either way, restore the signal mask */ 120 sigprocmask(SIG_UNBLOCK, &set, NULL); 121 } 122