]> git.proxmox.com Git - mirror_qemu.git/blame - util/qemu-timer.c
target/i386: Rename tcg_cpu_FOO() to include 'x86'
[mirror_qemu.git] / util / qemu-timer.c
CommitLineData
db1a4972
PB
1/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
d38ea87a 25#include "qemu/osdep.h"
1ac0206b 26#include "qemu/main-loop.h"
1de7afc9 27#include "qemu/timer.h"
3284c3dd 28#include "qemu/lockable.h"
740b1759 29#include "sysemu/cpu-timers.h"
8eda206e 30#include "sysemu/replay.h"
d2528bdc 31#include "sysemu/cpus.h"
1ac0206b 32
30ea8339
AL
33#ifdef CONFIG_POSIX
34#include <pthread.h>
35#endif
bff9f8bf 36
4e0c6529
AB
37#ifdef CONFIG_PPOLL
38#include <poll.h>
39#endif
40
cd758dd0
AB
41#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
42#include <sys/prctl.h>
43#endif
44
db1a4972
PB
45/***********************************************************/
46/* timers */
47
b4049b74 48typedef struct QEMUClock {
3c053411 49 /* We rely on BQL to protect the timerlists */
ff83c66e 50 QLIST_HEAD(, QEMUTimerList) timerlists;
691a0c9c 51
ff83c66e 52 QEMUClockType type;
9a14b298 53 bool enabled;
b4049b74 54} QEMUClock;
db1a4972 55
754d6a54 56QEMUTimerListGroup main_loop_tlg;
fbdb664c 57static QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
ff83c66e
AB
58
59/* A QEMUTimerList is a list of timers attached to a clock. More
60 * than one QEMUTimerList can be attached to each clock, for instance
61 * used by different AioContexts / threads. Each clock also has
62 * a list of the QEMUTimerLists associated with it, in order that
63 * reenabling the clock can call all the notifiers.
64 */
65
66struct QEMUTimerList {
9a14b298 67 QEMUClock *clock;
978f2205 68 QemuMutex active_timers_lock;
ff83c66e
AB
69 QEMUTimer *active_timers;
70 QLIST_ENTRY(QEMUTimerList) list;
d5541d86
AB
71 QEMUTimerListNotifyCB *notify_cb;
72 void *notify_opaque;
3c053411
LPF
73
74 /* lightweight method to mark the end of timerlist's running */
75 QemuEvent timers_done_ev;
db1a4972
PB
76};
77
7bf8fbde
AB
78/**
79 * qemu_clock_ptr:
80 * @type: type of clock
81 *
82 * Translate a clock type into a pointer to QEMUClock object.
83 *
84 * Returns: a pointer to the QEMUClock object
85 */
b4049b74 86static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
7bf8fbde
AB
87{
88 return &qemu_clocks[type];
89}
90
e93379b0 91static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
45c7b37f
SW
92{
93 return timer_head && (timer_head->expire_time <= current_time);
94}
95
7bf8fbde
AB
96QEMUTimerList *timerlist_new(QEMUClockType type,
97 QEMUTimerListNotifyCB *cb,
98 void *opaque)
ff83c66e
AB
99{
100 QEMUTimerList *timer_list;
7bf8fbde 101 QEMUClock *clock = qemu_clock_ptr(type);
ff83c66e 102
b21e2380 103 timer_list = g_new0(QEMUTimerList, 1);
e4efd8a4 104 qemu_event_init(&timer_list->timers_done_ev, true);
ff83c66e 105 timer_list->clock = clock;
d5541d86
AB
106 timer_list->notify_cb = cb;
107 timer_list->notify_opaque = opaque;
978f2205 108 qemu_mutex_init(&timer_list->active_timers_lock);
ff83c66e
AB
109 QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
110 return timer_list;
111}
112
ff83c66e
AB
113void timerlist_free(QEMUTimerList *timer_list)
114{
115 assert(!timerlist_has_timers(timer_list));
116 if (timer_list->clock) {
117 QLIST_REMOVE(timer_list, list);
ff83c66e 118 }
978f2205 119 qemu_mutex_destroy(&timer_list->active_timers_lock);
ff83c66e
AB
120 g_free(timer_list);
121}
122
3f53bc61 123static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb)
db1a4972 124{
7bf8fbde 125 QEMUClock *clock = qemu_clock_ptr(type);
691a0c9c 126
02ce232c
KB
127 /* Assert that the clock of type TYPE has not been initialized yet. */
128 assert(main_loop_tlg.tl[type] == NULL);
129
db1a4972 130 clock->type = type;
3fdd0ee3 131 clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : true);
ff83c66e 132 QLIST_INIT(&clock->timerlists);
3f53bc61 133 main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL);
db1a4972
PB
134}
135
40daca54 136bool qemu_clock_use_for_deadline(QEMUClockType type)
ff83c66e 137{
740b1759 138 return !(icount_enabled() && (type == QEMU_CLOCK_VIRTUAL));
ff83c66e
AB
139}
140
40daca54 141void qemu_clock_notify(QEMUClockType type)
b1bbfe72
AB
142{
143 QEMUTimerList *timer_list;
40daca54 144 QEMUClock *clock = qemu_clock_ptr(type);
b1bbfe72
AB
145 QLIST_FOREACH(timer_list, &clock->timerlists, list) {
146 timerlist_notify(timer_list);
147 }
148}
149
3c053411
LPF
150/* Disabling the clock will wait for related timerlists to stop
151 * executing qemu_run_timers. Thus, this functions should not
152 * be used from the callback of a timer that is based on @clock.
153 * Doing so would cause a deadlock.
154 *
155 * Caller should hold BQL.
156 */
40daca54 157void qemu_clock_enable(QEMUClockType type, bool enabled)
db1a4972 158{
40daca54 159 QEMUClock *clock = qemu_clock_ptr(type);
3c053411 160 QEMUTimerList *tl;
fbdc14eb 161 bool old = clock->enabled;
db1a4972 162 clock->enabled = enabled;
fbdc14eb 163 if (enabled && !old) {
40daca54 164 qemu_clock_notify(type);
3c053411
LPF
165 } else if (!enabled && old) {
166 QLIST_FOREACH(tl, &clock->timerlists, list) {
167 qemu_event_wait(&tl->timers_done_ev);
168 }
fbdc14eb 169 }
db1a4972
PB
170}
171
ff83c66e 172bool timerlist_has_timers(QEMUTimerList *timer_list)
dc2dfcf0 173{
d73415a3 174 return !!qatomic_read(&timer_list->active_timers);
dc2dfcf0
PB
175}
176
40daca54 177bool qemu_clock_has_timers(QEMUClockType type)
dc2dfcf0 178{
40daca54 179 return timerlist_has_timers(
7bf8fbde 180 main_loop_tlg.tl[type]);
dc2dfcf0
PB
181}
182
ff83c66e
AB
183bool timerlist_expired(QEMUTimerList *timer_list)
184{
978f2205
SH
185 int64_t expire_time;
186
d73415a3 187 if (!qatomic_read(&timer_list->active_timers)) {
8caa05d8
PB
188 return false;
189 }
190
3284c3dd
SH
191 WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
192 if (!timer_list->active_timers) {
193 return false;
194 }
195 expire_time = timer_list->active_timers->expire_time;
978f2205 196 }
978f2205 197
33bef0b9 198 return expire_time <= qemu_clock_get_ns(timer_list->clock->type);
ff83c66e
AB
199}
200
40daca54 201bool qemu_clock_expired(QEMUClockType type)
ff83c66e 202{
40daca54 203 return timerlist_expired(
7bf8fbde 204 main_loop_tlg.tl[type]);
ff83c66e
AB
205}
206
02a03a9f
AB
207/*
208 * As above, but return -1 for no deadline, and do not cap to 2^32
209 * as we know the result is always positive.
210 */
211
ff83c66e 212int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
02a03a9f
AB
213{
214 int64_t delta;
978f2205 215 int64_t expire_time;
02a03a9f 216
d73415a3 217 if (!qatomic_read(&timer_list->active_timers)) {
8caa05d8
PB
218 return -1;
219 }
220
978f2205 221 if (!timer_list->clock->enabled) {
02a03a9f
AB
222 return -1;
223 }
224
978f2205
SH
225 /* The active timers list may be modified before the caller uses our return
226 * value but ->notify_cb() is called when the deadline changes. Therefore
227 * the caller should notice the change and there is no race condition.
228 */
3284c3dd
SH
229 WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
230 if (!timer_list->active_timers) {
231 return -1;
232 }
233 expire_time = timer_list->active_timers->expire_time;
978f2205 234 }
978f2205
SH
235
236 delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
02a03a9f
AB
237
238 if (delta <= 0) {
239 return 0;
240 }
241
242 return delta;
243}
244
ac70aafc
AB
245/* Calculate the soonest deadline across all timerlists attached
246 * to the clock. This is used for the icount timeout so we
247 * ignore whether or not the clock should be used in deadline
248 * calculations.
249 */
dcb15780 250int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask)
ac70aafc
AB
251{
252 int64_t deadline = -1;
dcb15780
PD
253 int64_t delta;
254 int64_t expire_time;
255 QEMUTimer *ts;
ac70aafc 256 QEMUTimerList *timer_list;
40daca54 257 QEMUClock *clock = qemu_clock_ptr(type);
dcb15780
PD
258
259 if (!clock->enabled) {
260 return -1;
261 }
262
ac70aafc 263 QLIST_FOREACH(timer_list, &clock->timerlists, list) {
3f42906c
IH
264 if (!qatomic_read(&timer_list->active_timers)) {
265 continue;
266 }
dcb15780
PD
267 qemu_mutex_lock(&timer_list->active_timers_lock);
268 ts = timer_list->active_timers;
269 /* Skip all external timers */
270 while (ts && (ts->attributes & ~attr_mask)) {
271 ts = ts->next;
272 }
273 if (!ts) {
274 qemu_mutex_unlock(&timer_list->active_timers_lock);
275 continue;
276 }
277 expire_time = ts->expire_time;
278 qemu_mutex_unlock(&timer_list->active_timers_lock);
279
280 delta = expire_time - qemu_clock_get_ns(type);
281 if (delta <= 0) {
282 delta = 0;
283 }
284 deadline = qemu_soonest_timeout(deadline, delta);
ac70aafc
AB
285 }
286 return deadline;
287}
288
40daca54 289QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
ff83c66e 290{
40daca54 291 return timer_list->clock->type;
ff83c66e
AB
292}
293
40daca54 294QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
ff83c66e 295{
7bf8fbde 296 return main_loop_tlg.tl[type];
ff83c66e
AB
297}
298
d5541d86
AB
299void timerlist_notify(QEMUTimerList *timer_list)
300{
301 if (timer_list->notify_cb) {
3f53bc61 302 timer_list->notify_cb(timer_list->notify_opaque, timer_list->clock->type);
d5541d86
AB
303 } else {
304 qemu_notify_event();
305 }
306}
307
02a03a9f
AB
308/* Transition function to convert a nanosecond timeout to ms
309 * This is used where a system does not support ppoll
310 */
311int qemu_timeout_ns_to_ms(int64_t ns)
312{
313 int64_t ms;
314 if (ns < 0) {
315 return -1;
316 }
317
318 if (!ns) {
319 return 0;
320 }
321
322 /* Always round up, because it's better to wait too long than to wait too
323 * little and effectively busy-wait
324 */
5029b969 325 ms = DIV_ROUND_UP(ns, SCALE_MS);
02a03a9f
AB
326
327 /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
5bd34354 328 return MIN(ms, INT32_MAX);
02a03a9f
AB
329}
330
331
4e0c6529
AB
332/* qemu implementation of g_poll which uses a nanosecond timeout but is
333 * otherwise identical to g_poll
334 */
335int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
336{
337#ifdef CONFIG_PPOLL
338 if (timeout < 0) {
339 return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
340 } else {
341 struct timespec ts;
490309fc
PM
342 int64_t tvsec = timeout / 1000000000LL;
343 /* Avoid possibly overflowing and specifying a negative number of
344 * seconds, which would turn a very long timeout into a busy-wait.
345 */
346 if (tvsec > (int64_t)INT32_MAX) {
347 tvsec = INT32_MAX;
348 }
349 ts.tv_sec = tvsec;
4e0c6529
AB
350 ts.tv_nsec = timeout % 1000000000LL;
351 return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
352 }
353#else
354 return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
355#endif
356}
357
358
89a603a0
AP
359void timer_init_full(QEMUTimer *ts,
360 QEMUTimerListGroup *timer_list_group, QEMUClockType type,
361 int scale, int attributes,
362 QEMUTimerCB *cb, void *opaque)
db1a4972 363{
89a603a0
AP
364 if (!timer_list_group) {
365 timer_list_group = &main_loop_tlg;
366 }
367 ts->timer_list = timer_list_group->tl[type];
db1a4972
PB
368 ts->cb = cb;
369 ts->opaque = opaque;
4a998740 370 ts->scale = scale;
89a603a0 371 ts->attributes = attributes;
3db1ee7c 372 ts->expire_time = -1;
ff83c66e
AB
373}
374
cd1bd53a
PB
375void timer_deinit(QEMUTimer *ts)
376{
377 assert(ts->expire_time == -1);
378 ts->timer_list = NULL;
379}
380
978f2205 381static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
db1a4972
PB
382{
383 QEMUTimer **pt, *t;
384
3db1ee7c 385 ts->expire_time = -1;
978f2205 386 pt = &timer_list->active_timers;
db1a4972
PB
387 for(;;) {
388 t = *pt;
389 if (!t)
390 break;
391 if (t == ts) {
d73415a3 392 qatomic_set(pt, t->next);
db1a4972
PB
393 break;
394 }
395 pt = &t->next;
396 }
397}
398
0f809e5f
PB
399static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
400 QEMUTimer *ts, int64_t expire_time)
401{
402 QEMUTimer **pt, *t;
403
404 /* add the timer in the sorted list */
405 pt = &timer_list->active_timers;
406 for (;;) {
407 t = *pt;
408 if (!timer_expired_ns(t, expire_time)) {
409 break;
410 }
411 pt = &t->next;
412 }
413 ts->expire_time = MAX(expire_time, 0);
414 ts->next = *pt;
d73415a3 415 qatomic_set(pt, ts);
0f809e5f
PB
416
417 return pt == &timer_list->active_timers;
418}
419
420static void timerlist_rearm(QEMUTimerList *timer_list)
421{
422 /* Interrupt execution to force deadline recalculation. */
740b1759 423 if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
8191d368 424 icount_start_warp_timer();
e76d1798 425 }
0f809e5f
PB
426 timerlist_notify(timer_list);
427}
428
978f2205
SH
429/* stop a timer, but do not dealloc it */
430void timer_del(QEMUTimer *ts)
431{
432 QEMUTimerList *timer_list = ts->timer_list;
433
cd1bd53a
PB
434 if (timer_list) {
435 qemu_mutex_lock(&timer_list->active_timers_lock);
436 timer_del_locked(timer_list, ts);
437 qemu_mutex_unlock(&timer_list->active_timers_lock);
438 }
978f2205
SH
439}
440
db1a4972
PB
441/* modify the current timer so that it will be fired when current_time
442 >= expire_time. The corresponding callback will be called. */
40daca54 443void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
db1a4972 444{
978f2205 445 QEMUTimerList *timer_list = ts->timer_list;
0f809e5f 446 bool rearm;
db1a4972 447
978f2205
SH
448 qemu_mutex_lock(&timer_list->active_timers_lock);
449 timer_del_locked(timer_list, ts);
0f809e5f 450 rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
978f2205 451 qemu_mutex_unlock(&timer_list->active_timers_lock);
db1a4972 452
0f809e5f
PB
453 if (rearm) {
454 timerlist_rearm(timer_list);
db1a4972
PB
455 }
456}
457
add40e97
PB
458/* modify the current timer so that it will be fired when current_time
459 >= expire_time or the current deadline, whichever comes earlier.
460 The corresponding callback will be called. */
461void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
462{
463 QEMUTimerList *timer_list = ts->timer_list;
464 bool rearm;
465
6e8a355d
DB
466 WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
467 if (ts->expire_time == -1 || ts->expire_time > expire_time) {
468 if (ts->expire_time != -1) {
469 timer_del_locked(timer_list, ts);
470 }
471 rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
472 } else {
473 rearm = false;
add40e97 474 }
add40e97 475 }
add40e97
PB
476 if (rearm) {
477 timerlist_rearm(timer_list);
478 }
479}
480
40daca54 481void timer_mod(QEMUTimer *ts, int64_t expire_time)
4a998740 482{
40daca54 483 timer_mod_ns(ts, expire_time * ts->scale);
4a998740
PB
484}
485
add40e97
PB
486void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
487{
488 timer_mod_anticipate_ns(ts, expire_time * ts->scale);
489}
490
e93379b0 491bool timer_pending(QEMUTimer *ts)
db1a4972 492{
3db1ee7c 493 return ts->expire_time >= 0;
db1a4972
PB
494}
495
e93379b0 496bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
db1a4972 497{
e93379b0 498 return timer_expired_ns(timer_head, current_time * timer_head->scale);
db1a4972
PB
499}
500
ff83c66e 501bool timerlist_run_timers(QEMUTimerList *timer_list)
db1a4972 502{
144b97c2 503 QEMUTimer *ts;
db1a4972 504 int64_t current_time;
f9a976b7 505 bool progress = false;
978f2205
SH
506 QEMUTimerCB *cb;
507 void *opaque;
508
d73415a3 509 if (!qatomic_read(&timer_list->active_timers)) {
8caa05d8
PB
510 return false;
511 }
512
3c053411 513 qemu_event_reset(&timer_list->timers_done_ev);
8caa05d8 514 if (!timer_list->clock->enabled) {
3c053411 515 goto out;
ff83c66e 516 }
db1a4972 517
8bd7f71d
PD
518 switch (timer_list->clock->type) {
519 case QEMU_CLOCK_REALTIME:
520 break;
521 default:
522 case QEMU_CLOCK_VIRTUAL:
8bd7f71d
PD
523 break;
524 case QEMU_CLOCK_HOST:
525 if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
526 goto out;
527 }
528 break;
529 case QEMU_CLOCK_VIRTUAL_RT:
530 if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) {
531 goto out;
532 }
533 break;
534 }
535
e81f8679 536 /*
3cf10b29 537 * Extract expired timers from active timers list and process them.
e81f8679
AP
538 *
539 * In rr mode we need "filtered" checkpointing for virtual clock. The
540 * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer,
541 * and that must only be done once since the clock value stays the same. Because
542 * non-EXTERNAL timers may appear in the timers list while it being processed,
543 * the checkpoint can be issued at a time until no timers are left and we are
544 * done".
545 */
40daca54 546 current_time = qemu_clock_get_ns(timer_list->clock->type);
e81f8679
AP
547 qemu_mutex_lock(&timer_list->active_timers_lock);
548 while ((ts = timer_list->active_timers)) {
e93379b0 549 if (!timer_expired_ns(ts, current_time)) {
e81f8679
AP
550 /* No expired timers left. The checkpoint can be skipped
551 * if no timers fired or they were all external.
552 */
db1a4972 553 break;
45c7b37f 554 }
677a3bab
PD
555 /* Checkpoint for virtual clock is redundant in cases where
556 * it's being triggered with only non-EXTERNAL timers, because
557 * these timers don't change guest state directly.
558 */
559 if (replay_mode != REPLAY_MODE_NONE
560 && timer_list->clock->type == QEMU_CLOCK_VIRTUAL
561 && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)
562 && !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
e81f8679 563 qemu_mutex_unlock(&timer_list->active_timers_lock);
677a3bab 564 goto out;
e81f8679 565 }
978f2205 566
db1a4972 567 /* remove timer from the list before calling the callback */
ff83c66e 568 timer_list->active_timers = ts->next;
db1a4972 569 ts->next = NULL;
3db1ee7c 570 ts->expire_time = -1;
978f2205
SH
571 cb = ts->cb;
572 opaque = ts->opaque;
db1a4972
PB
573
574 /* run the callback (the timer list can be modified) */
e81f8679 575 qemu_mutex_unlock(&timer_list->active_timers_lock);
978f2205 576 cb(opaque);
e81f8679
AP
577 qemu_mutex_lock(&timer_list->active_timers_lock);
578
f9a976b7 579 progress = true;
db1a4972 580 }
e81f8679 581 qemu_mutex_unlock(&timer_list->active_timers_lock);
3c053411
LPF
582
583out:
584 qemu_event_set(&timer_list->timers_done_ev);
f9a976b7 585 return progress;
db1a4972
PB
586}
587
40daca54
AB
588bool qemu_clock_run_timers(QEMUClockType type)
589{
7bf8fbde 590 return timerlist_run_timers(main_loop_tlg.tl[type]);
40daca54
AB
591}
592
d5541d86
AB
593void timerlistgroup_init(QEMUTimerListGroup *tlg,
594 QEMUTimerListNotifyCB *cb, void *opaque)
754d6a54
AB
595{
596 QEMUClockType type;
597 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
d5541d86 598 tlg->tl[type] = timerlist_new(type, cb, opaque);
754d6a54
AB
599 }
600}
601
602void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
603{
604 QEMUClockType type;
605 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
606 timerlist_free(tlg->tl[type]);
607 }
608}
609
610bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
611{
612 QEMUClockType type;
613 bool progress = false;
614 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
615 progress |= timerlist_run_timers(tlg->tl[type]);
616 }
617 return progress;
618}
619
620int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
621{
622 int64_t deadline = -1;
623 QEMUClockType type;
624 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
8bd7f71d 625 if (qemu_clock_use_for_deadline(type)) {
e4dab944
PD
626 deadline = qemu_soonest_timeout(deadline,
627 timerlist_deadline_ns(tlg->tl[type]));
754d6a54
AB
628 }
629 }
630 return deadline;
631}
632
40daca54 633int64_t qemu_clock_get_ns(QEMUClockType type)
db1a4972 634{
40daca54 635 switch (type) {
db1a4972
PB
636 case QEMU_CLOCK_REALTIME:
637 return get_clock();
638 default:
639 case QEMU_CLOCK_VIRTUAL:
430065da 640 return cpus_get_virtual_clock();
db1a4972 641 case QEMU_CLOCK_HOST:
3c2d4c8a 642 return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
4e7fa73e 643 case QEMU_CLOCK_VIRTUAL_RT:
8eda206e 644 return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
db1a4972
PB
645 }
646}
647
3f53bc61 648void init_clocks(QEMUTimerListNotifyCB *notify_cb)
db1a4972 649{
ff83c66e
AB
650 QEMUClockType type;
651 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
3f53bc61 652 qemu_clock_init(type, notify_cb);
744ca8e3 653 }
ff83c66e 654
cd758dd0
AB
655#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
656 prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
657#endif
db1a4972
PB
658}
659
e93379b0 660uint64_t timer_expire_time_ns(QEMUTimer *ts)
db1a4972 661{
e93379b0 662 return timer_pending(ts) ? ts->expire_time : -1;
db1a4972
PB
663}
664
40daca54 665bool qemu_clock_run_all_timers(void)
db1a4972 666{
f9a976b7 667 bool progress = false;
ff83c66e 668 QEMUClockType type;
6d327171 669
ff83c66e 670 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
6b8f0187
PB
671 if (qemu_clock_use_for_deadline(type)) {
672 progress |= qemu_clock_run_timers(type);
673 }
ff83c66e 674 }
158fd3ce 675
f9a976b7 676 return progress;
db1a4972 677}