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