root / qemu-timer.c @ 8cfd0495
History | View | Annotate | Download (12.6 kB)
1 | db1a4972 | Paolo Bonzini | /*
|
---|---|---|---|
2 | db1a4972 | Paolo Bonzini | * QEMU System Emulator
|
3 | db1a4972 | Paolo Bonzini | *
|
4 | db1a4972 | Paolo Bonzini | * Copyright (c) 2003-2008 Fabrice Bellard
|
5 | db1a4972 | Paolo Bonzini | *
|
6 | db1a4972 | Paolo Bonzini | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | db1a4972 | Paolo Bonzini | * of this software and associated documentation files (the "Software"), to deal
|
8 | db1a4972 | Paolo Bonzini | * in the Software without restriction, including without limitation the rights
|
9 | db1a4972 | Paolo Bonzini | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | db1a4972 | Paolo Bonzini | * copies of the Software, and to permit persons to whom the Software is
|
11 | db1a4972 | Paolo Bonzini | * furnished to do so, subject to the following conditions:
|
12 | db1a4972 | Paolo Bonzini | *
|
13 | db1a4972 | Paolo Bonzini | * The above copyright notice and this permission notice shall be included in
|
14 | db1a4972 | Paolo Bonzini | * all copies or substantial portions of the Software.
|
15 | db1a4972 | Paolo Bonzini | *
|
16 | db1a4972 | Paolo Bonzini | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | db1a4972 | Paolo Bonzini | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | db1a4972 | Paolo Bonzini | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | db1a4972 | Paolo Bonzini | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | db1a4972 | Paolo Bonzini | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | db1a4972 | Paolo Bonzini | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | db1a4972 | Paolo Bonzini | * THE SOFTWARE.
|
23 | db1a4972 | Paolo Bonzini | */
|
24 | db1a4972 | Paolo Bonzini | |
25 | 9c17d615 | Paolo Bonzini | #include "sysemu/sysemu.h" |
26 | 83c9089e | Paolo Bonzini | #include "monitor/monitor.h" |
27 | 28ecbaee | Paolo Bonzini | #include "ui/console.h" |
28 | db1a4972 | Paolo Bonzini | |
29 | db1a4972 | Paolo Bonzini | #include "hw/hw.h" |
30 | db1a4972 | Paolo Bonzini | |
31 | 1de7afc9 | Paolo Bonzini | #include "qemu/timer.h" |
32 | 30ea8339 | Anthony Liguori | #ifdef CONFIG_POSIX
|
33 | 30ea8339 | Anthony Liguori | #include <pthread.h> |
34 | 30ea8339 | Anthony Liguori | #endif
|
35 | bff9f8bf | Stefan Weil | |
36 | 4e0c6529 | Alex Bligh | #ifdef CONFIG_PPOLL
|
37 | 4e0c6529 | Alex Bligh | #include <poll.h> |
38 | 4e0c6529 | Alex Bligh | #endif
|
39 | 4e0c6529 | Alex Bligh | |
40 | cd758dd0 | Alex Bligh | #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
|
41 | cd758dd0 | Alex Bligh | #include <sys/prctl.h> |
42 | cd758dd0 | Alex Bligh | #endif
|
43 | cd758dd0 | Alex Bligh | |
44 | db1a4972 | Paolo Bonzini | /***********************************************************/
|
45 | db1a4972 | Paolo Bonzini | /* timers */
|
46 | db1a4972 | Paolo Bonzini | |
47 | b4049b74 | Alex Bligh | typedef struct QEMUClock { |
48 | ff83c66e | Alex Bligh | QLIST_HEAD(, QEMUTimerList) timerlists; |
49 | 691a0c9c | Jan Kiszka | |
50 | 691a0c9c | Jan Kiszka | NotifierList reset_notifiers; |
51 | 691a0c9c | Jan Kiszka | int64_t last; |
52 | 9a14b298 | Stefan Weil | |
53 | ff83c66e | Alex Bligh | QEMUClockType type; |
54 | 9a14b298 | Stefan Weil | bool enabled;
|
55 | b4049b74 | Alex Bligh | } QEMUClock; |
56 | db1a4972 | Paolo Bonzini | |
57 | 754d6a54 | Alex Bligh | QEMUTimerListGroup main_loop_tlg; |
58 | 7bf8fbde | Alex Bligh | QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; |
59 | ff83c66e | Alex Bligh | |
60 | ff83c66e | Alex Bligh | /* A QEMUTimerList is a list of timers attached to a clock. More
|
61 | ff83c66e | Alex Bligh | * than one QEMUTimerList can be attached to each clock, for instance
|
62 | ff83c66e | Alex Bligh | * used by different AioContexts / threads. Each clock also has
|
63 | ff83c66e | Alex Bligh | * a list of the QEMUTimerLists associated with it, in order that
|
64 | ff83c66e | Alex Bligh | * reenabling the clock can call all the notifiers.
|
65 | ff83c66e | Alex Bligh | */
|
66 | ff83c66e | Alex Bligh | |
67 | ff83c66e | Alex Bligh | struct QEMUTimerList {
|
68 | 9a14b298 | Stefan Weil | QEMUClock *clock; |
69 | ff83c66e | Alex Bligh | QEMUTimer *active_timers; |
70 | ff83c66e | Alex Bligh | QLIST_ENTRY(QEMUTimerList) list; |
71 | d5541d86 | Alex Bligh | QEMUTimerListNotifyCB *notify_cb; |
72 | d5541d86 | Alex Bligh | void *notify_opaque;
|
73 | db1a4972 | Paolo Bonzini | }; |
74 | db1a4972 | Paolo Bonzini | |
75 | 7bf8fbde | Alex Bligh | /**
|
76 | 7bf8fbde | Alex Bligh | * qemu_clock_ptr:
|
77 | 7bf8fbde | Alex Bligh | * @type: type of clock
|
78 | 7bf8fbde | Alex Bligh | *
|
79 | 7bf8fbde | Alex Bligh | * Translate a clock type into a pointer to QEMUClock object.
|
80 | 7bf8fbde | Alex Bligh | *
|
81 | 7bf8fbde | Alex Bligh | * Returns: a pointer to the QEMUClock object
|
82 | 7bf8fbde | Alex Bligh | */
|
83 | b4049b74 | Alex Bligh | static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) |
84 | 7bf8fbde | Alex Bligh | { |
85 | 7bf8fbde | Alex Bligh | return &qemu_clocks[type];
|
86 | 7bf8fbde | Alex Bligh | } |
87 | 7bf8fbde | Alex Bligh | |
88 | e93379b0 | Alex Bligh | static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) |
89 | 45c7b37f | Stefan Weil | { |
90 | 45c7b37f | Stefan Weil | return timer_head && (timer_head->expire_time <= current_time);
|
91 | 45c7b37f | Stefan Weil | } |
92 | 45c7b37f | Stefan Weil | |
93 | 7bf8fbde | Alex Bligh | QEMUTimerList *timerlist_new(QEMUClockType type, |
94 | 7bf8fbde | Alex Bligh | QEMUTimerListNotifyCB *cb, |
95 | 7bf8fbde | Alex Bligh | void *opaque)
|
96 | ff83c66e | Alex Bligh | { |
97 | ff83c66e | Alex Bligh | QEMUTimerList *timer_list; |
98 | 7bf8fbde | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
99 | ff83c66e | Alex Bligh | |
100 | ff83c66e | Alex Bligh | timer_list = g_malloc0(sizeof(QEMUTimerList));
|
101 | ff83c66e | Alex Bligh | timer_list->clock = clock; |
102 | d5541d86 | Alex Bligh | timer_list->notify_cb = cb; |
103 | d5541d86 | Alex Bligh | timer_list->notify_opaque = opaque; |
104 | ff83c66e | Alex Bligh | QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); |
105 | ff83c66e | Alex Bligh | return timer_list;
|
106 | ff83c66e | Alex Bligh | } |
107 | ff83c66e | Alex Bligh | |
108 | ff83c66e | Alex Bligh | void timerlist_free(QEMUTimerList *timer_list)
|
109 | ff83c66e | Alex Bligh | { |
110 | ff83c66e | Alex Bligh | assert(!timerlist_has_timers(timer_list)); |
111 | ff83c66e | Alex Bligh | if (timer_list->clock) {
|
112 | ff83c66e | Alex Bligh | QLIST_REMOVE(timer_list, list); |
113 | ff83c66e | Alex Bligh | } |
114 | ff83c66e | Alex Bligh | g_free(timer_list); |
115 | ff83c66e | Alex Bligh | } |
116 | ff83c66e | Alex Bligh | |
117 | 7bf8fbde | Alex Bligh | static void qemu_clock_init(QEMUClockType type) |
118 | db1a4972 | Paolo Bonzini | { |
119 | 7bf8fbde | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
120 | 691a0c9c | Jan Kiszka | |
121 | db1a4972 | Paolo Bonzini | clock->type = type; |
122 | 5e1ec7b2 | Stefan Weil | clock->enabled = true;
|
123 | 2ff68d07 | Paolo Bonzini | clock->last = INT64_MIN; |
124 | ff83c66e | Alex Bligh | QLIST_INIT(&clock->timerlists); |
125 | 691a0c9c | Jan Kiszka | notifier_list_init(&clock->reset_notifiers); |
126 | 7bf8fbde | Alex Bligh | main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); |
127 | db1a4972 | Paolo Bonzini | } |
128 | db1a4972 | Paolo Bonzini | |
129 | 40daca54 | Alex Bligh | bool qemu_clock_use_for_deadline(QEMUClockType type)
|
130 | ff83c66e | Alex Bligh | { |
131 | 40daca54 | Alex Bligh | return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
|
132 | ff83c66e | Alex Bligh | } |
133 | ff83c66e | Alex Bligh | |
134 | 40daca54 | Alex Bligh | void qemu_clock_notify(QEMUClockType type)
|
135 | b1bbfe72 | Alex Bligh | { |
136 | b1bbfe72 | Alex Bligh | QEMUTimerList *timer_list; |
137 | 40daca54 | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
138 | b1bbfe72 | Alex Bligh | QLIST_FOREACH(timer_list, &clock->timerlists, list) { |
139 | b1bbfe72 | Alex Bligh | timerlist_notify(timer_list); |
140 | b1bbfe72 | Alex Bligh | } |
141 | b1bbfe72 | Alex Bligh | } |
142 | b1bbfe72 | Alex Bligh | |
143 | 40daca54 | Alex Bligh | void qemu_clock_enable(QEMUClockType type, bool enabled) |
144 | db1a4972 | Paolo Bonzini | { |
145 | 40daca54 | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
146 | fbdc14eb | Paolo Bonzini | bool old = clock->enabled;
|
147 | db1a4972 | Paolo Bonzini | clock->enabled = enabled; |
148 | fbdc14eb | Paolo Bonzini | if (enabled && !old) {
|
149 | 40daca54 | Alex Bligh | qemu_clock_notify(type); |
150 | fbdc14eb | Paolo Bonzini | } |
151 | db1a4972 | Paolo Bonzini | } |
152 | db1a4972 | Paolo Bonzini | |
153 | ff83c66e | Alex Bligh | bool timerlist_has_timers(QEMUTimerList *timer_list)
|
154 | dc2dfcf0 | Paolo Bonzini | { |
155 | ff83c66e | Alex Bligh | return !!timer_list->active_timers;
|
156 | dc2dfcf0 | Paolo Bonzini | } |
157 | dc2dfcf0 | Paolo Bonzini | |
158 | 40daca54 | Alex Bligh | bool qemu_clock_has_timers(QEMUClockType type)
|
159 | dc2dfcf0 | Paolo Bonzini | { |
160 | 40daca54 | Alex Bligh | return timerlist_has_timers(
|
161 | 7bf8fbde | Alex Bligh | main_loop_tlg.tl[type]); |
162 | dc2dfcf0 | Paolo Bonzini | } |
163 | dc2dfcf0 | Paolo Bonzini | |
164 | ff83c66e | Alex Bligh | bool timerlist_expired(QEMUTimerList *timer_list)
|
165 | ff83c66e | Alex Bligh | { |
166 | ff83c66e | Alex Bligh | return (timer_list->active_timers &&
|
167 | ff83c66e | Alex Bligh | timer_list->active_timers->expire_time < |
168 | 40daca54 | Alex Bligh | qemu_clock_get_ns(timer_list->clock->type)); |
169 | ff83c66e | Alex Bligh | } |
170 | ff83c66e | Alex Bligh | |
171 | 40daca54 | Alex Bligh | bool qemu_clock_expired(QEMUClockType type)
|
172 | ff83c66e | Alex Bligh | { |
173 | 40daca54 | Alex Bligh | return timerlist_expired(
|
174 | 7bf8fbde | Alex Bligh | main_loop_tlg.tl[type]); |
175 | ff83c66e | Alex Bligh | } |
176 | ff83c66e | Alex Bligh | |
177 | 02a03a9f | Alex Bligh | /*
|
178 | 02a03a9f | Alex Bligh | * As above, but return -1 for no deadline, and do not cap to 2^32
|
179 | 02a03a9f | Alex Bligh | * as we know the result is always positive.
|
180 | 02a03a9f | Alex Bligh | */
|
181 | 02a03a9f | Alex Bligh | |
182 | ff83c66e | Alex Bligh | int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) |
183 | 02a03a9f | Alex Bligh | { |
184 | 02a03a9f | Alex Bligh | int64_t delta; |
185 | 02a03a9f | Alex Bligh | |
186 | ff83c66e | Alex Bligh | if (!timer_list->clock->enabled || !timer_list->active_timers) {
|
187 | 02a03a9f | Alex Bligh | return -1; |
188 | 02a03a9f | Alex Bligh | } |
189 | 02a03a9f | Alex Bligh | |
190 | ff83c66e | Alex Bligh | delta = timer_list->active_timers->expire_time - |
191 | 40daca54 | Alex Bligh | qemu_clock_get_ns(timer_list->clock->type); |
192 | 02a03a9f | Alex Bligh | |
193 | 02a03a9f | Alex Bligh | if (delta <= 0) { |
194 | 02a03a9f | Alex Bligh | return 0; |
195 | 02a03a9f | Alex Bligh | } |
196 | 02a03a9f | Alex Bligh | |
197 | 02a03a9f | Alex Bligh | return delta;
|
198 | 02a03a9f | Alex Bligh | } |
199 | 02a03a9f | Alex Bligh | |
200 | ac70aafc | Alex Bligh | /* Calculate the soonest deadline across all timerlists attached
|
201 | ac70aafc | Alex Bligh | * to the clock. This is used for the icount timeout so we
|
202 | ac70aafc | Alex Bligh | * ignore whether or not the clock should be used in deadline
|
203 | ac70aafc | Alex Bligh | * calculations.
|
204 | ac70aafc | Alex Bligh | */
|
205 | 40daca54 | Alex Bligh | int64_t qemu_clock_deadline_ns_all(QEMUClockType type) |
206 | ac70aafc | Alex Bligh | { |
207 | ac70aafc | Alex Bligh | int64_t deadline = -1;
|
208 | ac70aafc | Alex Bligh | QEMUTimerList *timer_list; |
209 | 40daca54 | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
210 | ac70aafc | Alex Bligh | QLIST_FOREACH(timer_list, &clock->timerlists, list) { |
211 | ac70aafc | Alex Bligh | deadline = qemu_soonest_timeout(deadline, |
212 | ac70aafc | Alex Bligh | timerlist_deadline_ns(timer_list)); |
213 | ac70aafc | Alex Bligh | } |
214 | ac70aafc | Alex Bligh | return deadline;
|
215 | ac70aafc | Alex Bligh | } |
216 | ac70aafc | Alex Bligh | |
217 | 40daca54 | Alex Bligh | QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) |
218 | ff83c66e | Alex Bligh | { |
219 | 40daca54 | Alex Bligh | return timer_list->clock->type;
|
220 | ff83c66e | Alex Bligh | } |
221 | ff83c66e | Alex Bligh | |
222 | 40daca54 | Alex Bligh | QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) |
223 | ff83c66e | Alex Bligh | { |
224 | 7bf8fbde | Alex Bligh | return main_loop_tlg.tl[type];
|
225 | ff83c66e | Alex Bligh | } |
226 | ff83c66e | Alex Bligh | |
227 | d5541d86 | Alex Bligh | void timerlist_notify(QEMUTimerList *timer_list)
|
228 | d5541d86 | Alex Bligh | { |
229 | d5541d86 | Alex Bligh | if (timer_list->notify_cb) {
|
230 | d5541d86 | Alex Bligh | timer_list->notify_cb(timer_list->notify_opaque); |
231 | d5541d86 | Alex Bligh | } else {
|
232 | d5541d86 | Alex Bligh | qemu_notify_event(); |
233 | d5541d86 | Alex Bligh | } |
234 | d5541d86 | Alex Bligh | } |
235 | d5541d86 | Alex Bligh | |
236 | 02a03a9f | Alex Bligh | /* Transition function to convert a nanosecond timeout to ms
|
237 | 02a03a9f | Alex Bligh | * This is used where a system does not support ppoll
|
238 | 02a03a9f | Alex Bligh | */
|
239 | 02a03a9f | Alex Bligh | int qemu_timeout_ns_to_ms(int64_t ns)
|
240 | 02a03a9f | Alex Bligh | { |
241 | 02a03a9f | Alex Bligh | int64_t ms; |
242 | 02a03a9f | Alex Bligh | if (ns < 0) { |
243 | 02a03a9f | Alex Bligh | return -1; |
244 | 02a03a9f | Alex Bligh | } |
245 | 02a03a9f | Alex Bligh | |
246 | 02a03a9f | Alex Bligh | if (!ns) {
|
247 | 02a03a9f | Alex Bligh | return 0; |
248 | 02a03a9f | Alex Bligh | } |
249 | 02a03a9f | Alex Bligh | |
250 | 02a03a9f | Alex Bligh | /* Always round up, because it's better to wait too long than to wait too
|
251 | 02a03a9f | Alex Bligh | * little and effectively busy-wait
|
252 | 02a03a9f | Alex Bligh | */
|
253 | 02a03a9f | Alex Bligh | ms = (ns + SCALE_MS - 1) / SCALE_MS;
|
254 | 02a03a9f | Alex Bligh | |
255 | 02a03a9f | Alex Bligh | /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
|
256 | 02a03a9f | Alex Bligh | if (ms > (int64_t) INT32_MAX) {
|
257 | 02a03a9f | Alex Bligh | ms = INT32_MAX; |
258 | 02a03a9f | Alex Bligh | } |
259 | 02a03a9f | Alex Bligh | |
260 | 02a03a9f | Alex Bligh | return (int) ms; |
261 | 02a03a9f | Alex Bligh | } |
262 | 02a03a9f | Alex Bligh | |
263 | 02a03a9f | Alex Bligh | |
264 | 4e0c6529 | Alex Bligh | /* qemu implementation of g_poll which uses a nanosecond timeout but is
|
265 | 4e0c6529 | Alex Bligh | * otherwise identical to g_poll
|
266 | 4e0c6529 | Alex Bligh | */
|
267 | 4e0c6529 | Alex Bligh | int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
|
268 | 4e0c6529 | Alex Bligh | { |
269 | 4e0c6529 | Alex Bligh | #ifdef CONFIG_PPOLL
|
270 | 4e0c6529 | Alex Bligh | if (timeout < 0) { |
271 | 4e0c6529 | Alex Bligh | return ppoll((struct pollfd *)fds, nfds, NULL, NULL); |
272 | 4e0c6529 | Alex Bligh | } else {
|
273 | 4e0c6529 | Alex Bligh | struct timespec ts;
|
274 | 4e0c6529 | Alex Bligh | ts.tv_sec = timeout / 1000000000LL;
|
275 | 4e0c6529 | Alex Bligh | ts.tv_nsec = timeout % 1000000000LL;
|
276 | 4e0c6529 | Alex Bligh | return ppoll((struct pollfd *)fds, nfds, &ts, NULL); |
277 | 4e0c6529 | Alex Bligh | } |
278 | 4e0c6529 | Alex Bligh | #else
|
279 | 4e0c6529 | Alex Bligh | return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
|
280 | 4e0c6529 | Alex Bligh | #endif
|
281 | 4e0c6529 | Alex Bligh | } |
282 | 4e0c6529 | Alex Bligh | |
283 | 4e0c6529 | Alex Bligh | |
284 | ff83c66e | Alex Bligh | void timer_init(QEMUTimer *ts,
|
285 | ff83c66e | Alex Bligh | QEMUTimerList *timer_list, int scale,
|
286 | ff83c66e | Alex Bligh | QEMUTimerCB *cb, void *opaque)
|
287 | db1a4972 | Paolo Bonzini | { |
288 | ff83c66e | Alex Bligh | ts->timer_list = timer_list; |
289 | db1a4972 | Paolo Bonzini | ts->cb = cb; |
290 | db1a4972 | Paolo Bonzini | ts->opaque = opaque; |
291 | 4a998740 | Paolo Bonzini | ts->scale = scale; |
292 | ff83c66e | Alex Bligh | } |
293 | ff83c66e | Alex Bligh | |
294 | 40daca54 | Alex Bligh | void timer_free(QEMUTimer *ts)
|
295 | db1a4972 | Paolo Bonzini | { |
296 | 7267c094 | Anthony Liguori | g_free(ts); |
297 | db1a4972 | Paolo Bonzini | } |
298 | db1a4972 | Paolo Bonzini | |
299 | db1a4972 | Paolo Bonzini | /* stop a timer, but do not dealloc it */
|
300 | 40daca54 | Alex Bligh | void timer_del(QEMUTimer *ts)
|
301 | db1a4972 | Paolo Bonzini | { |
302 | db1a4972 | Paolo Bonzini | QEMUTimer **pt, *t; |
303 | db1a4972 | Paolo Bonzini | |
304 | db1a4972 | Paolo Bonzini | /* NOTE: this code must be signal safe because
|
305 | e93379b0 | Alex Bligh | timer_expired() can be called from a signal. */
|
306 | ff83c66e | Alex Bligh | pt = &ts->timer_list->active_timers; |
307 | db1a4972 | Paolo Bonzini | for(;;) {
|
308 | db1a4972 | Paolo Bonzini | t = *pt; |
309 | db1a4972 | Paolo Bonzini | if (!t)
|
310 | db1a4972 | Paolo Bonzini | break;
|
311 | db1a4972 | Paolo Bonzini | if (t == ts) {
|
312 | db1a4972 | Paolo Bonzini | *pt = t->next; |
313 | db1a4972 | Paolo Bonzini | break;
|
314 | db1a4972 | Paolo Bonzini | } |
315 | db1a4972 | Paolo Bonzini | pt = &t->next; |
316 | db1a4972 | Paolo Bonzini | } |
317 | db1a4972 | Paolo Bonzini | } |
318 | db1a4972 | Paolo Bonzini | |
319 | db1a4972 | Paolo Bonzini | /* modify the current timer so that it will be fired when current_time
|
320 | db1a4972 | Paolo Bonzini | >= expire_time. The corresponding callback will be called. */
|
321 | 40daca54 | Alex Bligh | void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
|
322 | db1a4972 | Paolo Bonzini | { |
323 | db1a4972 | Paolo Bonzini | QEMUTimer **pt, *t; |
324 | db1a4972 | Paolo Bonzini | |
325 | 40daca54 | Alex Bligh | timer_del(ts); |
326 | db1a4972 | Paolo Bonzini | |
327 | db1a4972 | Paolo Bonzini | /* add the timer in the sorted list */
|
328 | db1a4972 | Paolo Bonzini | /* NOTE: this code must be signal safe because
|
329 | e93379b0 | Alex Bligh | timer_expired() can be called from a signal. */
|
330 | ff83c66e | Alex Bligh | pt = &ts->timer_list->active_timers; |
331 | db1a4972 | Paolo Bonzini | for(;;) {
|
332 | db1a4972 | Paolo Bonzini | t = *pt; |
333 | e93379b0 | Alex Bligh | if (!timer_expired_ns(t, expire_time)) {
|
334 | db1a4972 | Paolo Bonzini | break;
|
335 | 45c7b37f | Stefan Weil | } |
336 | db1a4972 | Paolo Bonzini | pt = &t->next; |
337 | db1a4972 | Paolo Bonzini | } |
338 | db1a4972 | Paolo Bonzini | ts->expire_time = expire_time; |
339 | db1a4972 | Paolo Bonzini | ts->next = *pt; |
340 | db1a4972 | Paolo Bonzini | *pt = ts; |
341 | db1a4972 | Paolo Bonzini | |
342 | db1a4972 | Paolo Bonzini | /* Rearm if necessary */
|
343 | ff83c66e | Alex Bligh | if (pt == &ts->timer_list->active_timers) {
|
344 | db1a4972 | Paolo Bonzini | /* Interrupt execution to force deadline recalculation. */
|
345 | 40daca54 | Alex Bligh | qemu_clock_warp(ts->timer_list->clock->type); |
346 | b1bbfe72 | Alex Bligh | timerlist_notify(ts->timer_list); |
347 | db1a4972 | Paolo Bonzini | } |
348 | db1a4972 | Paolo Bonzini | } |
349 | db1a4972 | Paolo Bonzini | |
350 | 40daca54 | Alex Bligh | void timer_mod(QEMUTimer *ts, int64_t expire_time)
|
351 | 4a998740 | Paolo Bonzini | { |
352 | 40daca54 | Alex Bligh | timer_mod_ns(ts, expire_time * ts->scale); |
353 | 4a998740 | Paolo Bonzini | } |
354 | 4a998740 | Paolo Bonzini | |
355 | e93379b0 | Alex Bligh | bool timer_pending(QEMUTimer *ts)
|
356 | db1a4972 | Paolo Bonzini | { |
357 | db1a4972 | Paolo Bonzini | QEMUTimer *t; |
358 | ff83c66e | Alex Bligh | for (t = ts->timer_list->active_timers; t != NULL; t = t->next) { |
359 | 5e1ec7b2 | Stefan Weil | if (t == ts) {
|
360 | 5e1ec7b2 | Stefan Weil | return true; |
361 | 5e1ec7b2 | Stefan Weil | } |
362 | db1a4972 | Paolo Bonzini | } |
363 | 5e1ec7b2 | Stefan Weil | return false; |
364 | db1a4972 | Paolo Bonzini | } |
365 | db1a4972 | Paolo Bonzini | |
366 | e93379b0 | Alex Bligh | bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
|
367 | db1a4972 | Paolo Bonzini | { |
368 | e93379b0 | Alex Bligh | return timer_expired_ns(timer_head, current_time * timer_head->scale);
|
369 | db1a4972 | Paolo Bonzini | } |
370 | db1a4972 | Paolo Bonzini | |
371 | ff83c66e | Alex Bligh | bool timerlist_run_timers(QEMUTimerList *timer_list)
|
372 | db1a4972 | Paolo Bonzini | { |
373 | 144b97c2 | Paolo Bonzini | QEMUTimer *ts; |
374 | db1a4972 | Paolo Bonzini | int64_t current_time; |
375 | f9a976b7 | Alex Bligh | bool progress = false; |
376 | db1a4972 | Paolo Bonzini | |
377 | ff83c66e | Alex Bligh | if (!timer_list->clock->enabled) {
|
378 | f9a976b7 | Alex Bligh | return progress;
|
379 | ff83c66e | Alex Bligh | } |
380 | db1a4972 | Paolo Bonzini | |
381 | 40daca54 | Alex Bligh | current_time = qemu_clock_get_ns(timer_list->clock->type); |
382 | db1a4972 | Paolo Bonzini | for(;;) {
|
383 | ff83c66e | Alex Bligh | ts = timer_list->active_timers; |
384 | e93379b0 | Alex Bligh | if (!timer_expired_ns(ts, current_time)) {
|
385 | db1a4972 | Paolo Bonzini | break;
|
386 | 45c7b37f | Stefan Weil | } |
387 | db1a4972 | Paolo Bonzini | /* remove timer from the list before calling the callback */
|
388 | ff83c66e | Alex Bligh | timer_list->active_timers = ts->next; |
389 | db1a4972 | Paolo Bonzini | ts->next = NULL;
|
390 | db1a4972 | Paolo Bonzini | |
391 | db1a4972 | Paolo Bonzini | /* run the callback (the timer list can be modified) */
|
392 | db1a4972 | Paolo Bonzini | ts->cb(ts->opaque); |
393 | f9a976b7 | Alex Bligh | progress = true;
|
394 | db1a4972 | Paolo Bonzini | } |
395 | f9a976b7 | Alex Bligh | return progress;
|
396 | db1a4972 | Paolo Bonzini | } |
397 | db1a4972 | Paolo Bonzini | |
398 | 40daca54 | Alex Bligh | bool qemu_clock_run_timers(QEMUClockType type)
|
399 | 40daca54 | Alex Bligh | { |
400 | 7bf8fbde | Alex Bligh | return timerlist_run_timers(main_loop_tlg.tl[type]);
|
401 | 40daca54 | Alex Bligh | } |
402 | 40daca54 | Alex Bligh | |
403 | d5541d86 | Alex Bligh | void timerlistgroup_init(QEMUTimerListGroup *tlg,
|
404 | d5541d86 | Alex Bligh | QEMUTimerListNotifyCB *cb, void *opaque)
|
405 | 754d6a54 | Alex Bligh | { |
406 | 754d6a54 | Alex Bligh | QEMUClockType type; |
407 | 754d6a54 | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
408 | d5541d86 | Alex Bligh | tlg->tl[type] = timerlist_new(type, cb, opaque); |
409 | 754d6a54 | Alex Bligh | } |
410 | 754d6a54 | Alex Bligh | } |
411 | 754d6a54 | Alex Bligh | |
412 | 754d6a54 | Alex Bligh | void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
|
413 | 754d6a54 | Alex Bligh | { |
414 | 754d6a54 | Alex Bligh | QEMUClockType type; |
415 | 754d6a54 | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
416 | 754d6a54 | Alex Bligh | timerlist_free(tlg->tl[type]); |
417 | 754d6a54 | Alex Bligh | } |
418 | 754d6a54 | Alex Bligh | } |
419 | 754d6a54 | Alex Bligh | |
420 | 754d6a54 | Alex Bligh | bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
|
421 | 754d6a54 | Alex Bligh | { |
422 | 754d6a54 | Alex Bligh | QEMUClockType type; |
423 | 754d6a54 | Alex Bligh | bool progress = false; |
424 | 754d6a54 | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
425 | 754d6a54 | Alex Bligh | progress |= timerlist_run_timers(tlg->tl[type]); |
426 | 754d6a54 | Alex Bligh | } |
427 | 754d6a54 | Alex Bligh | return progress;
|
428 | 754d6a54 | Alex Bligh | } |
429 | 754d6a54 | Alex Bligh | |
430 | 754d6a54 | Alex Bligh | int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) |
431 | 754d6a54 | Alex Bligh | { |
432 | 754d6a54 | Alex Bligh | int64_t deadline = -1;
|
433 | 754d6a54 | Alex Bligh | QEMUClockType type; |
434 | 754d6a54 | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
435 | 40daca54 | Alex Bligh | if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
|
436 | 754d6a54 | Alex Bligh | deadline = qemu_soonest_timeout(deadline, |
437 | 754d6a54 | Alex Bligh | timerlist_deadline_ns( |
438 | 754d6a54 | Alex Bligh | tlg->tl[type])); |
439 | 754d6a54 | Alex Bligh | } |
440 | 754d6a54 | Alex Bligh | } |
441 | 754d6a54 | Alex Bligh | return deadline;
|
442 | 754d6a54 | Alex Bligh | } |
443 | 754d6a54 | Alex Bligh | |
444 | 40daca54 | Alex Bligh | int64_t qemu_clock_get_ns(QEMUClockType type) |
445 | db1a4972 | Paolo Bonzini | { |
446 | 691a0c9c | Jan Kiszka | int64_t now, last; |
447 | 40daca54 | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
448 | 691a0c9c | Jan Kiszka | |
449 | 40daca54 | Alex Bligh | switch (type) {
|
450 | db1a4972 | Paolo Bonzini | case QEMU_CLOCK_REALTIME:
|
451 | db1a4972 | Paolo Bonzini | return get_clock();
|
452 | db1a4972 | Paolo Bonzini | default:
|
453 | db1a4972 | Paolo Bonzini | case QEMU_CLOCK_VIRTUAL:
|
454 | db1a4972 | Paolo Bonzini | if (use_icount) {
|
455 | db1a4972 | Paolo Bonzini | return cpu_get_icount();
|
456 | db1a4972 | Paolo Bonzini | } else {
|
457 | db1a4972 | Paolo Bonzini | return cpu_get_clock();
|
458 | db1a4972 | Paolo Bonzini | } |
459 | db1a4972 | Paolo Bonzini | case QEMU_CLOCK_HOST:
|
460 | 691a0c9c | Jan Kiszka | now = get_clock_realtime(); |
461 | 691a0c9c | Jan Kiszka | last = clock->last; |
462 | 691a0c9c | Jan Kiszka | clock->last = now; |
463 | 691a0c9c | Jan Kiszka | if (now < last) {
|
464 | 691a0c9c | Jan Kiszka | notifier_list_notify(&clock->reset_notifiers, &now); |
465 | 691a0c9c | Jan Kiszka | } |
466 | 691a0c9c | Jan Kiszka | return now;
|
467 | db1a4972 | Paolo Bonzini | } |
468 | db1a4972 | Paolo Bonzini | } |
469 | db1a4972 | Paolo Bonzini | |
470 | 40daca54 | Alex Bligh | void qemu_clock_register_reset_notifier(QEMUClockType type,
|
471 | 40daca54 | Alex Bligh | Notifier *notifier) |
472 | 40daca54 | Alex Bligh | { |
473 | 40daca54 | Alex Bligh | QEMUClock *clock = qemu_clock_ptr(type); |
474 | 691a0c9c | Jan Kiszka | notifier_list_add(&clock->reset_notifiers, notifier); |
475 | 691a0c9c | Jan Kiszka | } |
476 | 691a0c9c | Jan Kiszka | |
477 | 40daca54 | Alex Bligh | void qemu_clock_unregister_reset_notifier(QEMUClockType type,
|
478 | 40daca54 | Alex Bligh | Notifier *notifier) |
479 | 691a0c9c | Jan Kiszka | { |
480 | 31552529 | Paolo Bonzini | notifier_remove(notifier); |
481 | 691a0c9c | Jan Kiszka | } |
482 | 691a0c9c | Jan Kiszka | |
483 | db1a4972 | Paolo Bonzini | void init_clocks(void) |
484 | db1a4972 | Paolo Bonzini | { |
485 | ff83c66e | Alex Bligh | QEMUClockType type; |
486 | ff83c66e | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
487 | 7bf8fbde | Alex Bligh | qemu_clock_init(type); |
488 | 744ca8e3 | Paolo Bonzini | } |
489 | ff83c66e | Alex Bligh | |
490 | cd758dd0 | Alex Bligh | #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
|
491 | cd758dd0 | Alex Bligh | prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); |
492 | cd758dd0 | Alex Bligh | #endif
|
493 | db1a4972 | Paolo Bonzini | } |
494 | db1a4972 | Paolo Bonzini | |
495 | e93379b0 | Alex Bligh | uint64_t timer_expire_time_ns(QEMUTimer *ts) |
496 | db1a4972 | Paolo Bonzini | { |
497 | e93379b0 | Alex Bligh | return timer_pending(ts) ? ts->expire_time : -1; |
498 | db1a4972 | Paolo Bonzini | } |
499 | db1a4972 | Paolo Bonzini | |
500 | 40daca54 | Alex Bligh | bool qemu_clock_run_all_timers(void) |
501 | db1a4972 | Paolo Bonzini | { |
502 | f9a976b7 | Alex Bligh | bool progress = false; |
503 | ff83c66e | Alex Bligh | QEMUClockType type; |
504 | 6d327171 | Alex Bligh | |
505 | ff83c66e | Alex Bligh | for (type = 0; type < QEMU_CLOCK_MAX; type++) { |
506 | 40daca54 | Alex Bligh | progress |= qemu_clock_run_timers(type); |
507 | ff83c66e | Alex Bligh | } |
508 | 158fd3ce | Peter Portante | |
509 | f9a976b7 | Alex Bligh | return progress;
|
510 | db1a4972 | Paolo Bonzini | } |