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" 283284c3ddSStefan Hajnoczi #include "qemu/lockable.h" 29740b1759SClaudio Fontana #include "sysemu/cpu-timers.h" 308eda206eSPavel Dovgalyuk #include "sysemu/replay.h" 31d2528bdcSPaolo Bonzini #include "sysemu/cpus.h" 321ac0206bSPeter Maydell 3330ea8339SAnthony Liguori #ifdef CONFIG_POSIX 3430ea8339SAnthony Liguori #include <pthread.h> 3530ea8339SAnthony Liguori #endif 36bff9f8bfSStefan Weil 374e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 384e0c6529SAlex Bligh #include <poll.h> 394e0c6529SAlex Bligh #endif 404e0c6529SAlex Bligh 41cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 42cd758dd0SAlex Bligh #include <sys/prctl.h> 43cd758dd0SAlex Bligh #endif 44cd758dd0SAlex Bligh 45db1a4972SPaolo Bonzini /***********************************************************/ 46db1a4972SPaolo Bonzini /* timers */ 47db1a4972SPaolo Bonzini 48b4049b74SAlex Bligh typedef struct QEMUClock { 493c053411SLiu Ping Fan /* We rely on BQL to protect the timerlists */ 50ff83c66eSAlex Bligh QLIST_HEAD(, QEMUTimerList) timerlists; 51691a0c9cSJan Kiszka 52ff83c66eSAlex Bligh QEMUClockType type; 539a14b298SStefan Weil bool enabled; 54b4049b74SAlex Bligh } QEMUClock; 55db1a4972SPaolo Bonzini 56754d6a54SAlex Bligh QEMUTimerListGroup main_loop_tlg; 57fbdb664cSStefan Weil static QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; 58ff83c66eSAlex Bligh 59ff83c66eSAlex Bligh /* A QEMUTimerList is a list of timers attached to a clock. More 60ff83c66eSAlex Bligh * than one QEMUTimerList can be attached to each clock, for instance 61ff83c66eSAlex Bligh * used by different AioContexts / threads. Each clock also has 62ff83c66eSAlex Bligh * a list of the QEMUTimerLists associated with it, in order that 63ff83c66eSAlex Bligh * reenabling the clock can call all the notifiers. 64ff83c66eSAlex Bligh */ 65ff83c66eSAlex Bligh 66ff83c66eSAlex Bligh struct QEMUTimerList { 679a14b298SStefan Weil QEMUClock *clock; 68978f2205SStefan Hajnoczi QemuMutex active_timers_lock; 69ff83c66eSAlex Bligh QEMUTimer *active_timers; 70ff83c66eSAlex Bligh QLIST_ENTRY(QEMUTimerList) list; 71d5541d86SAlex Bligh QEMUTimerListNotifyCB *notify_cb; 72d5541d86SAlex Bligh void *notify_opaque; 733c053411SLiu Ping Fan 743c053411SLiu Ping Fan /* lightweight method to mark the end of timerlist's running */ 753c053411SLiu Ping Fan QemuEvent timers_done_ev; 76db1a4972SPaolo Bonzini }; 77db1a4972SPaolo Bonzini 787bf8fbdeSAlex Bligh /** 797bf8fbdeSAlex Bligh * qemu_clock_ptr: 807bf8fbdeSAlex Bligh * @type: type of clock 817bf8fbdeSAlex Bligh * 827bf8fbdeSAlex Bligh * Translate a clock type into a pointer to QEMUClock object. 837bf8fbdeSAlex Bligh * 847bf8fbdeSAlex Bligh * Returns: a pointer to the QEMUClock object 857bf8fbdeSAlex Bligh */ 86b4049b74SAlex Bligh static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) 877bf8fbdeSAlex Bligh { 887bf8fbdeSAlex Bligh return &qemu_clocks[type]; 897bf8fbdeSAlex Bligh } 907bf8fbdeSAlex Bligh 91e93379b0SAlex Bligh static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) 9245c7b37fSStefan Weil { 9345c7b37fSStefan Weil return timer_head && (timer_head->expire_time <= current_time); 9445c7b37fSStefan Weil } 9545c7b37fSStefan Weil 967bf8fbdeSAlex Bligh QEMUTimerList *timerlist_new(QEMUClockType type, 97d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, 98d5541d86SAlex Bligh void *opaque) 99ff83c66eSAlex Bligh { 100ff83c66eSAlex Bligh QEMUTimerList *timer_list; 1017bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 102ff83c66eSAlex Bligh 103*b21e2380SMarkus Armbruster timer_list = g_new0(QEMUTimerList, 1); 104e4efd8a4SPaolo Bonzini qemu_event_init(&timer_list->timers_done_ev, true); 105ff83c66eSAlex Bligh timer_list->clock = clock; 106d5541d86SAlex Bligh timer_list->notify_cb = cb; 107d5541d86SAlex Bligh timer_list->notify_opaque = opaque; 108978f2205SStefan Hajnoczi qemu_mutex_init(&timer_list->active_timers_lock); 109ff83c66eSAlex Bligh QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); 110ff83c66eSAlex Bligh return timer_list; 111ff83c66eSAlex Bligh } 112ff83c66eSAlex Bligh 113ff83c66eSAlex Bligh void timerlist_free(QEMUTimerList *timer_list) 114ff83c66eSAlex Bligh { 115ff83c66eSAlex Bligh assert(!timerlist_has_timers(timer_list)); 116ff83c66eSAlex Bligh if (timer_list->clock) { 117ff83c66eSAlex Bligh QLIST_REMOVE(timer_list, list); 118ff83c66eSAlex Bligh } 119978f2205SStefan Hajnoczi qemu_mutex_destroy(&timer_list->active_timers_lock); 120ff83c66eSAlex Bligh g_free(timer_list); 121ff83c66eSAlex Bligh } 122ff83c66eSAlex Bligh 1233f53bc61SPaolo Bonzini static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb) 124db1a4972SPaolo Bonzini { 1257bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 126691a0c9cSJan Kiszka 12702ce232cSKirill Batuzov /* Assert that the clock of type TYPE has not been initialized yet. */ 12802ce232cSKirill Batuzov assert(main_loop_tlg.tl[type] == NULL); 12902ce232cSKirill Batuzov 130db1a4972SPaolo Bonzini clock->type = type; 1313fdd0ee3SGonglei clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : true); 132ff83c66eSAlex Bligh QLIST_INIT(&clock->timerlists); 1333f53bc61SPaolo Bonzini main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL); 134db1a4972SPaolo Bonzini } 135db1a4972SPaolo Bonzini 13640daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type) 137ff83c66eSAlex Bligh { 138740b1759SClaudio Fontana return !(icount_enabled() && (type == QEMU_CLOCK_VIRTUAL)); 139ff83c66eSAlex Bligh } 140ff83c66eSAlex Bligh 14140daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type) 142b1bbfe72SAlex Bligh { 143b1bbfe72SAlex Bligh QEMUTimerList *timer_list; 14440daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 145b1bbfe72SAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 146b1bbfe72SAlex Bligh timerlist_notify(timer_list); 147b1bbfe72SAlex Bligh } 148b1bbfe72SAlex Bligh } 149b1bbfe72SAlex Bligh 1503c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop 1513c053411SLiu Ping Fan * executing qemu_run_timers. Thus, this functions should not 1523c053411SLiu Ping Fan * be used from the callback of a timer that is based on @clock. 1533c053411SLiu Ping Fan * Doing so would cause a deadlock. 1543c053411SLiu Ping Fan * 1553c053411SLiu Ping Fan * Caller should hold BQL. 1563c053411SLiu Ping Fan */ 15740daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled) 158db1a4972SPaolo Bonzini { 15940daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 1603c053411SLiu Ping Fan QEMUTimerList *tl; 161fbdc14ebSPaolo Bonzini bool old = clock->enabled; 162db1a4972SPaolo Bonzini clock->enabled = enabled; 163fbdc14ebSPaolo Bonzini if (enabled && !old) { 16440daca54SAlex Bligh qemu_clock_notify(type); 1653c053411SLiu Ping Fan } else if (!enabled && old) { 1663c053411SLiu Ping Fan QLIST_FOREACH(tl, &clock->timerlists, list) { 1673c053411SLiu Ping Fan qemu_event_wait(&tl->timers_done_ev); 1683c053411SLiu Ping Fan } 169fbdc14ebSPaolo Bonzini } 170db1a4972SPaolo Bonzini } 171db1a4972SPaolo Bonzini 172ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list) 173dc2dfcf0SPaolo Bonzini { 174d73415a3SStefan Hajnoczi return !!qatomic_read(&timer_list->active_timers); 175dc2dfcf0SPaolo Bonzini } 176dc2dfcf0SPaolo Bonzini 17740daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type) 178dc2dfcf0SPaolo Bonzini { 17940daca54SAlex Bligh return timerlist_has_timers( 1807bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 181dc2dfcf0SPaolo Bonzini } 182dc2dfcf0SPaolo Bonzini 183ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list) 184ff83c66eSAlex Bligh { 185978f2205SStefan Hajnoczi int64_t expire_time; 186978f2205SStefan Hajnoczi 187d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 1888caa05d8SPaolo Bonzini return false; 1898caa05d8SPaolo Bonzini } 1908caa05d8SPaolo Bonzini 1913284c3ddSStefan Hajnoczi WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 192978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 193978f2205SStefan Hajnoczi return false; 194978f2205SStefan Hajnoczi } 195978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 1963284c3ddSStefan Hajnoczi } 197978f2205SStefan Hajnoczi 19833bef0b9SPaolo Bonzini return expire_time <= qemu_clock_get_ns(timer_list->clock->type); 199ff83c66eSAlex Bligh } 200ff83c66eSAlex Bligh 20140daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type) 202ff83c66eSAlex Bligh { 20340daca54SAlex Bligh return timerlist_expired( 2047bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 205ff83c66eSAlex Bligh } 206ff83c66eSAlex Bligh 20702a03a9fSAlex Bligh /* 20802a03a9fSAlex Bligh * As above, but return -1 for no deadline, and do not cap to 2^32 20902a03a9fSAlex Bligh * as we know the result is always positive. 21002a03a9fSAlex Bligh */ 21102a03a9fSAlex Bligh 212ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) 21302a03a9fSAlex Bligh { 21402a03a9fSAlex Bligh int64_t delta; 215978f2205SStefan Hajnoczi int64_t expire_time; 21602a03a9fSAlex Bligh 217d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 2188caa05d8SPaolo Bonzini return -1; 2198caa05d8SPaolo Bonzini } 2208caa05d8SPaolo Bonzini 221978f2205SStefan Hajnoczi if (!timer_list->clock->enabled) { 22202a03a9fSAlex Bligh return -1; 22302a03a9fSAlex Bligh } 22402a03a9fSAlex Bligh 225978f2205SStefan Hajnoczi /* The active timers list may be modified before the caller uses our return 226978f2205SStefan Hajnoczi * value but ->notify_cb() is called when the deadline changes. Therefore 227978f2205SStefan Hajnoczi * the caller should notice the change and there is no race condition. 228978f2205SStefan Hajnoczi */ 2293284c3ddSStefan Hajnoczi WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 230978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 231978f2205SStefan Hajnoczi return -1; 232978f2205SStefan Hajnoczi } 233978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 2343284c3ddSStefan Hajnoczi } 235978f2205SStefan Hajnoczi 236978f2205SStefan Hajnoczi delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 23702a03a9fSAlex Bligh 23802a03a9fSAlex Bligh if (delta <= 0) { 23902a03a9fSAlex Bligh return 0; 24002a03a9fSAlex Bligh } 24102a03a9fSAlex Bligh 24202a03a9fSAlex Bligh return delta; 24302a03a9fSAlex Bligh } 24402a03a9fSAlex Bligh 245ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached 246ac70aafcSAlex Bligh * to the clock. This is used for the icount timeout so we 247ac70aafcSAlex Bligh * ignore whether or not the clock should be used in deadline 248ac70aafcSAlex Bligh * calculations. 249ac70aafcSAlex Bligh */ 250dcb15780SPavel Dovgalyuk int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) 251ac70aafcSAlex Bligh { 252ac70aafcSAlex Bligh int64_t deadline = -1; 253dcb15780SPavel Dovgalyuk int64_t delta; 254dcb15780SPavel Dovgalyuk int64_t expire_time; 255dcb15780SPavel Dovgalyuk QEMUTimer *ts; 256ac70aafcSAlex Bligh QEMUTimerList *timer_list; 25740daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 258dcb15780SPavel Dovgalyuk 259dcb15780SPavel Dovgalyuk if (!clock->enabled) { 260dcb15780SPavel Dovgalyuk return -1; 261dcb15780SPavel Dovgalyuk } 262dcb15780SPavel Dovgalyuk 263ac70aafcSAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 264dcb15780SPavel Dovgalyuk qemu_mutex_lock(&timer_list->active_timers_lock); 265dcb15780SPavel Dovgalyuk ts = timer_list->active_timers; 266dcb15780SPavel Dovgalyuk /* Skip all external timers */ 267dcb15780SPavel Dovgalyuk while (ts && (ts->attributes & ~attr_mask)) { 268dcb15780SPavel Dovgalyuk ts = ts->next; 269dcb15780SPavel Dovgalyuk } 270dcb15780SPavel Dovgalyuk if (!ts) { 271dcb15780SPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 272dcb15780SPavel Dovgalyuk continue; 273dcb15780SPavel Dovgalyuk } 274dcb15780SPavel Dovgalyuk expire_time = ts->expire_time; 275dcb15780SPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 276dcb15780SPavel Dovgalyuk 277dcb15780SPavel Dovgalyuk delta = expire_time - qemu_clock_get_ns(type); 278dcb15780SPavel Dovgalyuk if (delta <= 0) { 279dcb15780SPavel Dovgalyuk delta = 0; 280dcb15780SPavel Dovgalyuk } 281dcb15780SPavel Dovgalyuk deadline = qemu_soonest_timeout(deadline, delta); 282ac70aafcSAlex Bligh } 283ac70aafcSAlex Bligh return deadline; 284ac70aafcSAlex Bligh } 285ac70aafcSAlex Bligh 28640daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) 287ff83c66eSAlex Bligh { 28840daca54SAlex Bligh return timer_list->clock->type; 289ff83c66eSAlex Bligh } 290ff83c66eSAlex Bligh 29140daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) 292ff83c66eSAlex Bligh { 2937bf8fbdeSAlex Bligh return main_loop_tlg.tl[type]; 294ff83c66eSAlex Bligh } 295ff83c66eSAlex Bligh 296d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list) 297d5541d86SAlex Bligh { 298d5541d86SAlex Bligh if (timer_list->notify_cb) { 2993f53bc61SPaolo Bonzini timer_list->notify_cb(timer_list->notify_opaque, timer_list->clock->type); 300d5541d86SAlex Bligh } else { 301d5541d86SAlex Bligh qemu_notify_event(); 302d5541d86SAlex Bligh } 303d5541d86SAlex Bligh } 304d5541d86SAlex Bligh 30502a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms 30602a03a9fSAlex Bligh * This is used where a system does not support ppoll 30702a03a9fSAlex Bligh */ 30802a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns) 30902a03a9fSAlex Bligh { 31002a03a9fSAlex Bligh int64_t ms; 31102a03a9fSAlex Bligh if (ns < 0) { 31202a03a9fSAlex Bligh return -1; 31302a03a9fSAlex Bligh } 31402a03a9fSAlex Bligh 31502a03a9fSAlex Bligh if (!ns) { 31602a03a9fSAlex Bligh return 0; 31702a03a9fSAlex Bligh } 31802a03a9fSAlex Bligh 31902a03a9fSAlex Bligh /* Always round up, because it's better to wait too long than to wait too 32002a03a9fSAlex Bligh * little and effectively busy-wait 32102a03a9fSAlex Bligh */ 3225029b969SLaurent Vivier ms = DIV_ROUND_UP(ns, SCALE_MS); 32302a03a9fSAlex Bligh 32402a03a9fSAlex Bligh /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ 3255bd34354SFrediano Ziglio return MIN(ms, INT32_MAX); 32602a03a9fSAlex Bligh } 32702a03a9fSAlex Bligh 32802a03a9fSAlex Bligh 3294e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is 3304e0c6529SAlex Bligh * otherwise identical to g_poll 3314e0c6529SAlex Bligh */ 3324e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) 3334e0c6529SAlex Bligh { 3344e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 3354e0c6529SAlex Bligh if (timeout < 0) { 3364e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, NULL, NULL); 3374e0c6529SAlex Bligh } else { 3384e0c6529SAlex Bligh struct timespec ts; 339490309fcSPeter Maydell int64_t tvsec = timeout / 1000000000LL; 340490309fcSPeter Maydell /* Avoid possibly overflowing and specifying a negative number of 341490309fcSPeter Maydell * seconds, which would turn a very long timeout into a busy-wait. 342490309fcSPeter Maydell */ 343490309fcSPeter Maydell if (tvsec > (int64_t)INT32_MAX) { 344490309fcSPeter Maydell tvsec = INT32_MAX; 345490309fcSPeter Maydell } 346490309fcSPeter Maydell ts.tv_sec = tvsec; 3474e0c6529SAlex Bligh ts.tv_nsec = timeout % 1000000000LL; 3484e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, &ts, NULL); 3494e0c6529SAlex Bligh } 3504e0c6529SAlex Bligh #else 3514e0c6529SAlex Bligh return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); 3524e0c6529SAlex Bligh #endif 3534e0c6529SAlex Bligh } 3544e0c6529SAlex Bligh 3554e0c6529SAlex Bligh 35689a603a0SArtem Pisarenko void timer_init_full(QEMUTimer *ts, 35789a603a0SArtem Pisarenko QEMUTimerListGroup *timer_list_group, QEMUClockType type, 35889a603a0SArtem Pisarenko int scale, int attributes, 3594a998740SPaolo Bonzini QEMUTimerCB *cb, void *opaque) 360db1a4972SPaolo Bonzini { 36189a603a0SArtem Pisarenko if (!timer_list_group) { 36289a603a0SArtem Pisarenko timer_list_group = &main_loop_tlg; 36389a603a0SArtem Pisarenko } 36489a603a0SArtem Pisarenko ts->timer_list = timer_list_group->tl[type]; 365db1a4972SPaolo Bonzini ts->cb = cb; 366db1a4972SPaolo Bonzini ts->opaque = opaque; 3674a998740SPaolo Bonzini ts->scale = scale; 36889a603a0SArtem Pisarenko ts->attributes = attributes; 3693db1ee7cSPaolo Bonzini ts->expire_time = -1; 370ff83c66eSAlex Bligh } 371ff83c66eSAlex Bligh 372cd1bd53aSPaolo Bonzini void timer_deinit(QEMUTimer *ts) 373cd1bd53aSPaolo Bonzini { 374cd1bd53aSPaolo Bonzini assert(ts->expire_time == -1); 375cd1bd53aSPaolo Bonzini ts->timer_list = NULL; 376cd1bd53aSPaolo Bonzini } 377cd1bd53aSPaolo Bonzini 378978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) 379db1a4972SPaolo Bonzini { 380db1a4972SPaolo Bonzini QEMUTimer **pt, *t; 381db1a4972SPaolo Bonzini 3823db1ee7cSPaolo Bonzini ts->expire_time = -1; 383978f2205SStefan Hajnoczi pt = &timer_list->active_timers; 384db1a4972SPaolo Bonzini for(;;) { 385db1a4972SPaolo Bonzini t = *pt; 386db1a4972SPaolo Bonzini if (!t) 387db1a4972SPaolo Bonzini break; 388db1a4972SPaolo Bonzini if (t == ts) { 389d73415a3SStefan Hajnoczi qatomic_set(pt, t->next); 390db1a4972SPaolo Bonzini break; 391db1a4972SPaolo Bonzini } 392db1a4972SPaolo Bonzini pt = &t->next; 393db1a4972SPaolo Bonzini } 394db1a4972SPaolo Bonzini } 395db1a4972SPaolo Bonzini 3960f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list, 3970f809e5fSPaolo Bonzini QEMUTimer *ts, int64_t expire_time) 3980f809e5fSPaolo Bonzini { 3990f809e5fSPaolo Bonzini QEMUTimer **pt, *t; 4000f809e5fSPaolo Bonzini 4010f809e5fSPaolo Bonzini /* add the timer in the sorted list */ 4020f809e5fSPaolo Bonzini pt = &timer_list->active_timers; 4030f809e5fSPaolo Bonzini for (;;) { 4040f809e5fSPaolo Bonzini t = *pt; 4050f809e5fSPaolo Bonzini if (!timer_expired_ns(t, expire_time)) { 4060f809e5fSPaolo Bonzini break; 4070f809e5fSPaolo Bonzini } 4080f809e5fSPaolo Bonzini pt = &t->next; 4090f809e5fSPaolo Bonzini } 4100f809e5fSPaolo Bonzini ts->expire_time = MAX(expire_time, 0); 4110f809e5fSPaolo Bonzini ts->next = *pt; 412d73415a3SStefan Hajnoczi qatomic_set(pt, ts); 4130f809e5fSPaolo Bonzini 4140f809e5fSPaolo Bonzini return pt == &timer_list->active_timers; 4150f809e5fSPaolo Bonzini } 4160f809e5fSPaolo Bonzini 4170f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list) 4180f809e5fSPaolo Bonzini { 4190f809e5fSPaolo Bonzini /* Interrupt execution to force deadline recalculation. */ 420740b1759SClaudio Fontana if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { 4218191d368SClaudio Fontana icount_start_warp_timer(); 422e76d1798SPavel Dovgalyuk } 4230f809e5fSPaolo Bonzini timerlist_notify(timer_list); 4240f809e5fSPaolo Bonzini } 4250f809e5fSPaolo Bonzini 426978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */ 427978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts) 428978f2205SStefan Hajnoczi { 429978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 430978f2205SStefan Hajnoczi 431cd1bd53aSPaolo Bonzini if (timer_list) { 432978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 433978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 434978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 435978f2205SStefan Hajnoczi } 436cd1bd53aSPaolo Bonzini } 437978f2205SStefan Hajnoczi 438db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 439db1a4972SPaolo Bonzini >= expire_time. The corresponding callback will be called. */ 44040daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) 441db1a4972SPaolo Bonzini { 442978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 4430f809e5fSPaolo Bonzini bool rearm; 444db1a4972SPaolo Bonzini 445978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 446978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 4470f809e5fSPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 448978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 449db1a4972SPaolo Bonzini 4500f809e5fSPaolo Bonzini if (rearm) { 4510f809e5fSPaolo Bonzini timerlist_rearm(timer_list); 452db1a4972SPaolo Bonzini } 453db1a4972SPaolo Bonzini } 454db1a4972SPaolo Bonzini 455add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 456add40e97SPaolo Bonzini >= expire_time or the current deadline, whichever comes earlier. 457add40e97SPaolo Bonzini The corresponding callback will be called. */ 458add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) 459add40e97SPaolo Bonzini { 460add40e97SPaolo Bonzini QEMUTimerList *timer_list = ts->timer_list; 461add40e97SPaolo Bonzini bool rearm; 462add40e97SPaolo Bonzini 4636e8a355dSDaniel Brodsky WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 464add40e97SPaolo Bonzini if (ts->expire_time == -1 || ts->expire_time > expire_time) { 465add40e97SPaolo Bonzini if (ts->expire_time != -1) { 466add40e97SPaolo Bonzini timer_del_locked(timer_list, ts); 467add40e97SPaolo Bonzini } 468add40e97SPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 469add40e97SPaolo Bonzini } else { 470add40e97SPaolo Bonzini rearm = false; 471add40e97SPaolo Bonzini } 4726e8a355dSDaniel Brodsky } 473add40e97SPaolo Bonzini if (rearm) { 474add40e97SPaolo Bonzini timerlist_rearm(timer_list); 475add40e97SPaolo Bonzini } 476add40e97SPaolo Bonzini } 477add40e97SPaolo Bonzini 47840daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time) 4794a998740SPaolo Bonzini { 48040daca54SAlex Bligh timer_mod_ns(ts, expire_time * ts->scale); 4814a998740SPaolo Bonzini } 4824a998740SPaolo Bonzini 483add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) 484add40e97SPaolo Bonzini { 485add40e97SPaolo Bonzini timer_mod_anticipate_ns(ts, expire_time * ts->scale); 486add40e97SPaolo Bonzini } 487add40e97SPaolo Bonzini 488e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts) 489db1a4972SPaolo Bonzini { 4903db1ee7cSPaolo Bonzini return ts->expire_time >= 0; 491db1a4972SPaolo Bonzini } 492db1a4972SPaolo Bonzini 493e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time) 494db1a4972SPaolo Bonzini { 495e93379b0SAlex Bligh return timer_expired_ns(timer_head, current_time * timer_head->scale); 496db1a4972SPaolo Bonzini } 497db1a4972SPaolo Bonzini 498ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list) 499db1a4972SPaolo Bonzini { 500144b97c2SPaolo Bonzini QEMUTimer *ts; 501db1a4972SPaolo Bonzini int64_t current_time; 502f9a976b7SAlex Bligh bool progress = false; 503978f2205SStefan Hajnoczi QEMUTimerCB *cb; 504978f2205SStefan Hajnoczi void *opaque; 505db1a4972SPaolo Bonzini 506d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 5078caa05d8SPaolo Bonzini return false; 5088caa05d8SPaolo Bonzini } 5098caa05d8SPaolo Bonzini 5103c053411SLiu Ping Fan qemu_event_reset(&timer_list->timers_done_ev); 5118caa05d8SPaolo Bonzini if (!timer_list->clock->enabled) { 5123c053411SLiu Ping Fan goto out; 513ff83c66eSAlex Bligh } 514db1a4972SPaolo Bonzini 5158bd7f71dSPavel Dovgalyuk switch (timer_list->clock->type) { 5168bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_REALTIME: 5178bd7f71dSPavel Dovgalyuk break; 5188bd7f71dSPavel Dovgalyuk default: 5198bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL: 5208bd7f71dSPavel Dovgalyuk break; 5218bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_HOST: 5228bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) { 5238bd7f71dSPavel Dovgalyuk goto out; 5248bd7f71dSPavel Dovgalyuk } 5258bd7f71dSPavel Dovgalyuk break; 5268bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 5278bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) { 5288bd7f71dSPavel Dovgalyuk goto out; 5298bd7f71dSPavel Dovgalyuk } 5308bd7f71dSPavel Dovgalyuk break; 5318bd7f71dSPavel Dovgalyuk } 5328bd7f71dSPavel Dovgalyuk 533e81f8679SArtem Pisarenko /* 5343cf10b29SPhilippe Mathieu-Daudé * Extract expired timers from active timers list and process them. 535e81f8679SArtem Pisarenko * 536e81f8679SArtem Pisarenko * In rr mode we need "filtered" checkpointing for virtual clock. The 537e81f8679SArtem Pisarenko * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer, 538e81f8679SArtem Pisarenko * and that must only be done once since the clock value stays the same. Because 539e81f8679SArtem Pisarenko * non-EXTERNAL timers may appear in the timers list while it being processed, 540e81f8679SArtem Pisarenko * the checkpoint can be issued at a time until no timers are left and we are 541e81f8679SArtem Pisarenko * done". 542e81f8679SArtem Pisarenko */ 54340daca54SAlex Bligh current_time = qemu_clock_get_ns(timer_list->clock->type); 544978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 545e81f8679SArtem Pisarenko while ((ts = timer_list->active_timers)) { 546e93379b0SAlex Bligh if (!timer_expired_ns(ts, current_time)) { 547e81f8679SArtem Pisarenko /* No expired timers left. The checkpoint can be skipped 548e81f8679SArtem Pisarenko * if no timers fired or they were all external. 549e81f8679SArtem Pisarenko */ 550db1a4972SPaolo Bonzini break; 55145c7b37fSStefan Weil } 552677a3babSPavel Dovgalyuk /* Checkpoint for virtual clock is redundant in cases where 553677a3babSPavel Dovgalyuk * it's being triggered with only non-EXTERNAL timers, because 554677a3babSPavel Dovgalyuk * these timers don't change guest state directly. 555e81f8679SArtem Pisarenko */ 556677a3babSPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE 557677a3babSPavel Dovgalyuk && timer_list->clock->type == QEMU_CLOCK_VIRTUAL 558677a3babSPavel Dovgalyuk && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL) 559677a3babSPavel Dovgalyuk && !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { 560677a3babSPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 561677a3babSPavel Dovgalyuk goto out; 562e81f8679SArtem Pisarenko } 563978f2205SStefan Hajnoczi 564db1a4972SPaolo Bonzini /* remove timer from the list before calling the callback */ 565ff83c66eSAlex Bligh timer_list->active_timers = ts->next; 566db1a4972SPaolo Bonzini ts->next = NULL; 5673db1ee7cSPaolo Bonzini ts->expire_time = -1; 568978f2205SStefan Hajnoczi cb = ts->cb; 569978f2205SStefan Hajnoczi opaque = ts->opaque; 570db1a4972SPaolo Bonzini 571db1a4972SPaolo Bonzini /* run the callback (the timer list can be modified) */ 572e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 573978f2205SStefan Hajnoczi cb(opaque); 574e81f8679SArtem Pisarenko qemu_mutex_lock(&timer_list->active_timers_lock); 575e81f8679SArtem Pisarenko 576f9a976b7SAlex Bligh progress = true; 577db1a4972SPaolo Bonzini } 578e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 5793c053411SLiu Ping Fan 5803c053411SLiu Ping Fan out: 5813c053411SLiu Ping Fan qemu_event_set(&timer_list->timers_done_ev); 582f9a976b7SAlex Bligh return progress; 583db1a4972SPaolo Bonzini } 584db1a4972SPaolo Bonzini 58540daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type) 58640daca54SAlex Bligh { 5877bf8fbdeSAlex Bligh return timerlist_run_timers(main_loop_tlg.tl[type]); 58840daca54SAlex Bligh } 58940daca54SAlex Bligh 590d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg, 591d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, void *opaque) 592754d6a54SAlex Bligh { 593754d6a54SAlex Bligh QEMUClockType type; 594754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 595d5541d86SAlex Bligh tlg->tl[type] = timerlist_new(type, cb, opaque); 596754d6a54SAlex Bligh } 597754d6a54SAlex Bligh } 598754d6a54SAlex Bligh 599754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg) 600754d6a54SAlex Bligh { 601754d6a54SAlex Bligh QEMUClockType type; 602754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 603754d6a54SAlex Bligh timerlist_free(tlg->tl[type]); 604754d6a54SAlex Bligh } 605754d6a54SAlex Bligh } 606754d6a54SAlex Bligh 607754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 608754d6a54SAlex Bligh { 609754d6a54SAlex Bligh QEMUClockType type; 610754d6a54SAlex Bligh bool progress = false; 611754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 612754d6a54SAlex Bligh progress |= timerlist_run_timers(tlg->tl[type]); 613754d6a54SAlex Bligh } 614754d6a54SAlex Bligh return progress; 615754d6a54SAlex Bligh } 616754d6a54SAlex Bligh 617754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 618754d6a54SAlex Bligh { 619754d6a54SAlex Bligh int64_t deadline = -1; 620754d6a54SAlex Bligh QEMUClockType type; 621754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6228bd7f71dSPavel Dovgalyuk if (qemu_clock_use_for_deadline(type)) { 623754d6a54SAlex Bligh deadline = qemu_soonest_timeout(deadline, 6248bd7f71dSPavel Dovgalyuk timerlist_deadline_ns(tlg->tl[type])); 625754d6a54SAlex Bligh } 626754d6a54SAlex Bligh } 627754d6a54SAlex Bligh return deadline; 628754d6a54SAlex Bligh } 629754d6a54SAlex Bligh 63040daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type) 631db1a4972SPaolo Bonzini { 63240daca54SAlex Bligh switch (type) { 633db1a4972SPaolo Bonzini case QEMU_CLOCK_REALTIME: 634db1a4972SPaolo Bonzini return get_clock(); 635db1a4972SPaolo Bonzini default: 636db1a4972SPaolo Bonzini case QEMU_CLOCK_VIRTUAL: 637430065daSClaudio Fontana return cpus_get_virtual_clock(); 638db1a4972SPaolo Bonzini case QEMU_CLOCK_HOST: 6393c2d4c8aSDr. David Alan Gilbert return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); 6404e7fa73eSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 6418eda206eSPavel Dovgalyuk return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock()); 642691a0c9cSJan Kiszka } 643691a0c9cSJan Kiszka } 644691a0c9cSJan Kiszka 6453f53bc61SPaolo Bonzini void init_clocks(QEMUTimerListNotifyCB *notify_cb) 646db1a4972SPaolo Bonzini { 647ff83c66eSAlex Bligh QEMUClockType type; 648ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6493f53bc61SPaolo Bonzini qemu_clock_init(type, notify_cb); 650ff83c66eSAlex Bligh } 651ff83c66eSAlex Bligh 652cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 653cd758dd0SAlex Bligh prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 654cd758dd0SAlex Bligh #endif 655744ca8e3SPaolo Bonzini } 656db1a4972SPaolo Bonzini 657e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts) 658db1a4972SPaolo Bonzini { 659e93379b0SAlex Bligh return timer_pending(ts) ? ts->expire_time : -1; 660db1a4972SPaolo Bonzini } 661db1a4972SPaolo Bonzini 66240daca54SAlex Bligh bool qemu_clock_run_all_timers(void) 663db1a4972SPaolo Bonzini { 664f9a976b7SAlex Bligh bool progress = false; 665ff83c66eSAlex Bligh QEMUClockType type; 6666d327171SAlex Bligh 667ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6686b8f0187SPaolo Bonzini if (qemu_clock_use_for_deadline(type)) { 66940daca54SAlex Bligh progress |= qemu_clock_run_timers(type); 670ff83c66eSAlex Bligh } 6716b8f0187SPaolo Bonzini } 672158fd3ceSPeter Portante 673f9a976b7SAlex Bligh return progress; 674db1a4972SPaolo Bonzini } 675