Commit | Line | Data |
---|---|---|
cff65c4f | 1 | /* |
2eb5f31b AI |
2 | * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) |
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | |
4 | * Copyright (C) 2012-2014 Cisco Systems | |
4c9e1385 | 5 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) |
cff65c4f GS |
6 | * Licensed under the GPL |
7 | */ | |
8 | ||
4c9e1385 JD |
9 | #include <stddef.h> |
10 | #include <errno.h> | |
11 | #include <signal.h> | |
cff65c4f | 12 | #include <time.h> |
1da177e4 | 13 | #include <sys/time.h> |
37185b33 AV |
14 | #include <kern_util.h> |
15 | #include <os.h> | |
2eb5f31b AI |
16 | #include <string.h> |
17 | #include <timer-internal.h> | |
cff65c4f | 18 | |
2eb5f31b | 19 | static timer_t event_high_res_timer = 0; |
537ae946 | 20 | |
2eb5f31b AI |
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; | |
cff65c4f GS |
25 | } |
26 | ||
2eb5f31b | 27 | static inline long long timespec_to_ns(const struct timespec *ts) |
d2753a6d | 28 | { |
2eb5f31b AI |
29 | return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + |
30 | ts->tv_nsec; | |
31 | } | |
d2753a6d | 32 | |
2eb5f31b AI |
33 | long long os_persistent_clock_emulation (void) { |
34 | struct timespec realtime_tp; | |
d2753a6d | 35 | |
2eb5f31b AI |
36 | clock_gettime(CLOCK_REALTIME, &realtime_tp); |
37 | return timespec_to_ns(&realtime_tp); | |
d2753a6d JD |
38 | } |
39 | ||
5f734614 | 40 | /** |
2eb5f31b | 41 | * os_timer_create() - create an new posix (interval) timer |
5f734614 | 42 | */ |
2eb5f31b AI |
43 | int os_timer_create(void* timer) { |
44 | ||
45 | timer_t* t = timer; | |
46 | ||
47 | if(t == NULL) { | |
48 | t = &event_high_res_timer; | |
49 | } | |
50 | ||
51 | if (timer_create( | |
52 | CLOCK_MONOTONIC, | |
53 | NULL, | |
54 | t) == -1) { | |
55 | return -1; | |
56 | } | |
57 | return 0; | |
5f734614 JD |
58 | } |
59 | ||
2eb5f31b | 60 | int os_timer_set_interval(void* timer, void* i) |
cff65c4f | 61 | { |
2eb5f31b AI |
62 | struct itimerspec its; |
63 | unsigned long long nsec; | |
64 | timer_t* t = timer; | |
65 | struct itimerspec* its_in = i; | |
4c9e1385 | 66 | |
2eb5f31b AI |
67 | if(t == NULL) { |
68 | t = &event_high_res_timer; | |
69 | } | |
181bde80 | 70 | |
2eb5f31b | 71 | nsec = UM_NSEC_PER_SEC / UM_HZ; |
fe2cc53e | 72 | |
2eb5f31b AI |
73 | if(its_in != NULL) { |
74 | its.it_value.tv_sec = its_in->it_value.tv_sec; | |
75 | its.it_value.tv_nsec = its_in->it_value.tv_nsec; | |
76 | } else { | |
77 | its.it_value.tv_sec = 0; | |
78 | its.it_value.tv_nsec = nsec; | |
79 | } | |
1da177e4 | 80 | |
2eb5f31b AI |
81 | its.it_interval.tv_sec = 0; |
82 | its.it_interval.tv_nsec = nsec; | |
1da177e4 | 83 | |
2eb5f31b AI |
84 | if(timer_settime(*t, 0, &its, NULL) == -1) { |
85 | return -errno; | |
86 | } | |
1da177e4 | 87 | |
0a765329 | 88 | return 0; |
364e3a3d | 89 | } |
fe2cc53e | 90 | |
2eb5f31b AI |
91 | /** |
92 | * os_timer_remain() - returns the remaining nano seconds of the given interval | |
93 | * timer | |
94 | * Because this is the remaining time of an interval timer, which correspondends | |
95 | * to HZ, this value can never be bigger than one second. Just | |
96 | * the nanosecond part of the timer is returned. | |
97 | * The returned time is relative to the start time of the interval timer. | |
98 | * Return an negative value in an error case. | |
99 | */ | |
100 | long os_timer_remain(void* timer) | |
fe2cc53e | 101 | { |
2eb5f31b AI |
102 | struct itimerspec its; |
103 | timer_t* t = timer; | |
fe2cc53e | 104 | |
2eb5f31b AI |
105 | if(t == NULL) { |
106 | t = &event_high_res_timer; | |
107 | } | |
fe2cc53e | 108 | |
2eb5f31b AI |
109 | if(timer_gettime(t, &its) == -1) { |
110 | return -errno; | |
111 | } | |
fe2cc53e | 112 | |
2eb5f31b AI |
113 | return its.it_value.tv_nsec; |
114 | } | |
fe2cc53e | 115 | |
2eb5f31b AI |
116 | int os_timer_one_shot(int ticks) |
117 | { | |
118 | struct itimerspec its; | |
119 | unsigned long long nsec; | |
120 | unsigned long sec; | |
06e1e4ff | 121 | |
2eb5f31b AI |
122 | nsec = (ticks + 1); |
123 | sec = nsec / UM_NSEC_PER_SEC; | |
124 | nsec = nsec % UM_NSEC_PER_SEC; | |
fe2cc53e | 125 | |
2eb5f31b AI |
126 | its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC; |
127 | its.it_value.tv_nsec = nsec; | |
fe2cc53e | 128 | |
2eb5f31b AI |
129 | its.it_interval.tv_sec = 0; |
130 | its.it_interval.tv_nsec = 0; // we cheat here | |
fe2cc53e | 131 | |
2eb5f31b AI |
132 | timer_settime(event_high_res_timer, 0, &its, NULL); |
133 | return 0; | |
fe2cc53e JD |
134 | } |
135 | ||
2eb5f31b AI |
136 | /** |
137 | * os_timer_disable() - disable the posix (interval) timer | |
138 | * Returns the remaining interval timer time in nanoseconds | |
139 | */ | |
140 | long long os_timer_disable(void) | |
fe2cc53e | 141 | { |
2eb5f31b | 142 | struct itimerspec its; |
fe2cc53e | 143 | |
2eb5f31b AI |
144 | memset(&its, 0, sizeof(struct itimerspec)); |
145 | timer_settime(event_high_res_timer, 0, &its, &its); | |
146 | ||
147 | return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec; | |
364e3a3d JD |
148 | } |
149 | ||
2eb5f31b | 150 | long long os_vnsecs(void) |
364e3a3d | 151 | { |
2eb5f31b | 152 | struct timespec ts; |
06e1e4ff | 153 | |
2eb5f31b AI |
154 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts); |
155 | return timespec_to_ns(&ts); | |
156 | } | |
364e3a3d | 157 | |
2eb5f31b AI |
158 | long long os_nsecs(void) |
159 | { | |
160 | struct timespec ts; | |
364e3a3d | 161 | |
2eb5f31b AI |
162 | clock_gettime(CLOCK_MONOTONIC,&ts); |
163 | return timespec_to_ns(&ts); | |
364e3a3d | 164 | } |
364e3a3d | 165 | |
2eb5f31b AI |
166 | /** |
167 | * os_idle_sleep() - sleep for a given time of nsecs | |
168 | * @nsecs: nanoseconds to sleep | |
169 | */ | |
170 | void os_idle_sleep(unsigned long long nsecs) | |
cff65c4f | 171 | { |
364e3a3d JD |
172 | struct timespec ts; |
173 | ||
2eb5f31b AI |
174 | if (nsecs <= 0) { |
175 | return; | |
176 | } | |
fe2cc53e | 177 | |
2eb5f31b AI |
178 | ts = ((struct timespec) { |
179 | .tv_sec = nsecs / UM_NSEC_PER_SEC, | |
180 | .tv_nsec = nsecs % UM_NSEC_PER_SEC | |
181 | }); | |
cff65c4f | 182 | |
2eb5f31b AI |
183 | /* |
184 | * Relay the signal if clock_nanosleep is interrupted. | |
185 | */ | |
186 | if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) { | |
fe2cc53e | 187 | deliver_alarm(); |
2eb5f31b | 188 | } |
cff65c4f | 189 | } |