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 <errno.h> 11 #include <signal.h> 12 #include <time.h> 13 #include <sys/time.h> 14 #include <kern_util.h> 15 #include <os.h> 16 #include <string.h> 17 18 static timer_t event_high_res_timer = 0; 19 20 static inline long long timeval_to_ns(const struct timeval *tv) 21 { 22 return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + 23 tv->tv_usec * UM_NSEC_PER_USEC; 24 } 25 26 static inline long long timespec_to_ns(const struct timespec *ts) 27 { 28 return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec; 29 } 30 31 long long os_persistent_clock_emulation(void) 32 { 33 struct timespec realtime_tp; 34 35 clock_gettime(CLOCK_REALTIME, &realtime_tp); 36 return timespec_to_ns(&realtime_tp); 37 } 38 39 /** 40 * os_timer_create() - create an new posix (interval) timer 41 */ 42 int os_timer_create(void) 43 { 44 timer_t *t = &event_high_res_timer; 45 46 if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 47 return -1; 48 49 return 0; 50 } 51 52 int os_timer_set_interval(unsigned long long nsecs) 53 { 54 struct itimerspec its; 55 56 its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC; 57 its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC; 58 59 its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 60 its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 61 62 if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 63 return -errno; 64 65 return 0; 66 } 67 68 int os_timer_one_shot(unsigned long long nsecs) 69 { 70 struct itimerspec its = { 71 .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, 72 .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC, 73 74 .it_interval.tv_sec = 0, 75 .it_interval.tv_nsec = 0, // we cheat here 76 }; 77 78 timer_settime(event_high_res_timer, 0, &its, NULL); 79 return 0; 80 } 81 82 /** 83 * os_timer_disable() - disable the posix (interval) timer 84 */ 85 void os_timer_disable(void) 86 { 87 struct itimerspec its; 88 89 memset(&its, 0, sizeof(struct itimerspec)); 90 timer_settime(event_high_res_timer, 0, &its, NULL); 91 } 92 93 long long os_nsecs(void) 94 { 95 struct timespec ts; 96 97 clock_gettime(CLOCK_MONOTONIC,&ts); 98 return timespec_to_ns(&ts); 99 } 100 101 /** 102 * os_idle_sleep() - sleep for a given time of nsecs 103 * @nsecs: nanoseconds to sleep 104 */ 105 void os_idle_sleep(unsigned long long nsecs) 106 { 107 struct timespec ts = { 108 .tv_sec = nsecs / UM_NSEC_PER_SEC, 109 .tv_nsec = nsecs % UM_NSEC_PER_SEC 110 }; 111 112 /* 113 * Relay the signal if clock_nanosleep is interrupted. 114 */ 115 if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) 116 deliver_alarm(); 117 } 118