xref: /qemu/util/qemu-timer.c (revision 8caa05d8891d0a09dc4c00908c24c6ddfd872bbe)
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 
25d38ea87aSPeter Maydell #include "qemu/osdep.h"
261ac0206bSPeter Maydell #include "qemu/main-loop.h"
271de7afc9SPaolo Bonzini #include "qemu/timer.h"
288eda206eSPavel Dovgalyuk #include "sysemu/replay.h"
298bd7f71dSPavel Dovgalyuk #include "sysemu/sysemu.h"
301ac0206bSPeter Maydell 
3130ea8339SAnthony Liguori #ifdef CONFIG_POSIX
3230ea8339SAnthony Liguori #include <pthread.h>
3330ea8339SAnthony Liguori #endif
34bff9f8bfSStefan Weil 
354e0c6529SAlex Bligh #ifdef CONFIG_PPOLL
364e0c6529SAlex Bligh #include <poll.h>
374e0c6529SAlex Bligh #endif
384e0c6529SAlex Bligh 
39cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
40cd758dd0SAlex Bligh #include <sys/prctl.h>
41cd758dd0SAlex Bligh #endif
42cd758dd0SAlex Bligh 
43db1a4972SPaolo Bonzini /***********************************************************/
44db1a4972SPaolo Bonzini /* timers */
45db1a4972SPaolo Bonzini 
46b4049b74SAlex Bligh typedef struct QEMUClock {
473c053411SLiu Ping Fan     /* We rely on BQL to protect the timerlists */
48ff83c66eSAlex Bligh     QLIST_HEAD(, QEMUTimerList) timerlists;
49691a0c9cSJan Kiszka 
50691a0c9cSJan Kiszka     NotifierList reset_notifiers;
51691a0c9cSJan Kiszka     int64_t last;
529a14b298SStefan Weil 
53ff83c66eSAlex Bligh     QEMUClockType type;
549a14b298SStefan Weil     bool enabled;
55b4049b74SAlex Bligh } QEMUClock;
56db1a4972SPaolo Bonzini 
57754d6a54SAlex Bligh QEMUTimerListGroup main_loop_tlg;
58fbdb664cSStefan Weil static QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
59ff83c66eSAlex Bligh 
60ff83c66eSAlex Bligh /* A QEMUTimerList is a list of timers attached to a clock. More
61ff83c66eSAlex Bligh  * than one QEMUTimerList can be attached to each clock, for instance
62ff83c66eSAlex Bligh  * used by different AioContexts / threads. Each clock also has
63ff83c66eSAlex Bligh  * a list of the QEMUTimerLists associated with it, in order that
64ff83c66eSAlex Bligh  * reenabling the clock can call all the notifiers.
65ff83c66eSAlex Bligh  */
66ff83c66eSAlex Bligh 
67ff83c66eSAlex Bligh struct QEMUTimerList {
689a14b298SStefan Weil     QEMUClock *clock;
69978f2205SStefan Hajnoczi     QemuMutex active_timers_lock;
70ff83c66eSAlex Bligh     QEMUTimer *active_timers;
71ff83c66eSAlex Bligh     QLIST_ENTRY(QEMUTimerList) list;
72d5541d86SAlex Bligh     QEMUTimerListNotifyCB *notify_cb;
73d5541d86SAlex Bligh     void *notify_opaque;
743c053411SLiu Ping Fan 
753c053411SLiu Ping Fan     /* lightweight method to mark the end of timerlist's running */
763c053411SLiu Ping Fan     QemuEvent timers_done_ev;
77db1a4972SPaolo Bonzini };
78db1a4972SPaolo Bonzini 
797bf8fbdeSAlex Bligh /**
807bf8fbdeSAlex Bligh  * qemu_clock_ptr:
817bf8fbdeSAlex Bligh  * @type: type of clock
827bf8fbdeSAlex Bligh  *
837bf8fbdeSAlex Bligh  * Translate a clock type into a pointer to QEMUClock object.
847bf8fbdeSAlex Bligh  *
857bf8fbdeSAlex Bligh  * Returns: a pointer to the QEMUClock object
867bf8fbdeSAlex Bligh  */
87b4049b74SAlex Bligh static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
887bf8fbdeSAlex Bligh {
897bf8fbdeSAlex Bligh     return &qemu_clocks[type];
907bf8fbdeSAlex Bligh }
917bf8fbdeSAlex Bligh 
92e93379b0SAlex Bligh static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
9345c7b37fSStefan Weil {
9445c7b37fSStefan Weil     return timer_head && (timer_head->expire_time <= current_time);
9545c7b37fSStefan Weil }
9645c7b37fSStefan Weil 
977bf8fbdeSAlex Bligh QEMUTimerList *timerlist_new(QEMUClockType type,
98d5541d86SAlex Bligh                              QEMUTimerListNotifyCB *cb,
99d5541d86SAlex Bligh                              void *opaque)
100ff83c66eSAlex Bligh {
101ff83c66eSAlex Bligh     QEMUTimerList *timer_list;
1027bf8fbdeSAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
103ff83c66eSAlex Bligh 
104ff83c66eSAlex Bligh     timer_list = g_malloc0(sizeof(QEMUTimerList));
105e4efd8a4SPaolo Bonzini     qemu_event_init(&timer_list->timers_done_ev, true);
106ff83c66eSAlex Bligh     timer_list->clock = clock;
107d5541d86SAlex Bligh     timer_list->notify_cb = cb;
108d5541d86SAlex Bligh     timer_list->notify_opaque = opaque;
109978f2205SStefan Hajnoczi     qemu_mutex_init(&timer_list->active_timers_lock);
110ff83c66eSAlex Bligh     QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
111ff83c66eSAlex Bligh     return timer_list;
112ff83c66eSAlex Bligh }
113ff83c66eSAlex Bligh 
114ff83c66eSAlex Bligh void timerlist_free(QEMUTimerList *timer_list)
115ff83c66eSAlex Bligh {
116ff83c66eSAlex Bligh     assert(!timerlist_has_timers(timer_list));
117ff83c66eSAlex Bligh     if (timer_list->clock) {
118ff83c66eSAlex Bligh         QLIST_REMOVE(timer_list, list);
119ff83c66eSAlex Bligh     }
120978f2205SStefan Hajnoczi     qemu_mutex_destroy(&timer_list->active_timers_lock);
121ff83c66eSAlex Bligh     g_free(timer_list);
122ff83c66eSAlex Bligh }
123ff83c66eSAlex Bligh 
1247bf8fbdeSAlex Bligh static void qemu_clock_init(QEMUClockType type)
125db1a4972SPaolo Bonzini {
1267bf8fbdeSAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
127691a0c9cSJan Kiszka 
12802ce232cSKirill Batuzov     /* Assert that the clock of type TYPE has not been initialized yet. */
12902ce232cSKirill Batuzov     assert(main_loop_tlg.tl[type] == NULL);
13002ce232cSKirill Batuzov 
131db1a4972SPaolo Bonzini     clock->type = type;
1323fdd0ee3SGonglei     clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : true);
1332ff68d07SPaolo Bonzini     clock->last = INT64_MIN;
134ff83c66eSAlex Bligh     QLIST_INIT(&clock->timerlists);
135691a0c9cSJan Kiszka     notifier_list_init(&clock->reset_notifiers);
1367bf8fbdeSAlex Bligh     main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
137db1a4972SPaolo Bonzini }
138db1a4972SPaolo Bonzini 
13940daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type)
140ff83c66eSAlex Bligh {
14140daca54SAlex Bligh     return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
142ff83c66eSAlex Bligh }
143ff83c66eSAlex Bligh 
14440daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type)
145b1bbfe72SAlex Bligh {
146b1bbfe72SAlex Bligh     QEMUTimerList *timer_list;
14740daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
148b1bbfe72SAlex Bligh     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
149b1bbfe72SAlex Bligh         timerlist_notify(timer_list);
150b1bbfe72SAlex Bligh     }
151b1bbfe72SAlex Bligh }
152b1bbfe72SAlex Bligh 
1533c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop
1543c053411SLiu Ping Fan  * executing qemu_run_timers.  Thus, this functions should not
1553c053411SLiu Ping Fan  * be used from the callback of a timer that is based on @clock.
1563c053411SLiu Ping Fan  * Doing so would cause a deadlock.
1573c053411SLiu Ping Fan  *
1583c053411SLiu Ping Fan  * Caller should hold BQL.
1593c053411SLiu Ping Fan  */
16040daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled)
161db1a4972SPaolo Bonzini {
16240daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
1633c053411SLiu Ping Fan     QEMUTimerList *tl;
164fbdc14ebSPaolo Bonzini     bool old = clock->enabled;
165db1a4972SPaolo Bonzini     clock->enabled = enabled;
166fbdc14ebSPaolo Bonzini     if (enabled && !old) {
16740daca54SAlex Bligh         qemu_clock_notify(type);
1683c053411SLiu Ping Fan     } else if (!enabled && old) {
1693c053411SLiu Ping Fan         QLIST_FOREACH(tl, &clock->timerlists, list) {
1703c053411SLiu Ping Fan             qemu_event_wait(&tl->timers_done_ev);
1713c053411SLiu Ping Fan         }
172fbdc14ebSPaolo Bonzini     }
173db1a4972SPaolo Bonzini }
174db1a4972SPaolo Bonzini 
175ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list)
176dc2dfcf0SPaolo Bonzini {
177*8caa05d8SPaolo Bonzini     return !!atomic_read(&timer_list->active_timers);
178dc2dfcf0SPaolo Bonzini }
179dc2dfcf0SPaolo Bonzini 
18040daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type)
181dc2dfcf0SPaolo Bonzini {
18240daca54SAlex Bligh     return timerlist_has_timers(
1837bf8fbdeSAlex Bligh         main_loop_tlg.tl[type]);
184dc2dfcf0SPaolo Bonzini }
185dc2dfcf0SPaolo Bonzini 
186ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list)
187ff83c66eSAlex Bligh {
188978f2205SStefan Hajnoczi     int64_t expire_time;
189978f2205SStefan Hajnoczi 
190*8caa05d8SPaolo Bonzini     if (!atomic_read(&timer_list->active_timers)) {
191*8caa05d8SPaolo Bonzini         return false;
192*8caa05d8SPaolo Bonzini     }
193*8caa05d8SPaolo Bonzini 
194978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
195978f2205SStefan Hajnoczi     if (!timer_list->active_timers) {
196978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
197978f2205SStefan Hajnoczi         return false;
198978f2205SStefan Hajnoczi     }
199978f2205SStefan Hajnoczi     expire_time = timer_list->active_timers->expire_time;
200978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
201978f2205SStefan Hajnoczi 
202978f2205SStefan Hajnoczi     return expire_time < qemu_clock_get_ns(timer_list->clock->type);
203ff83c66eSAlex Bligh }
204ff83c66eSAlex Bligh 
20540daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type)
206ff83c66eSAlex Bligh {
20740daca54SAlex Bligh     return timerlist_expired(
2087bf8fbdeSAlex Bligh         main_loop_tlg.tl[type]);
209ff83c66eSAlex Bligh }
210ff83c66eSAlex Bligh 
21102a03a9fSAlex Bligh /*
21202a03a9fSAlex Bligh  * As above, but return -1 for no deadline, and do not cap to 2^32
21302a03a9fSAlex Bligh  * as we know the result is always positive.
21402a03a9fSAlex Bligh  */
21502a03a9fSAlex Bligh 
216ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
21702a03a9fSAlex Bligh {
21802a03a9fSAlex Bligh     int64_t delta;
219978f2205SStefan Hajnoczi     int64_t expire_time;
22002a03a9fSAlex Bligh 
221*8caa05d8SPaolo Bonzini     if (!atomic_read(&timer_list->active_timers)) {
222*8caa05d8SPaolo Bonzini         return -1;
223*8caa05d8SPaolo Bonzini     }
224*8caa05d8SPaolo Bonzini 
225978f2205SStefan Hajnoczi     if (!timer_list->clock->enabled) {
22602a03a9fSAlex Bligh         return -1;
22702a03a9fSAlex Bligh     }
22802a03a9fSAlex Bligh 
229978f2205SStefan Hajnoczi     /* The active timers list may be modified before the caller uses our return
230978f2205SStefan Hajnoczi      * value but ->notify_cb() is called when the deadline changes.  Therefore
231978f2205SStefan Hajnoczi      * the caller should notice the change and there is no race condition.
232978f2205SStefan Hajnoczi      */
233978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
234978f2205SStefan Hajnoczi     if (!timer_list->active_timers) {
235978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
236978f2205SStefan Hajnoczi         return -1;
237978f2205SStefan Hajnoczi     }
238978f2205SStefan Hajnoczi     expire_time = timer_list->active_timers->expire_time;
239978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
240978f2205SStefan Hajnoczi 
241978f2205SStefan Hajnoczi     delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
24202a03a9fSAlex Bligh 
24302a03a9fSAlex Bligh     if (delta <= 0) {
24402a03a9fSAlex Bligh         return 0;
24502a03a9fSAlex Bligh     }
24602a03a9fSAlex Bligh 
24702a03a9fSAlex Bligh     return delta;
24802a03a9fSAlex Bligh }
24902a03a9fSAlex Bligh 
250ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached
251ac70aafcSAlex Bligh  * to the clock. This is used for the icount timeout so we
252ac70aafcSAlex Bligh  * ignore whether or not the clock should be used in deadline
253ac70aafcSAlex Bligh  * calculations.
254ac70aafcSAlex Bligh  */
25540daca54SAlex Bligh int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
256ac70aafcSAlex Bligh {
257ac70aafcSAlex Bligh     int64_t deadline = -1;
258ac70aafcSAlex Bligh     QEMUTimerList *timer_list;
25940daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
260ac70aafcSAlex Bligh     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
261ac70aafcSAlex Bligh         deadline = qemu_soonest_timeout(deadline,
262ac70aafcSAlex Bligh                                         timerlist_deadline_ns(timer_list));
263ac70aafcSAlex Bligh     }
264ac70aafcSAlex Bligh     return deadline;
265ac70aafcSAlex Bligh }
266ac70aafcSAlex Bligh 
26740daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
268ff83c66eSAlex Bligh {
26940daca54SAlex Bligh     return timer_list->clock->type;
270ff83c66eSAlex Bligh }
271ff83c66eSAlex Bligh 
27240daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
273ff83c66eSAlex Bligh {
2747bf8fbdeSAlex Bligh     return main_loop_tlg.tl[type];
275ff83c66eSAlex Bligh }
276ff83c66eSAlex Bligh 
277d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list)
278d5541d86SAlex Bligh {
279d5541d86SAlex Bligh     if (timer_list->notify_cb) {
280d5541d86SAlex Bligh         timer_list->notify_cb(timer_list->notify_opaque);
281d5541d86SAlex Bligh     } else {
282d5541d86SAlex Bligh         qemu_notify_event();
283d5541d86SAlex Bligh     }
284d5541d86SAlex Bligh }
285d5541d86SAlex Bligh 
28602a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms
28702a03a9fSAlex Bligh  * This is used where a system does not support ppoll
28802a03a9fSAlex Bligh  */
28902a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns)
29002a03a9fSAlex Bligh {
29102a03a9fSAlex Bligh     int64_t ms;
29202a03a9fSAlex Bligh     if (ns < 0) {
29302a03a9fSAlex Bligh         return -1;
29402a03a9fSAlex Bligh     }
29502a03a9fSAlex Bligh 
29602a03a9fSAlex Bligh     if (!ns) {
29702a03a9fSAlex Bligh         return 0;
29802a03a9fSAlex Bligh     }
29902a03a9fSAlex Bligh 
30002a03a9fSAlex Bligh     /* Always round up, because it's better to wait too long than to wait too
30102a03a9fSAlex Bligh      * little and effectively busy-wait
30202a03a9fSAlex Bligh      */
3035029b969SLaurent Vivier     ms = DIV_ROUND_UP(ns, SCALE_MS);
30402a03a9fSAlex Bligh 
30502a03a9fSAlex Bligh     /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
30602a03a9fSAlex Bligh     if (ms > (int64_t) INT32_MAX) {
30702a03a9fSAlex Bligh         ms = INT32_MAX;
30802a03a9fSAlex Bligh     }
30902a03a9fSAlex Bligh 
31002a03a9fSAlex Bligh     return (int) ms;
31102a03a9fSAlex Bligh }
31202a03a9fSAlex Bligh 
31302a03a9fSAlex Bligh 
3144e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is
3154e0c6529SAlex Bligh  * otherwise identical to g_poll
3164e0c6529SAlex Bligh  */
3174e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
3184e0c6529SAlex Bligh {
3194e0c6529SAlex Bligh #ifdef CONFIG_PPOLL
3204e0c6529SAlex Bligh     if (timeout < 0) {
3214e0c6529SAlex Bligh         return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
3224e0c6529SAlex Bligh     } else {
3234e0c6529SAlex Bligh         struct timespec ts;
324490309fcSPeter Maydell         int64_t tvsec = timeout / 1000000000LL;
325490309fcSPeter Maydell         /* Avoid possibly overflowing and specifying a negative number of
326490309fcSPeter Maydell          * seconds, which would turn a very long timeout into a busy-wait.
327490309fcSPeter Maydell          */
328490309fcSPeter Maydell         if (tvsec > (int64_t)INT32_MAX) {
329490309fcSPeter Maydell             tvsec = INT32_MAX;
330490309fcSPeter Maydell         }
331490309fcSPeter Maydell         ts.tv_sec = tvsec;
3324e0c6529SAlex Bligh         ts.tv_nsec = timeout % 1000000000LL;
3334e0c6529SAlex Bligh         return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
3344e0c6529SAlex Bligh     }
3354e0c6529SAlex Bligh #else
3364e0c6529SAlex Bligh     return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
3374e0c6529SAlex Bligh #endif
3384e0c6529SAlex Bligh }
3394e0c6529SAlex Bligh 
3404e0c6529SAlex Bligh 
341f186aa97SPaolo Bonzini void timer_init_tl(QEMUTimer *ts,
342ff83c66eSAlex Bligh                    QEMUTimerList *timer_list, int scale,
3434a998740SPaolo Bonzini                    QEMUTimerCB *cb, void *opaque)
344db1a4972SPaolo Bonzini {
345ff83c66eSAlex Bligh     ts->timer_list = timer_list;
346db1a4972SPaolo Bonzini     ts->cb = cb;
347db1a4972SPaolo Bonzini     ts->opaque = opaque;
3484a998740SPaolo Bonzini     ts->scale = scale;
3493db1ee7cSPaolo Bonzini     ts->expire_time = -1;
350ff83c66eSAlex Bligh }
351ff83c66eSAlex Bligh 
352cd1bd53aSPaolo Bonzini void timer_deinit(QEMUTimer *ts)
353cd1bd53aSPaolo Bonzini {
354cd1bd53aSPaolo Bonzini     assert(ts->expire_time == -1);
355cd1bd53aSPaolo Bonzini     ts->timer_list = NULL;
356cd1bd53aSPaolo Bonzini }
357cd1bd53aSPaolo Bonzini 
35840daca54SAlex Bligh void timer_free(QEMUTimer *ts)
359db1a4972SPaolo Bonzini {
3607267c094SAnthony Liguori     g_free(ts);
361db1a4972SPaolo Bonzini }
362db1a4972SPaolo Bonzini 
363978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
364db1a4972SPaolo Bonzini {
365db1a4972SPaolo Bonzini     QEMUTimer **pt, *t;
366db1a4972SPaolo Bonzini 
3673db1ee7cSPaolo Bonzini     ts->expire_time = -1;
368978f2205SStefan Hajnoczi     pt = &timer_list->active_timers;
369db1a4972SPaolo Bonzini     for(;;) {
370db1a4972SPaolo Bonzini         t = *pt;
371db1a4972SPaolo Bonzini         if (!t)
372db1a4972SPaolo Bonzini             break;
373db1a4972SPaolo Bonzini         if (t == ts) {
374*8caa05d8SPaolo Bonzini             atomic_set(pt, t->next);
375db1a4972SPaolo Bonzini             break;
376db1a4972SPaolo Bonzini         }
377db1a4972SPaolo Bonzini         pt = &t->next;
378db1a4972SPaolo Bonzini     }
379db1a4972SPaolo Bonzini }
380db1a4972SPaolo Bonzini 
3810f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
3820f809e5fSPaolo Bonzini                                 QEMUTimer *ts, int64_t expire_time)
3830f809e5fSPaolo Bonzini {
3840f809e5fSPaolo Bonzini     QEMUTimer **pt, *t;
3850f809e5fSPaolo Bonzini 
3860f809e5fSPaolo Bonzini     /* add the timer in the sorted list */
3870f809e5fSPaolo Bonzini     pt = &timer_list->active_timers;
3880f809e5fSPaolo Bonzini     for (;;) {
3890f809e5fSPaolo Bonzini         t = *pt;
3900f809e5fSPaolo Bonzini         if (!timer_expired_ns(t, expire_time)) {
3910f809e5fSPaolo Bonzini             break;
3920f809e5fSPaolo Bonzini         }
3930f809e5fSPaolo Bonzini         pt = &t->next;
3940f809e5fSPaolo Bonzini     }
3950f809e5fSPaolo Bonzini     ts->expire_time = MAX(expire_time, 0);
3960f809e5fSPaolo Bonzini     ts->next = *pt;
397*8caa05d8SPaolo Bonzini     atomic_set(pt, ts);
3980f809e5fSPaolo Bonzini 
3990f809e5fSPaolo Bonzini     return pt == &timer_list->active_timers;
4000f809e5fSPaolo Bonzini }
4010f809e5fSPaolo Bonzini 
4020f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list)
4030f809e5fSPaolo Bonzini {
4040f809e5fSPaolo Bonzini     /* Interrupt execution to force deadline recalculation.  */
405e76d1798SPavel Dovgalyuk     if (timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
406e76d1798SPavel Dovgalyuk         qemu_start_warp_timer();
407e76d1798SPavel Dovgalyuk     }
4080f809e5fSPaolo Bonzini     timerlist_notify(timer_list);
4090f809e5fSPaolo Bonzini }
4100f809e5fSPaolo Bonzini 
411978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */
412978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts)
413978f2205SStefan Hajnoczi {
414978f2205SStefan Hajnoczi     QEMUTimerList *timer_list = ts->timer_list;
415978f2205SStefan Hajnoczi 
416cd1bd53aSPaolo Bonzini     if (timer_list) {
417978f2205SStefan Hajnoczi         qemu_mutex_lock(&timer_list->active_timers_lock);
418978f2205SStefan Hajnoczi         timer_del_locked(timer_list, ts);
419978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
420978f2205SStefan Hajnoczi     }
421cd1bd53aSPaolo Bonzini }
422978f2205SStefan Hajnoczi 
423db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time
424db1a4972SPaolo Bonzini    >= expire_time. The corresponding callback will be called. */
42540daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
426db1a4972SPaolo Bonzini {
427978f2205SStefan Hajnoczi     QEMUTimerList *timer_list = ts->timer_list;
4280f809e5fSPaolo Bonzini     bool rearm;
429db1a4972SPaolo Bonzini 
430978f2205SStefan Hajnoczi     qemu_mutex_lock(&timer_list->active_timers_lock);
431978f2205SStefan Hajnoczi     timer_del_locked(timer_list, ts);
4320f809e5fSPaolo Bonzini     rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
433978f2205SStefan Hajnoczi     qemu_mutex_unlock(&timer_list->active_timers_lock);
434db1a4972SPaolo Bonzini 
4350f809e5fSPaolo Bonzini     if (rearm) {
4360f809e5fSPaolo Bonzini         timerlist_rearm(timer_list);
437db1a4972SPaolo Bonzini     }
438db1a4972SPaolo Bonzini }
439db1a4972SPaolo Bonzini 
440add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time
441add40e97SPaolo Bonzini    >= expire_time or the current deadline, whichever comes earlier.
442add40e97SPaolo Bonzini    The corresponding callback will be called. */
443add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
444add40e97SPaolo Bonzini {
445add40e97SPaolo Bonzini     QEMUTimerList *timer_list = ts->timer_list;
446add40e97SPaolo Bonzini     bool rearm;
447add40e97SPaolo Bonzini 
448add40e97SPaolo Bonzini     qemu_mutex_lock(&timer_list->active_timers_lock);
449add40e97SPaolo Bonzini     if (ts->expire_time == -1 || ts->expire_time > expire_time) {
450add40e97SPaolo Bonzini         if (ts->expire_time != -1) {
451add40e97SPaolo Bonzini             timer_del_locked(timer_list, ts);
452add40e97SPaolo Bonzini         }
453add40e97SPaolo Bonzini         rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
454add40e97SPaolo Bonzini     } else {
455add40e97SPaolo Bonzini         rearm = false;
456add40e97SPaolo Bonzini     }
457add40e97SPaolo Bonzini     qemu_mutex_unlock(&timer_list->active_timers_lock);
458add40e97SPaolo Bonzini 
459add40e97SPaolo Bonzini     if (rearm) {
460add40e97SPaolo Bonzini         timerlist_rearm(timer_list);
461add40e97SPaolo Bonzini     }
462add40e97SPaolo Bonzini }
463add40e97SPaolo Bonzini 
46440daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time)
4654a998740SPaolo Bonzini {
46640daca54SAlex Bligh     timer_mod_ns(ts, expire_time * ts->scale);
4674a998740SPaolo Bonzini }
4684a998740SPaolo Bonzini 
469add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
470add40e97SPaolo Bonzini {
471add40e97SPaolo Bonzini     timer_mod_anticipate_ns(ts, expire_time * ts->scale);
472add40e97SPaolo Bonzini }
473add40e97SPaolo Bonzini 
474e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts)
475db1a4972SPaolo Bonzini {
4763db1ee7cSPaolo Bonzini     return ts->expire_time >= 0;
477db1a4972SPaolo Bonzini }
478db1a4972SPaolo Bonzini 
479e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
480db1a4972SPaolo Bonzini {
481e93379b0SAlex Bligh     return timer_expired_ns(timer_head, current_time * timer_head->scale);
482db1a4972SPaolo Bonzini }
483db1a4972SPaolo Bonzini 
484ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list)
485db1a4972SPaolo Bonzini {
486144b97c2SPaolo Bonzini     QEMUTimer *ts;
487db1a4972SPaolo Bonzini     int64_t current_time;
488f9a976b7SAlex Bligh     bool progress = false;
489978f2205SStefan Hajnoczi     QEMUTimerCB *cb;
490978f2205SStefan Hajnoczi     void *opaque;
491db1a4972SPaolo Bonzini 
492*8caa05d8SPaolo Bonzini     if (!atomic_read(&timer_list->active_timers)) {
493*8caa05d8SPaolo Bonzini         return false;
494*8caa05d8SPaolo Bonzini     }
495*8caa05d8SPaolo Bonzini 
4963c053411SLiu Ping Fan     qemu_event_reset(&timer_list->timers_done_ev);
497*8caa05d8SPaolo Bonzini     if (!timer_list->clock->enabled) {
4983c053411SLiu Ping Fan         goto out;
499ff83c66eSAlex Bligh     }
500db1a4972SPaolo Bonzini 
5018bd7f71dSPavel Dovgalyuk     switch (timer_list->clock->type) {
5028bd7f71dSPavel Dovgalyuk     case QEMU_CLOCK_REALTIME:
5038bd7f71dSPavel Dovgalyuk         break;
5048bd7f71dSPavel Dovgalyuk     default:
5058bd7f71dSPavel Dovgalyuk     case QEMU_CLOCK_VIRTUAL:
5068bd7f71dSPavel Dovgalyuk         if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
5078bd7f71dSPavel Dovgalyuk             goto out;
5088bd7f71dSPavel Dovgalyuk         }
5098bd7f71dSPavel Dovgalyuk         break;
5108bd7f71dSPavel Dovgalyuk     case QEMU_CLOCK_HOST:
5118bd7f71dSPavel Dovgalyuk         if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
5128bd7f71dSPavel Dovgalyuk             goto out;
5138bd7f71dSPavel Dovgalyuk         }
5148bd7f71dSPavel Dovgalyuk         break;
5158bd7f71dSPavel Dovgalyuk     case QEMU_CLOCK_VIRTUAL_RT:
5168bd7f71dSPavel Dovgalyuk         if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) {
5178bd7f71dSPavel Dovgalyuk             goto out;
5188bd7f71dSPavel Dovgalyuk         }
5198bd7f71dSPavel Dovgalyuk         break;
5208bd7f71dSPavel Dovgalyuk     }
5218bd7f71dSPavel Dovgalyuk 
52240daca54SAlex Bligh     current_time = qemu_clock_get_ns(timer_list->clock->type);
523db1a4972SPaolo Bonzini     for(;;) {
524978f2205SStefan Hajnoczi         qemu_mutex_lock(&timer_list->active_timers_lock);
525ff83c66eSAlex Bligh         ts = timer_list->active_timers;
526e93379b0SAlex Bligh         if (!timer_expired_ns(ts, current_time)) {
527978f2205SStefan Hajnoczi             qemu_mutex_unlock(&timer_list->active_timers_lock);
528db1a4972SPaolo Bonzini             break;
52945c7b37fSStefan Weil         }
530978f2205SStefan Hajnoczi 
531db1a4972SPaolo Bonzini         /* remove timer from the list before calling the callback */
532ff83c66eSAlex Bligh         timer_list->active_timers = ts->next;
533db1a4972SPaolo Bonzini         ts->next = NULL;
5343db1ee7cSPaolo Bonzini         ts->expire_time = -1;
535978f2205SStefan Hajnoczi         cb = ts->cb;
536978f2205SStefan Hajnoczi         opaque = ts->opaque;
537978f2205SStefan Hajnoczi         qemu_mutex_unlock(&timer_list->active_timers_lock);
538db1a4972SPaolo Bonzini 
539db1a4972SPaolo Bonzini         /* run the callback (the timer list can be modified) */
540978f2205SStefan Hajnoczi         cb(opaque);
541f9a976b7SAlex Bligh         progress = true;
542db1a4972SPaolo Bonzini     }
5433c053411SLiu Ping Fan 
5443c053411SLiu Ping Fan out:
5453c053411SLiu Ping Fan     qemu_event_set(&timer_list->timers_done_ev);
546f9a976b7SAlex Bligh     return progress;
547db1a4972SPaolo Bonzini }
548db1a4972SPaolo Bonzini 
54940daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type)
55040daca54SAlex Bligh {
5517bf8fbdeSAlex Bligh     return timerlist_run_timers(main_loop_tlg.tl[type]);
55240daca54SAlex Bligh }
55340daca54SAlex Bligh 
554d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg,
555d5541d86SAlex Bligh                          QEMUTimerListNotifyCB *cb, void *opaque)
556754d6a54SAlex Bligh {
557754d6a54SAlex Bligh     QEMUClockType type;
558754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
559d5541d86SAlex Bligh         tlg->tl[type] = timerlist_new(type, cb, opaque);
560754d6a54SAlex Bligh     }
561754d6a54SAlex Bligh }
562754d6a54SAlex Bligh 
563754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
564754d6a54SAlex Bligh {
565754d6a54SAlex Bligh     QEMUClockType type;
566754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
567754d6a54SAlex Bligh         timerlist_free(tlg->tl[type]);
568754d6a54SAlex Bligh     }
569754d6a54SAlex Bligh }
570754d6a54SAlex Bligh 
571754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
572754d6a54SAlex Bligh {
573754d6a54SAlex Bligh     QEMUClockType type;
574754d6a54SAlex Bligh     bool progress = false;
575754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
576754d6a54SAlex Bligh         progress |= timerlist_run_timers(tlg->tl[type]);
577754d6a54SAlex Bligh     }
578754d6a54SAlex Bligh     return progress;
579754d6a54SAlex Bligh }
580754d6a54SAlex Bligh 
581754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
582754d6a54SAlex Bligh {
583754d6a54SAlex Bligh     int64_t deadline = -1;
584754d6a54SAlex Bligh     QEMUClockType type;
5858bd7f71dSPavel Dovgalyuk     bool play = replay_mode == REPLAY_MODE_PLAY;
586754d6a54SAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
5878bd7f71dSPavel Dovgalyuk         if (qemu_clock_use_for_deadline(type)) {
5888bd7f71dSPavel Dovgalyuk             if (!play || type == QEMU_CLOCK_REALTIME) {
589754d6a54SAlex Bligh                 deadline = qemu_soonest_timeout(deadline,
5908bd7f71dSPavel Dovgalyuk                                                 timerlist_deadline_ns(tlg->tl[type]));
5918bd7f71dSPavel Dovgalyuk             } else {
5928bd7f71dSPavel Dovgalyuk                 /* Read clock from the replay file and
5938bd7f71dSPavel Dovgalyuk                    do not calculate the deadline, based on virtual clock. */
5948bd7f71dSPavel Dovgalyuk                 qemu_clock_get_ns(type);
5958bd7f71dSPavel Dovgalyuk             }
596754d6a54SAlex Bligh         }
597754d6a54SAlex Bligh     }
598754d6a54SAlex Bligh     return deadline;
599754d6a54SAlex Bligh }
600754d6a54SAlex Bligh 
60140daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type)
602db1a4972SPaolo Bonzini {
603691a0c9cSJan Kiszka     int64_t now, last;
60440daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
605691a0c9cSJan Kiszka 
60640daca54SAlex Bligh     switch (type) {
607db1a4972SPaolo Bonzini     case QEMU_CLOCK_REALTIME:
608db1a4972SPaolo Bonzini         return get_clock();
609db1a4972SPaolo Bonzini     default:
610db1a4972SPaolo Bonzini     case QEMU_CLOCK_VIRTUAL:
611db1a4972SPaolo Bonzini         if (use_icount) {
612db1a4972SPaolo Bonzini             return cpu_get_icount();
613db1a4972SPaolo Bonzini         } else {
614db1a4972SPaolo Bonzini             return cpu_get_clock();
615db1a4972SPaolo Bonzini         }
616db1a4972SPaolo Bonzini     case QEMU_CLOCK_HOST:
6178eda206eSPavel Dovgalyuk         now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
618691a0c9cSJan Kiszka         last = clock->last;
619691a0c9cSJan Kiszka         clock->last = now;
6208bd7f71dSPavel Dovgalyuk         if (now < last || now > (last + get_max_clock_jump())) {
621691a0c9cSJan Kiszka             notifier_list_notify(&clock->reset_notifiers, &now);
622db1a4972SPaolo Bonzini         }
623691a0c9cSJan Kiszka         return now;
6244e7fa73eSPavel Dovgalyuk     case QEMU_CLOCK_VIRTUAL_RT:
6258eda206eSPavel Dovgalyuk         return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
626691a0c9cSJan Kiszka     }
627691a0c9cSJan Kiszka }
628691a0c9cSJan Kiszka 
62940daca54SAlex Bligh void qemu_clock_register_reset_notifier(QEMUClockType type,
63040daca54SAlex Bligh                                         Notifier *notifier)
63140daca54SAlex Bligh {
63240daca54SAlex Bligh     QEMUClock *clock = qemu_clock_ptr(type);
633691a0c9cSJan Kiszka     notifier_list_add(&clock->reset_notifiers, notifier);
634691a0c9cSJan Kiszka }
635691a0c9cSJan Kiszka 
63640daca54SAlex Bligh void qemu_clock_unregister_reset_notifier(QEMUClockType type,
63740daca54SAlex Bligh                                           Notifier *notifier)
638691a0c9cSJan Kiszka {
63931552529SPaolo Bonzini     notifier_remove(notifier);
640db1a4972SPaolo Bonzini }
641db1a4972SPaolo Bonzini 
642db1a4972SPaolo Bonzini void init_clocks(void)
643db1a4972SPaolo Bonzini {
644ff83c66eSAlex Bligh     QEMUClockType type;
645ff83c66eSAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
6467bf8fbdeSAlex Bligh         qemu_clock_init(type);
647ff83c66eSAlex Bligh     }
648ff83c66eSAlex Bligh 
649cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
650cd758dd0SAlex Bligh     prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
651cd758dd0SAlex Bligh #endif
652744ca8e3SPaolo Bonzini }
653db1a4972SPaolo Bonzini 
654e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts)
655db1a4972SPaolo Bonzini {
656e93379b0SAlex Bligh     return timer_pending(ts) ? ts->expire_time : -1;
657db1a4972SPaolo Bonzini }
658db1a4972SPaolo Bonzini 
65940daca54SAlex Bligh bool qemu_clock_run_all_timers(void)
660db1a4972SPaolo Bonzini {
661f9a976b7SAlex Bligh     bool progress = false;
662ff83c66eSAlex Bligh     QEMUClockType type;
6636d327171SAlex Bligh 
664ff83c66eSAlex Bligh     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
66540daca54SAlex Bligh         progress |= qemu_clock_run_timers(type);
666ff83c66eSAlex Bligh     }
667158fd3ceSPeter Portante 
668f9a976b7SAlex Bligh     return progress;
669db1a4972SPaolo Bonzini }
670