Line data Source code
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 774 : return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec; 24 : } 25 : 26 1 : long long os_persistent_clock_emulation(void) 27 : { 28 : struct timespec realtime_tp; 29 : 30 1 : clock_gettime(CLOCK_REALTIME, &realtime_tp); 31 1 : return timespec_to_ns(&realtime_tp); 32 : } 33 : 34 : /** 35 : * os_timer_create() - create an new posix (interval) timer 36 : */ 37 1 : int os_timer_create(void) 38 : { 39 1 : timer_t *t = &event_high_res_timer; 40 : 41 1 : if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 42 : return -1; 43 : 44 1 : return 0; 45 : } 46 : 47 1 : int os_timer_set_interval(unsigned long long nsecs) 48 : { 49 : struct itimerspec its; 50 : 51 1 : its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC; 52 1 : its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC; 53 : 54 1 : its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 55 1 : its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 56 : 57 1 : if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 58 0 : return -errno; 59 : 60 : return 0; 61 : } 62 : 63 0 : int os_timer_one_shot(unsigned long long nsecs) 64 : { 65 0 : struct itimerspec its = { 66 0 : .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, 67 0 : .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 0 : timer_settime(event_high_res_timer, 0, &its, NULL); 74 0 : return 0; 75 : } 76 : 77 : /** 78 : * os_timer_disable() - disable the posix (interval) timer 79 : */ 80 2 : void os_timer_disable(void) 81 : { 82 : struct itimerspec its; 83 : 84 2 : memset(&its, 0, sizeof(struct itimerspec)); 85 2 : timer_settime(event_high_res_timer, 0, &its, NULL); 86 2 : } 87 : 88 773 : long long os_nsecs(void) 89 : { 90 : struct timespec ts; 91 : 92 773 : clock_gettime(CLOCK_MONOTONIC,&ts); 93 773 : return timespec_to_ns(&ts); 94 : } 95 : 96 : /** 97 : * os_idle_sleep() - sleep until interrupted 98 : */ 99 0 : 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 0 : sigemptyset(&set); 106 0 : sigaddset(&set, SIGALRM); 107 0 : sigprocmask(SIG_BLOCK, &set, &old); 108 : 109 : /* check the timer, and if it'll fire then wait for it */ 110 0 : timer_gettime(event_high_res_timer, &its); 111 0 : if (its.it_value.tv_sec || its.it_value.tv_nsec) 112 0 : sigsuspend(&old); 113 : /* either way, restore the signal mask */ 114 0 : sigprocmask(SIG_UNBLOCK, &set, NULL); 115 0 : }