xref: /qemu/util/qemu-timer.c (revision 490309fcfbed9fa1ed357541f609975016a34628)
1db1a4972SPaolo Bonzini /*
2db1a4972SPaolo Bonzini  * QEMU System Emulator
3db1a4972SPaolo Bonzini  *
4db1a4972SPaolo Bonzini  * Copyright (c) 2003-2008 Fabrice Bellard
5db1a4972SPaolo Bonzini  *
6db1a4972SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
7db1a4972SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
8db1a4972SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
9db1a4972SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10db1a4972SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
11db1a4972SPaolo Bonzini  * furnished to do so, subject to the following conditions:
12db1a4972SPaolo Bonzini  *
13db1a4972SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
14db1a4972SPaolo Bonzini  * all copies or substantial portions of the Software.
15db1a4972SPaolo Bonzini  *
16db1a4972SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17db1a4972SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18db1a4972SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19db1a4972SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20db1a4972SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21db1a4972SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22db1a4972SPaolo Bonzini  * THE SOFTWARE.
23db1a4972SPaolo Bonzini  */
24db1a4972SPaolo Bonzini 
259c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
2683c9089eSPaolo Bonzini #include "monitor/monitor.h"
2728ecbaeeSPaolo Bonzini #include "ui/console.h"
28db1a4972SPaolo Bonzini 
29db1a4972SPaolo Bonzini #include "hw/hw.h"
30db1a4972SPaolo Bonzini 
311de7afc9SPaolo Bonzini #include "qemu/timer.h"
3230ea8339SAnthony Liguori #ifdef CONFIG_POSIX
3330ea8339SAnthony Liguori #include <pthread.h>
3430ea8339SAnthony Liguori #endif
35bff9f8bfSStefan Weil 
364e0c6529SAlex Bligh #ifdef CONFIG_PPOLL
374e0c6529SAlex Bligh #include <poll.h>
384e0c6529SAlex Bligh #endif
394e0c6529SAlex Bligh 
40cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
41cd758dd0SAlex Bligh #include <sys/prctl.h>
42cd758dd0SAlex Bligh #endif
43cd758dd0SAlex Bligh 
44db1a4972SPaolo Bonzini /***********************************************************/
45db1a4972SPaolo Bonzini /* timers */
46db1a4972SPaolo Bonzini 
47b4049b74SAlex Bligh typedef struct QEMUClock {
483c053411SLiu Ping Fan     /* We rely on BQL to protect the timerlists */
49ff83c66eSAlex Bligh     QLIST_HEAD(, QEMUTimerList) timerlists;
50691a0c9cSJan Kiszka 
51691a0c9cSJan Kiszka     NotifierList reset_notifiers;
52691a0c9cSJan Kiszka     int64_t last;
539a14b298SStefan Weil 
54ff83c66eSAlex Bligh     QEMUClockType type;
559a14b298SStefan Weil     bool enabled;
56b4049b74SAlex Bligh } QEMUClock;
57db1a4972SPaolo Bonzini 
58754d6a54SAlex Bligh QEMUTimerListGroup main_loop_tlg;
59fbdb664cSStefan Weil static QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
60ff83c66eSAlex Bligh 
61ff83c66eSAlex Bligh /* A QEMUTimerList is a list of timers attached to a clock. More
62ff83c66eSAlex Bligh  * than one QEMUTimerList can be attached to each clock, for instance
63ff83c66eSAlex Bligh  * used by different AioContexts / threads. Each clock also has
64ff83c66eSAlex Bligh  * a list of the QEMUTimerLists associated with it, in order that
65ff83c66eSAlex Bligh  * reenabling the clock can call all the notifiers.
66ff83c66eSAlex Bligh  */
67ff83c66eSAlex Bligh 
68ff83c66eSAlex Bligh struct QEMUTimerList {
699a14b298SStefan Weil     QEMUClock *clock;
70978f2205SStefan Hajnoczi     QemuMutex active_timers_lock;
71ff83c66eSAlex Bligh     QEMUTimer *active_timers;
72ff83c66eSAlex Bligh     QLIST_ENTRY(QEMUTimerList) list;
73d5541d86SAlex Bligh     QEMUTimerListNotifyCB *notify_cb;
74d5541d86SAlex Bligh     void *notify_opaque;
753c053411SLiu Ping Fan 
763c053411SLiu Ping Fan     /* lightweight method to mark the end of timerlist's running */
773c053411SLiu Ping Fan     QemuEvent timers_done_ev;
78db1a4972SPaolo Bonzini };
79db1a4972SPaolo Bonzini 
807bf8fbdeSAlex Bligh /**
817bf8fbdeSAlex Bligh  * qemu_clock_ptr:
827bf8fbdeSAlex Bligh  * @type: type of clock
837bf8fbdeSAlex Bligh  *
847bf8fbdeSAlex Bligh  * Translate a clock type into a pointer to QEMUClock object.
857bf8fbdeSAlex Bligh  *
867bf8fbdeSAlex Bligh  * Returns: a pointer to the QEMUClock object
877bf8fbdeSAlex Bligh  */
88b4049b74SAlex Bligh static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
897bf8fbdeSAlex Bligh {
907bf8fbdeSAlex Bligh     return &qemu_clocks[type];
917bf8fbdeSAlex Bligh }
927bf8fbdeSAlex Bligh 
93e93379b0SAlex Bligh static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
9445c7b37fSStefan Weil {
9545c7b37fSStefan Weil     return timer_head && (timer_head->expire_time <= current_time);
9645c7b37fSStefan Weil }
9745c7b37fSStefan Weil 
987bf8fbdeSAlex Bligh QEMUTimerList *timerlist_new(QEMUClockType type,
99d5541d86SAlex Bligh                              QEMUTimerListNotifyCB *cb,
100d5541d86SAlex Bligh                              void *opaque)
101ff83c66eSAlex Bligh {
102ff83c66eSAlex Bligh     QEMUTimerList *timer_list;
1037bf8fbdeSAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
104ff83c66eSAlex Bligh 
105ff83c66eSAlex Bligh     timer_list = g_malloc0(sizeof(QEMUTimerList));
1063c053411SLiu Ping Fan     qemu_event_init(&timer_list->timers_done_ev, false);
107ff83c66eSAlex Bligh     timer_list->clock = clock;
108d5541d86SAlex Bligh     timer_list->notify_cb = cb;
109d5541d86SAlex Bligh     timer_list->notify_opaque = opaque;
110978f2205SStefan Hajnoczi     qemu_mutex_init(&timer_list->active_timers_lock);
111ff83c66eSAlex Bligh     QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
112ff83c66eSAlex Bligh     return timer_list;
113ff83c66eSAlex Bligh }
114ff83c66eSAlex Bligh 
115ff83c66eSAlex Bligh void timerlist_free(QEMUTimerList *timer_list)
116ff83c66eSAlex Bligh {
117ff83c66eSAlex Bligh     assert(!timerlist_has_timers(timer_list));
118ff83c66eSAlex Bligh     if (timer_list->clock) {
119ff83c66eSAlex Bligh         QLIST_REMOVE(timer_list, list);
120ff83c66eSAlex Bligh     }
121978f2205SStefan Hajnoczi     qemu_mutex_destroy(&timer_list->active_timers_lock);
122ff83c66eSAlex Bligh     g_free(timer_list);
123ff83c66eSAlex Bligh }
124ff83c66eSAlex Bligh 
1257bf8fbdeSAlex Bligh static void qemu_clock_init(QEMUClockType type)
126db1a4972SPaolo Bonzini {
1277bf8fbdeSAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
128691a0c9cSJan Kiszka 
12902ce232cSKirill Batuzov     /* Assert that the clock of type TYPE has not been initialized yet. */
13002ce232cSKirill Batuzov     assert(main_loop_tlg.tl[type] == NULL);
13102ce232cSKirill Batuzov 
132db1a4972SPaolo Bonzini     clock->type = type;
1335e1ec7b2SStefan Weil     clock->enabled = true;
1342ff68d07SPaolo Bonzini     clock->last = INT64_MIN;
135ff83c66eSAlex Bligh     QLIST_INIT(&clock->timerlists);
136691a0c9cSJan Kiszka     notifier_list_init(&clock->reset_notifiers);
1377bf8fbdeSAlex Bligh     main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
138db1a4972SPaolo Bonzini }
139db1a4972SPaolo Bonzini 
14040daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type)
141ff83c66eSAlex Bligh {
14240daca54SAlex Bligh     return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
143ff83c66eSAlex Bligh }
144ff83c66eSAlex Bligh 
14540daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type)
146b1bbfe72SAlex Bligh {
147b1bbfe72SAlex Bligh     QEMUTimerList *timer_list;
14840daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
149b1bbfe72SAlex Bligh     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
150b1bbfe72SAlex Bligh         timerlist_notify(timer_list);
151b1bbfe72SAlex Bligh     }
152b1bbfe72SAlex Bligh }
153b1bbfe72SAlex Bligh 
1543c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop
1553c053411SLiu Ping Fan  * executing qemu_run_timers.  Thus, this functions should not
1563c053411SLiu Ping Fan  * be used from the callback of a timer that is based on @clock.
1573c053411SLiu Ping Fan  * Doing so would cause a deadlock.
1583c053411SLiu Ping Fan  *
1593c053411SLiu Ping Fan  * Caller should hold BQL.
1603c053411SLiu Ping Fan  */
16140daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled)
162db1a4972SPaolo Bonzini {
16340daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
1643c053411SLiu Ping Fan     QEMUTimerList *tl;
165fbdc14ebSPaolo Bonzini     bool old = clock->enabled;
166db1a4972SPaolo Bonzini     clock->enabled = enabled;
167fbdc14ebSPaolo Bonzini     if (enabled && !old) {
16840daca54SAlex Bligh         qemu_clock_notify(type);
1693c053411SLiu Ping Fan     } else if (!enabled && old) {
1703c053411SLiu Ping Fan         QLIST_FOREACH(tl, &clock->timerlists, list) {
1713c053411SLiu Ping Fan             qemu_event_wait(&tl->timers_done_ev);
1723c053411SLiu Ping Fan         }
173fbdc14ebSPaolo Bonzini     }
174db1a4972SPaolo Bonzini }
175db1a4972SPaolo Bonzini 
176ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list)
177dc2dfcf0SPaolo Bonzini {
178ff83c66eSAlex Bligh     return !!timer_list->active_timers;
179dc2dfcf0SPaolo Bonzini }
180dc2dfcf0SPaolo Bonzini 
18140daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type)
182dc2dfcf0SPaolo Bonzini {
18340daca54SAlex Bligh     return timerlist_has_timers(
1847bf8fbdeSAlex Bligh         main_loop_tlg.tl[type]);
185dc2dfcf0SPaolo Bonzini }
186dc2dfcf0SPaolo Bonzini 
187ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list)
188ff83c66eSAlex Bligh {
189978f2205SStefan Hajnoczi     int64_t expire_time;
190978f2205SStefan Hajnoczi 
191978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
192978f2205SStefan Hajnoczi     if (!timer_list->active_timers) {
193978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
194978f2205SStefan Hajnoczi         return false;
195978f2205SStefan Hajnoczi     }
196978f2205SStefan Hajnoczi     expire_time = timer_list->active_timers->expire_time;
197978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
198978f2205SStefan Hajnoczi 
199978f2205SStefan Hajnoczi     return expire_time < qemu_clock_get_ns(timer_list->clock->type);
200ff83c66eSAlex Bligh }
201ff83c66eSAlex Bligh 
20240daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type)
203ff83c66eSAlex Bligh {
20440daca54SAlex Bligh     return timerlist_expired(
2057bf8fbdeSAlex Bligh         main_loop_tlg.tl[type]);
206ff83c66eSAlex Bligh }
207ff83c66eSAlex Bligh 
20802a03a9fSAlex Bligh /*
20902a03a9fSAlex Bligh  * As above, but return -1 for no deadline, and do not cap to 2^32
21002a03a9fSAlex Bligh  * as we know the result is always positive.
21102a03a9fSAlex Bligh  */
21202a03a9fSAlex Bligh 
213ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
21402a03a9fSAlex Bligh {
21502a03a9fSAlex Bligh     int64_t delta;
216978f2205SStefan Hajnoczi     int64_t expire_time;
21702a03a9fSAlex Bligh 
218978f2205SStefan Hajnoczi     if (!timer_list->clock->enabled) {
21902a03a9fSAlex Bligh         return -1;
22002a03a9fSAlex Bligh     }
22102a03a9fSAlex Bligh 
222978f2205SStefan Hajnoczi     /* The active timers list may be modified before the caller uses our return
223978f2205SStefan Hajnoczi      * value but ->notify_cb() is called when the deadline changes.  Therefore
224978f2205SStefan Hajnoczi      * the caller should notice the change and there is no race condition.
225978f2205SStefan Hajnoczi      */
226978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
227978f2205SStefan Hajnoczi     if (!timer_list->active_timers) {
228978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
229978f2205SStefan Hajnoczi         return -1;
230978f2205SStefan Hajnoczi     }
231978f2205SStefan Hajnoczi     expire_time = timer_list->active_timers->expire_time;
232978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
233978f2205SStefan Hajnoczi 
234978f2205SStefan Hajnoczi     delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
23502a03a9fSAlex Bligh 
23602a03a9fSAlex Bligh     if (delta <= 0) {
23702a03a9fSAlex Bligh         return 0;
23802a03a9fSAlex Bligh     }
23902a03a9fSAlex Bligh 
24002a03a9fSAlex Bligh     return delta;
24102a03a9fSAlex Bligh }
24202a03a9fSAlex Bligh 
243ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached
244ac70aafcSAlex Bligh  * to the clock. This is used for the icount timeout so we
245ac70aafcSAlex Bligh  * ignore whether or not the clock should be used in deadline
246ac70aafcSAlex Bligh  * calculations.
247ac70aafcSAlex Bligh  */
24840daca54SAlex Bligh int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
249ac70aafcSAlex Bligh {
250ac70aafcSAlex Bligh     int64_t deadline = -1;
251ac70aafcSAlex Bligh     QEMUTimerList *timer_list;
25240daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
253ac70aafcSAlex Bligh     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
254ac70aafcSAlex Bligh         deadline = qemu_soonest_timeout(deadline,
255ac70aafcSAlex Bligh                                         timerlist_deadline_ns(timer_list));
256ac70aafcSAlex Bligh     }
257ac70aafcSAlex Bligh     return deadline;
258ac70aafcSAlex Bligh }
259ac70aafcSAlex Bligh 
26040daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
261ff83c66eSAlex Bligh {
26240daca54SAlex Bligh     return timer_list->clock->type;
263ff83c66eSAlex Bligh }
264ff83c66eSAlex Bligh 
26540daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
266ff83c66eSAlex Bligh {
2677bf8fbdeSAlex Bligh     return main_loop_tlg.tl[type];
268ff83c66eSAlex Bligh }
269ff83c66eSAlex Bligh 
270d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list)
271d5541d86SAlex Bligh {
272d5541d86SAlex Bligh     if (timer_list->notify_cb) {
273d5541d86SAlex Bligh         timer_list->notify_cb(timer_list->notify_opaque);
274d5541d86SAlex Bligh     } else {
275d5541d86SAlex Bligh         qemu_notify_event();
276d5541d86SAlex Bligh     }
277d5541d86SAlex Bligh }
278d5541d86SAlex Bligh 
27902a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms
28002a03a9fSAlex Bligh  * This is used where a system does not support ppoll
28102a03a9fSAlex Bligh  */
28202a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns)
28302a03a9fSAlex Bligh {
28402a03a9fSAlex Bligh     int64_t ms;
28502a03a9fSAlex Bligh     if (ns < 0) {
28602a03a9fSAlex Bligh         return -1;
28702a03a9fSAlex Bligh     }
28802a03a9fSAlex Bligh 
28902a03a9fSAlex Bligh     if (!ns) {
29002a03a9fSAlex Bligh         return 0;
29102a03a9fSAlex Bligh     }
29202a03a9fSAlex Bligh 
29302a03a9fSAlex Bligh     /* Always round up, because it's better to wait too long than to wait too
29402a03a9fSAlex Bligh      * little and effectively busy-wait
29502a03a9fSAlex Bligh      */
29602a03a9fSAlex Bligh     ms = (ns + SCALE_MS - 1) / SCALE_MS;
29702a03a9fSAlex Bligh 
29802a03a9fSAlex Bligh     /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
29902a03a9fSAlex Bligh     if (ms > (int64_t) INT32_MAX) {
30002a03a9fSAlex Bligh         ms = INT32_MAX;
30102a03a9fSAlex Bligh     }
30202a03a9fSAlex Bligh 
30302a03a9fSAlex Bligh     return (int) ms;
30402a03a9fSAlex Bligh }
30502a03a9fSAlex Bligh 
30602a03a9fSAlex Bligh 
3074e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is
3084e0c6529SAlex Bligh  * otherwise identical to g_poll
3094e0c6529SAlex Bligh  */
3104e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
3114e0c6529SAlex Bligh {
3124e0c6529SAlex Bligh #ifdef CONFIG_PPOLL
3134e0c6529SAlex Bligh     if (timeout < 0) {
3144e0c6529SAlex Bligh         return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
3154e0c6529SAlex Bligh     } else {
3164e0c6529SAlex Bligh         struct timespec ts;
317*490309fcSPeter Maydell         int64_t tvsec = timeout / 1000000000LL;
318*490309fcSPeter Maydell         /* Avoid possibly overflowing and specifying a negative number of
319*490309fcSPeter Maydell          * seconds, which would turn a very long timeout into a busy-wait.
320*490309fcSPeter Maydell          */
321*490309fcSPeter Maydell         if (tvsec > (int64_t)INT32_MAX) {
322*490309fcSPeter Maydell             tvsec = INT32_MAX;
323*490309fcSPeter Maydell         }
324*490309fcSPeter Maydell         ts.tv_sec = tvsec;
3254e0c6529SAlex Bligh         ts.tv_nsec = timeout % 1000000000LL;
3264e0c6529SAlex Bligh         return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
3274e0c6529SAlex Bligh     }
3284e0c6529SAlex Bligh #else
3294e0c6529SAlex Bligh     return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
3304e0c6529SAlex Bligh #endif
3314e0c6529SAlex Bligh }
3324e0c6529SAlex Bligh 
3334e0c6529SAlex Bligh 
334ff83c66eSAlex Bligh void timer_init(QEMUTimer *ts,
335ff83c66eSAlex Bligh                 QEMUTimerList *timer_list, int scale,
3364a998740SPaolo Bonzini                 QEMUTimerCB *cb, void *opaque)
337db1a4972SPaolo Bonzini {
338ff83c66eSAlex Bligh     ts->timer_list = timer_list;
339db1a4972SPaolo Bonzini     ts->cb = cb;
340db1a4972SPaolo Bonzini     ts->opaque = opaque;
3414a998740SPaolo Bonzini     ts->scale = scale;
3423db1ee7cSPaolo Bonzini     ts->expire_time = -1;
343ff83c66eSAlex Bligh }
344ff83c66eSAlex Bligh 
34540daca54SAlex Bligh void timer_free(QEMUTimer *ts)
346db1a4972SPaolo Bonzini {
3477267c094SAnthony Liguori     g_free(ts);
348db1a4972SPaolo Bonzini }
349db1a4972SPaolo Bonzini 
350978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
351db1a4972SPaolo Bonzini {
352db1a4972SPaolo Bonzini     QEMUTimer **pt, *t;
353db1a4972SPaolo Bonzini 
3543db1ee7cSPaolo Bonzini     ts->expire_time = -1;
355978f2205SStefan Hajnoczi     pt = &timer_list->active_timers;
356db1a4972SPaolo Bonzini     for(;;) {
357db1a4972SPaolo Bonzini         t = *pt;
358db1a4972SPaolo Bonzini         if (!t)
359db1a4972SPaolo Bonzini             break;
360db1a4972SPaolo Bonzini         if (t == ts) {
361db1a4972SPaolo Bonzini             *pt = t->next;
362db1a4972SPaolo Bonzini             break;
363db1a4972SPaolo Bonzini         }
364db1a4972SPaolo Bonzini         pt = &t->next;
365db1a4972SPaolo Bonzini     }
366db1a4972SPaolo Bonzini }
367db1a4972SPaolo Bonzini 
3680f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
3690f809e5fSPaolo Bonzini                                 QEMUTimer *ts, int64_t expire_time)
3700f809e5fSPaolo Bonzini {
3710f809e5fSPaolo Bonzini     QEMUTimer **pt, *t;
3720f809e5fSPaolo Bonzini 
3730f809e5fSPaolo Bonzini     /* add the timer in the sorted list */
3740f809e5fSPaolo Bonzini     pt = &timer_list->active_timers;
3750f809e5fSPaolo Bonzini     for (;;) {
3760f809e5fSPaolo Bonzini         t = *pt;
3770f809e5fSPaolo Bonzini         if (!timer_expired_ns(t, expire_time)) {
3780f809e5fSPaolo Bonzini             break;
3790f809e5fSPaolo Bonzini         }
3800f809e5fSPaolo Bonzini         pt = &t->next;
3810f809e5fSPaolo Bonzini     }
3820f809e5fSPaolo Bonzini     ts->expire_time = MAX(expire_time, 0);
3830f809e5fSPaolo Bonzini     ts->next = *pt;
3840f809e5fSPaolo Bonzini     *pt = ts;
3850f809e5fSPaolo Bonzini 
3860f809e5fSPaolo Bonzini     return pt == &timer_list->active_timers;
3870f809e5fSPaolo Bonzini }
3880f809e5fSPaolo Bonzini 
3890f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list)
3900f809e5fSPaolo Bonzini {
3910f809e5fSPaolo Bonzini     /* Interrupt execution to force deadline recalculation.  */
3920f809e5fSPaolo Bonzini     qemu_clock_warp(timer_list->clock->type);
3930f809e5fSPaolo Bonzini     timerlist_notify(timer_list);
3940f809e5fSPaolo Bonzini }
3950f809e5fSPaolo Bonzini 
396978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */
397978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts)
398978f2205SStefan Hajnoczi {
399978f2205SStefan Hajnoczi     QEMUTimerList *timer_list = ts->timer_list;
400978f2205SStefan Hajnoczi 
401978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
402978f2205SStefan Hajnoczi     timer_del_locked(timer_list, ts);
403978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
404978f2205SStefan Hajnoczi }
405978f2205SStefan Hajnoczi 
406db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time
407db1a4972SPaolo Bonzini    >= expire_time. The corresponding callback will be called. */
40840daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
409db1a4972SPaolo Bonzini {
410978f2205SStefan Hajnoczi     QEMUTimerList *timer_list = ts->timer_list;
4110f809e5fSPaolo Bonzini     bool rearm;
412db1a4972SPaolo Bonzini 
413978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
414978f2205SStefan Hajnoczi     timer_del_locked(timer_list, ts);
4150f809e5fSPaolo Bonzini     rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
416978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
417db1a4972SPaolo Bonzini 
4180f809e5fSPaolo Bonzini     if (rearm) {
4190f809e5fSPaolo Bonzini         timerlist_rearm(timer_list);
420db1a4972SPaolo Bonzini     }
421db1a4972SPaolo Bonzini }
422db1a4972SPaolo Bonzini 
423add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time
424add40e97SPaolo Bonzini    >= expire_time or the current deadline, whichever comes earlier.
425add40e97SPaolo Bonzini    The corresponding callback will be called. */
426add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
427add40e97SPaolo Bonzini {
428add40e97SPaolo Bonzini     QEMUTimerList *timer_list = ts->timer_list;
429add40e97SPaolo Bonzini     bool rearm;
430add40e97SPaolo Bonzini 
431add40e97SPaolo Bonzini     qemu_mutex_lock(&timer_list->active_timers_lock);
432add40e97SPaolo Bonzini     if (ts->expire_time == -1 || ts->expire_time > expire_time) {
433add40e97SPaolo Bonzini         if (ts->expire_time != -1) {
434add40e97SPaolo Bonzini             timer_del_locked(timer_list, ts);
435add40e97SPaolo Bonzini         }
436add40e97SPaolo Bonzini         rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
437add40e97SPaolo Bonzini     } else {
438add40e97SPaolo Bonzini         rearm = false;
439add40e97SPaolo Bonzini     }
440add40e97SPaolo Bonzini     qemu_mutex_unlock(&timer_list->active_timers_lock);
441add40e97SPaolo Bonzini 
442add40e97SPaolo Bonzini     if (rearm) {
443add40e97SPaolo Bonzini         timerlist_rearm(timer_list);
444add40e97SPaolo Bonzini     }
445add40e97SPaolo Bonzini }
446add40e97SPaolo Bonzini 
44740daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time)
4484a998740SPaolo Bonzini {
44940daca54SAlex Bligh     timer_mod_ns(ts, expire_time * ts->scale);
4504a998740SPaolo Bonzini }
4514a998740SPaolo Bonzini 
452add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
453add40e97SPaolo Bonzini {
454add40e97SPaolo Bonzini     timer_mod_anticipate_ns(ts, expire_time * ts->scale);
455add40e97SPaolo Bonzini }
456add40e97SPaolo Bonzini 
457e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts)
458db1a4972SPaolo Bonzini {
4593db1ee7cSPaolo Bonzini     return ts->expire_time >= 0;
460db1a4972SPaolo Bonzini }
461db1a4972SPaolo Bonzini 
462e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
463db1a4972SPaolo Bonzini {
464e93379b0SAlex Bligh     return timer_expired_ns(timer_head, current_time * timer_head->scale);
465db1a4972SPaolo Bonzini }
466db1a4972SPaolo Bonzini 
467ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list)
468db1a4972SPaolo Bonzini {
469144b97c2SPaolo Bonzini     QEMUTimer *ts;
470db1a4972SPaolo Bonzini     int64_t current_time;
471f9a976b7SAlex Bligh     bool progress = false;
472978f2205SStefan Hajnoczi     QEMUTimerCB *cb;
473978f2205SStefan Hajnoczi     void *opaque;
474db1a4972SPaolo Bonzini 
4753c053411SLiu Ping Fan     qemu_event_reset(&timer_list->timers_done_ev);
476ff83c66eSAlex Bligh     if (!timer_list->clock->enabled) {
4773c053411SLiu Ping Fan         goto out;
478ff83c66eSAlex Bligh     }
479db1a4972SPaolo Bonzini 
48040daca54SAlex Bligh     current_time = qemu_clock_get_ns(timer_list->clock->type);
481db1a4972SPaolo Bonzini     for(;;) {
482978f2205SStefan Hajnoczi         qemu_mutex_lock(&timer_list->active_timers_lock);
483ff83c66eSAlex Bligh         ts = timer_list->active_timers;
484e93379b0SAlex Bligh         if (!timer_expired_ns(ts, current_time)) {
485978f2205SStefan Hajnoczi             qemu_mutex_unlock(&timer_list->active_timers_lock);
486db1a4972SPaolo Bonzini             break;
48745c7b37fSStefan Weil         }
488978f2205SStefan Hajnoczi 
489db1a4972SPaolo Bonzini         /* remove timer from the list before calling the callback */
490ff83c66eSAlex Bligh         timer_list->active_timers = ts->next;
491db1a4972SPaolo Bonzini         ts->next = NULL;
4923db1ee7cSPaolo Bonzini         ts->expire_time = -1;
493978f2205SStefan Hajnoczi         cb = ts->cb;
494978f2205SStefan Hajnoczi         opaque = ts->opaque;
495978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
496db1a4972SPaolo Bonzini 
497db1a4972SPaolo Bonzini         /* run the callback (the timer list can be modified) */
498978f2205SStefan Hajnoczi         cb(opaque);
499f9a976b7SAlex Bligh         progress = true;
500db1a4972SPaolo Bonzini     }
5013c053411SLiu Ping Fan 
5023c053411SLiu Ping Fan out:
5033c053411SLiu Ping Fan     qemu_event_set(&timer_list->timers_done_ev);
504f9a976b7SAlex Bligh     return progress;
505db1a4972SPaolo Bonzini }
506db1a4972SPaolo Bonzini 
50740daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type)
50840daca54SAlex Bligh {
5097bf8fbdeSAlex Bligh     return timerlist_run_timers(main_loop_tlg.tl[type]);
51040daca54SAlex Bligh }
51140daca54SAlex Bligh 
512d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg,
513d5541d86SAlex Bligh                          QEMUTimerListNotifyCB *cb, void *opaque)
514754d6a54SAlex Bligh {
515754d6a54SAlex Bligh     QEMUClockType type;
516754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
517d5541d86SAlex Bligh         tlg->tl[type] = timerlist_new(type, cb, opaque);
518754d6a54SAlex Bligh     }
519754d6a54SAlex Bligh }
520754d6a54SAlex Bligh 
521754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
522754d6a54SAlex Bligh {
523754d6a54SAlex Bligh     QEMUClockType type;
524754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
525754d6a54SAlex Bligh         timerlist_free(tlg->tl[type]);
526754d6a54SAlex Bligh     }
527754d6a54SAlex Bligh }
528754d6a54SAlex Bligh 
529754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
530754d6a54SAlex Bligh {
531754d6a54SAlex Bligh     QEMUClockType type;
532754d6a54SAlex Bligh     bool progress = false;
533754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
534754d6a54SAlex Bligh         progress |= timerlist_run_timers(tlg->tl[type]);
535754d6a54SAlex Bligh     }
536754d6a54SAlex Bligh     return progress;
537754d6a54SAlex Bligh }
538754d6a54SAlex Bligh 
539754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
540754d6a54SAlex Bligh {
541754d6a54SAlex Bligh     int64_t deadline = -1;
542754d6a54SAlex Bligh     QEMUClockType type;
543754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
54440daca54SAlex Bligh         if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
545754d6a54SAlex Bligh             deadline = qemu_soonest_timeout(deadline,
546754d6a54SAlex Bligh                                             timerlist_deadline_ns(
547754d6a54SAlex Bligh                                                 tlg->tl[type]));
548754d6a54SAlex Bligh         }
549754d6a54SAlex Bligh     }
550754d6a54SAlex Bligh     return deadline;
551754d6a54SAlex Bligh }
552754d6a54SAlex Bligh 
55340daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type)
554db1a4972SPaolo Bonzini {
555691a0c9cSJan Kiszka     int64_t now, last;
55640daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
557691a0c9cSJan Kiszka 
55840daca54SAlex Bligh     switch (type) {
559db1a4972SPaolo Bonzini     case QEMU_CLOCK_REALTIME:
560db1a4972SPaolo Bonzini         return get_clock();
561db1a4972SPaolo Bonzini     default:
562db1a4972SPaolo Bonzini     case QEMU_CLOCK_VIRTUAL:
563db1a4972SPaolo Bonzini         if (use_icount) {
564db1a4972SPaolo Bonzini             return cpu_get_icount();
565db1a4972SPaolo Bonzini         } else {
566db1a4972SPaolo Bonzini             return cpu_get_clock();
567db1a4972SPaolo Bonzini         }
568db1a4972SPaolo Bonzini     case QEMU_CLOCK_HOST:
569691a0c9cSJan Kiszka         now = get_clock_realtime();
570691a0c9cSJan Kiszka         last = clock->last;
571691a0c9cSJan Kiszka         clock->last = now;
572691a0c9cSJan Kiszka         if (now < last) {
573691a0c9cSJan Kiszka             notifier_list_notify(&clock->reset_notifiers, &now);
574db1a4972SPaolo Bonzini         }
575691a0c9cSJan Kiszka         return now;
576691a0c9cSJan Kiszka     }
577691a0c9cSJan Kiszka }
578691a0c9cSJan Kiszka 
57940daca54SAlex Bligh void qemu_clock_register_reset_notifier(QEMUClockType type,
58040daca54SAlex Bligh                                         Notifier *notifier)
58140daca54SAlex Bligh {
58240daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
583691a0c9cSJan Kiszka     notifier_list_add(&clock->reset_notifiers, notifier);
584691a0c9cSJan Kiszka }
585691a0c9cSJan Kiszka 
58640daca54SAlex Bligh void qemu_clock_unregister_reset_notifier(QEMUClockType type,
58740daca54SAlex Bligh                                           Notifier *notifier)
588691a0c9cSJan Kiszka {
58931552529SPaolo Bonzini     notifier_remove(notifier);
590db1a4972SPaolo Bonzini }
591db1a4972SPaolo Bonzini 
592db1a4972SPaolo Bonzini void init_clocks(void)
593db1a4972SPaolo Bonzini {
594ff83c66eSAlex Bligh     QEMUClockType type;
595ff83c66eSAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
5967bf8fbdeSAlex Bligh         qemu_clock_init(type);
597ff83c66eSAlex Bligh     }
598ff83c66eSAlex Bligh 
599cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
600cd758dd0SAlex Bligh     prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
601cd758dd0SAlex Bligh #endif
602744ca8e3SPaolo Bonzini }
603db1a4972SPaolo Bonzini 
604e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts)
605db1a4972SPaolo Bonzini {
606e93379b0SAlex Bligh     return timer_pending(ts) ? ts->expire_time : -1;
607db1a4972SPaolo Bonzini }
608db1a4972SPaolo Bonzini 
60940daca54SAlex Bligh bool qemu_clock_run_all_timers(void)
610db1a4972SPaolo Bonzini {
611f9a976b7SAlex Bligh     bool progress = false;
612ff83c66eSAlex Bligh     QEMUClockType type;
6136d327171SAlex Bligh 
614ff83c66eSAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
61540daca54SAlex Bligh         progress |= qemu_clock_run_timers(type);
616ff83c66eSAlex Bligh     }
617158fd3ceSPeter Portante 
618f9a976b7SAlex Bligh     return progress;
619db1a4972SPaolo Bonzini }
620