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