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" 29d2528bdcSPaolo Bonzini #include "sysemu/cpus.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 50ff83c66eSAlex Bligh QEMUClockType type; 519a14b298SStefan Weil bool enabled; 52b4049b74SAlex Bligh } QEMUClock; 53db1a4972SPaolo Bonzini 54754d6a54SAlex Bligh QEMUTimerListGroup main_loop_tlg; 55fbdb664cSStefan Weil static QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; 56ff83c66eSAlex Bligh 57ff83c66eSAlex Bligh /* A QEMUTimerList is a list of timers attached to a clock. More 58ff83c66eSAlex Bligh * than one QEMUTimerList can be attached to each clock, for instance 59ff83c66eSAlex Bligh * used by different AioContexts / threads. Each clock also has 60ff83c66eSAlex Bligh * a list of the QEMUTimerLists associated with it, in order that 61ff83c66eSAlex Bligh * reenabling the clock can call all the notifiers. 62ff83c66eSAlex Bligh */ 63ff83c66eSAlex Bligh 64ff83c66eSAlex Bligh struct QEMUTimerList { 659a14b298SStefan Weil QEMUClock *clock; 66978f2205SStefan Hajnoczi QemuMutex active_timers_lock; 67ff83c66eSAlex Bligh QEMUTimer *active_timers; 68ff83c66eSAlex Bligh QLIST_ENTRY(QEMUTimerList) list; 69d5541d86SAlex Bligh QEMUTimerListNotifyCB *notify_cb; 70d5541d86SAlex Bligh void *notify_opaque; 713c053411SLiu Ping Fan 723c053411SLiu Ping Fan /* lightweight method to mark the end of timerlist's running */ 733c053411SLiu Ping Fan QemuEvent timers_done_ev; 74db1a4972SPaolo Bonzini }; 75db1a4972SPaolo Bonzini 767bf8fbdeSAlex Bligh /** 777bf8fbdeSAlex Bligh * qemu_clock_ptr: 787bf8fbdeSAlex Bligh * @type: type of clock 797bf8fbdeSAlex Bligh * 807bf8fbdeSAlex Bligh * Translate a clock type into a pointer to QEMUClock object. 817bf8fbdeSAlex Bligh * 827bf8fbdeSAlex Bligh * Returns: a pointer to the QEMUClock object 837bf8fbdeSAlex Bligh */ 84b4049b74SAlex Bligh static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) 857bf8fbdeSAlex Bligh { 867bf8fbdeSAlex Bligh return &qemu_clocks[type]; 877bf8fbdeSAlex Bligh } 887bf8fbdeSAlex Bligh 89e93379b0SAlex Bligh static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) 9045c7b37fSStefan Weil { 9145c7b37fSStefan Weil return timer_head && (timer_head->expire_time <= current_time); 9245c7b37fSStefan Weil } 9345c7b37fSStefan Weil 947bf8fbdeSAlex Bligh QEMUTimerList *timerlist_new(QEMUClockType type, 95d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, 96d5541d86SAlex Bligh void *opaque) 97ff83c66eSAlex Bligh { 98ff83c66eSAlex Bligh QEMUTimerList *timer_list; 997bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 100ff83c66eSAlex Bligh 101ff83c66eSAlex Bligh timer_list = g_malloc0(sizeof(QEMUTimerList)); 102e4efd8a4SPaolo Bonzini qemu_event_init(&timer_list->timers_done_ev, true); 103ff83c66eSAlex Bligh timer_list->clock = clock; 104d5541d86SAlex Bligh timer_list->notify_cb = cb; 105d5541d86SAlex Bligh timer_list->notify_opaque = opaque; 106978f2205SStefan Hajnoczi qemu_mutex_init(&timer_list->active_timers_lock); 107ff83c66eSAlex Bligh QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); 108ff83c66eSAlex Bligh return timer_list; 109ff83c66eSAlex Bligh } 110ff83c66eSAlex Bligh 111ff83c66eSAlex Bligh void timerlist_free(QEMUTimerList *timer_list) 112ff83c66eSAlex Bligh { 113ff83c66eSAlex Bligh assert(!timerlist_has_timers(timer_list)); 114ff83c66eSAlex Bligh if (timer_list->clock) { 115ff83c66eSAlex Bligh QLIST_REMOVE(timer_list, list); 116ff83c66eSAlex Bligh } 117978f2205SStefan Hajnoczi qemu_mutex_destroy(&timer_list->active_timers_lock); 118ff83c66eSAlex Bligh g_free(timer_list); 119ff83c66eSAlex Bligh } 120ff83c66eSAlex Bligh 1213f53bc61SPaolo Bonzini static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb) 122db1a4972SPaolo Bonzini { 1237bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 124691a0c9cSJan Kiszka 12502ce232cSKirill Batuzov /* Assert that the clock of type TYPE has not been initialized yet. */ 12602ce232cSKirill Batuzov assert(main_loop_tlg.tl[type] == NULL); 12702ce232cSKirill Batuzov 128db1a4972SPaolo Bonzini clock->type = type; 1293fdd0ee3SGonglei clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : true); 130ff83c66eSAlex Bligh QLIST_INIT(&clock->timerlists); 1313f53bc61SPaolo Bonzini main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL); 132db1a4972SPaolo Bonzini } 133db1a4972SPaolo Bonzini 13440daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type) 135ff83c66eSAlex Bligh { 13640daca54SAlex Bligh return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); 137ff83c66eSAlex Bligh } 138ff83c66eSAlex Bligh 13940daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type) 140b1bbfe72SAlex Bligh { 141b1bbfe72SAlex Bligh QEMUTimerList *timer_list; 14240daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 143b1bbfe72SAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 144b1bbfe72SAlex Bligh timerlist_notify(timer_list); 145b1bbfe72SAlex Bligh } 146b1bbfe72SAlex Bligh } 147b1bbfe72SAlex Bligh 1483c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop 1493c053411SLiu Ping Fan * executing qemu_run_timers. Thus, this functions should not 1503c053411SLiu Ping Fan * be used from the callback of a timer that is based on @clock. 1513c053411SLiu Ping Fan * Doing so would cause a deadlock. 1523c053411SLiu Ping Fan * 1533c053411SLiu Ping Fan * Caller should hold BQL. 1543c053411SLiu Ping Fan */ 15540daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled) 156db1a4972SPaolo Bonzini { 15740daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 1583c053411SLiu Ping Fan QEMUTimerList *tl; 159fbdc14ebSPaolo Bonzini bool old = clock->enabled; 160db1a4972SPaolo Bonzini clock->enabled = enabled; 161fbdc14ebSPaolo Bonzini if (enabled && !old) { 16240daca54SAlex Bligh qemu_clock_notify(type); 1633c053411SLiu Ping Fan } else if (!enabled && old) { 1643c053411SLiu Ping Fan QLIST_FOREACH(tl, &clock->timerlists, list) { 1653c053411SLiu Ping Fan qemu_event_wait(&tl->timers_done_ev); 1663c053411SLiu Ping Fan } 167fbdc14ebSPaolo Bonzini } 168db1a4972SPaolo Bonzini } 169db1a4972SPaolo Bonzini 170ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list) 171dc2dfcf0SPaolo Bonzini { 1728caa05d8SPaolo Bonzini return !!atomic_read(&timer_list->active_timers); 173dc2dfcf0SPaolo Bonzini } 174dc2dfcf0SPaolo Bonzini 17540daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type) 176dc2dfcf0SPaolo Bonzini { 17740daca54SAlex Bligh return timerlist_has_timers( 1787bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 179dc2dfcf0SPaolo Bonzini } 180dc2dfcf0SPaolo Bonzini 181ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list) 182ff83c66eSAlex Bligh { 183978f2205SStefan Hajnoczi int64_t expire_time; 184978f2205SStefan Hajnoczi 1858caa05d8SPaolo Bonzini if (!atomic_read(&timer_list->active_timers)) { 1868caa05d8SPaolo Bonzini return false; 1878caa05d8SPaolo Bonzini } 1888caa05d8SPaolo Bonzini 189978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 190978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 191978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 192978f2205SStefan Hajnoczi return false; 193978f2205SStefan Hajnoczi } 194978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 195978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 196978f2205SStefan Hajnoczi 19733bef0b9SPaolo Bonzini return expire_time <= qemu_clock_get_ns(timer_list->clock->type); 198ff83c66eSAlex Bligh } 199ff83c66eSAlex Bligh 20040daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type) 201ff83c66eSAlex Bligh { 20240daca54SAlex Bligh return timerlist_expired( 2037bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 204ff83c66eSAlex Bligh } 205ff83c66eSAlex Bligh 20602a03a9fSAlex Bligh /* 20702a03a9fSAlex Bligh * As above, but return -1 for no deadline, and do not cap to 2^32 20802a03a9fSAlex Bligh * as we know the result is always positive. 20902a03a9fSAlex Bligh */ 21002a03a9fSAlex Bligh 211ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) 21202a03a9fSAlex Bligh { 21302a03a9fSAlex Bligh int64_t delta; 214978f2205SStefan Hajnoczi int64_t expire_time; 21502a03a9fSAlex Bligh 2168caa05d8SPaolo Bonzini if (!atomic_read(&timer_list->active_timers)) { 2178caa05d8SPaolo Bonzini return -1; 2188caa05d8SPaolo Bonzini } 2198caa05d8SPaolo Bonzini 220978f2205SStefan Hajnoczi if (!timer_list->clock->enabled) { 22102a03a9fSAlex Bligh return -1; 22202a03a9fSAlex Bligh } 22302a03a9fSAlex Bligh 224978f2205SStefan Hajnoczi /* The active timers list may be modified before the caller uses our return 225978f2205SStefan Hajnoczi * value but ->notify_cb() is called when the deadline changes. Therefore 226978f2205SStefan Hajnoczi * the caller should notice the change and there is no race condition. 227978f2205SStefan Hajnoczi */ 228978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 229978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 230978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 231978f2205SStefan Hajnoczi return -1; 232978f2205SStefan Hajnoczi } 233978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 234978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 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 */ 325*5bd34354SFrediano 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) { 3898caa05d8SPaolo Bonzini atomic_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; 4128caa05d8SPaolo Bonzini atomic_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. */ 420e76d1798SPavel Dovgalyuk if (timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { 421e76d1798SPavel Dovgalyuk qemu_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 463add40e97SPaolo Bonzini qemu_mutex_lock(&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 } 472add40e97SPaolo Bonzini qemu_mutex_unlock(&timer_list->active_timers_lock); 473add40e97SPaolo Bonzini 474add40e97SPaolo Bonzini if (rearm) { 475add40e97SPaolo Bonzini timerlist_rearm(timer_list); 476add40e97SPaolo Bonzini } 477add40e97SPaolo Bonzini } 478add40e97SPaolo Bonzini 47940daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time) 4804a998740SPaolo Bonzini { 48140daca54SAlex Bligh timer_mod_ns(ts, expire_time * ts->scale); 4824a998740SPaolo Bonzini } 4834a998740SPaolo Bonzini 484add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) 485add40e97SPaolo Bonzini { 486add40e97SPaolo Bonzini timer_mod_anticipate_ns(ts, expire_time * ts->scale); 487add40e97SPaolo Bonzini } 488add40e97SPaolo Bonzini 489e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts) 490db1a4972SPaolo Bonzini { 4913db1ee7cSPaolo Bonzini return ts->expire_time >= 0; 492db1a4972SPaolo Bonzini } 493db1a4972SPaolo Bonzini 494e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time) 495db1a4972SPaolo Bonzini { 496e93379b0SAlex Bligh return timer_expired_ns(timer_head, current_time * timer_head->scale); 497db1a4972SPaolo Bonzini } 498db1a4972SPaolo Bonzini 499ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list) 500db1a4972SPaolo Bonzini { 501144b97c2SPaolo Bonzini QEMUTimer *ts; 502db1a4972SPaolo Bonzini int64_t current_time; 503f9a976b7SAlex Bligh bool progress = false; 504978f2205SStefan Hajnoczi QEMUTimerCB *cb; 505978f2205SStefan Hajnoczi void *opaque; 506e81f8679SArtem Pisarenko bool need_replay_checkpoint = false; 507db1a4972SPaolo Bonzini 5088caa05d8SPaolo Bonzini if (!atomic_read(&timer_list->active_timers)) { 5098caa05d8SPaolo Bonzini return false; 5108caa05d8SPaolo Bonzini } 5118caa05d8SPaolo Bonzini 5123c053411SLiu Ping Fan qemu_event_reset(&timer_list->timers_done_ev); 5138caa05d8SPaolo Bonzini if (!timer_list->clock->enabled) { 5143c053411SLiu Ping Fan goto out; 515ff83c66eSAlex Bligh } 516db1a4972SPaolo Bonzini 5178bd7f71dSPavel Dovgalyuk switch (timer_list->clock->type) { 5188bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_REALTIME: 5198bd7f71dSPavel Dovgalyuk break; 5208bd7f71dSPavel Dovgalyuk default: 5218bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL: 522e81f8679SArtem Pisarenko if (replay_mode != REPLAY_MODE_NONE) { 523e81f8679SArtem Pisarenko /* Checkpoint for virtual clock is redundant in cases where 524e81f8679SArtem Pisarenko * it's being triggered with only non-EXTERNAL timers, because 525e81f8679SArtem Pisarenko * these timers don't change guest state directly. 526e81f8679SArtem Pisarenko * Since it has conditional dependence on specific timers, it is 527e81f8679SArtem Pisarenko * subject to race conditions and requires special handling. 528e81f8679SArtem Pisarenko * See below. 529e81f8679SArtem Pisarenko */ 530e81f8679SArtem Pisarenko need_replay_checkpoint = true; 5318bd7f71dSPavel Dovgalyuk } 5328bd7f71dSPavel Dovgalyuk break; 5338bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_HOST: 5348bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) { 5358bd7f71dSPavel Dovgalyuk goto out; 5368bd7f71dSPavel Dovgalyuk } 5378bd7f71dSPavel Dovgalyuk break; 5388bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 5398bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) { 5408bd7f71dSPavel Dovgalyuk goto out; 5418bd7f71dSPavel Dovgalyuk } 5428bd7f71dSPavel Dovgalyuk break; 5438bd7f71dSPavel Dovgalyuk } 5448bd7f71dSPavel Dovgalyuk 545e81f8679SArtem Pisarenko /* 546e81f8679SArtem Pisarenko * Extract expired timers from active timers list and and process them. 547e81f8679SArtem Pisarenko * 548e81f8679SArtem Pisarenko * In rr mode we need "filtered" checkpointing for virtual clock. The 549e81f8679SArtem Pisarenko * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer, 550e81f8679SArtem Pisarenko * and that must only be done once since the clock value stays the same. Because 551e81f8679SArtem Pisarenko * non-EXTERNAL timers may appear in the timers list while it being processed, 552e81f8679SArtem Pisarenko * the checkpoint can be issued at a time until no timers are left and we are 553e81f8679SArtem Pisarenko * done". 554e81f8679SArtem Pisarenko */ 55540daca54SAlex Bligh current_time = qemu_clock_get_ns(timer_list->clock->type); 556978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 557e81f8679SArtem Pisarenko while ((ts = timer_list->active_timers)) { 558e93379b0SAlex Bligh if (!timer_expired_ns(ts, current_time)) { 559e81f8679SArtem Pisarenko /* No expired timers left. The checkpoint can be skipped 560e81f8679SArtem Pisarenko * if no timers fired or they were all external. 561e81f8679SArtem Pisarenko */ 562db1a4972SPaolo Bonzini break; 56345c7b37fSStefan Weil } 564e81f8679SArtem Pisarenko if (need_replay_checkpoint 565e81f8679SArtem Pisarenko && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) { 566e81f8679SArtem Pisarenko /* once we got here, checkpoint clock only once */ 567e81f8679SArtem Pisarenko need_replay_checkpoint = false; 568e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 569e81f8679SArtem Pisarenko if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { 570e81f8679SArtem Pisarenko goto out; 571e81f8679SArtem Pisarenko } 572e81f8679SArtem Pisarenko qemu_mutex_lock(&timer_list->active_timers_lock); 573e81f8679SArtem Pisarenko /* The lock was released; start over again in case the list was 574e81f8679SArtem Pisarenko * modified. 575e81f8679SArtem Pisarenko */ 576e81f8679SArtem Pisarenko continue; 577e81f8679SArtem Pisarenko } 578978f2205SStefan Hajnoczi 579db1a4972SPaolo Bonzini /* remove timer from the list before calling the callback */ 580ff83c66eSAlex Bligh timer_list->active_timers = ts->next; 581db1a4972SPaolo Bonzini ts->next = NULL; 5823db1ee7cSPaolo Bonzini ts->expire_time = -1; 583978f2205SStefan Hajnoczi cb = ts->cb; 584978f2205SStefan Hajnoczi opaque = ts->opaque; 585db1a4972SPaolo Bonzini 586db1a4972SPaolo Bonzini /* run the callback (the timer list can be modified) */ 587e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 588978f2205SStefan Hajnoczi cb(opaque); 589e81f8679SArtem Pisarenko qemu_mutex_lock(&timer_list->active_timers_lock); 590e81f8679SArtem Pisarenko 591f9a976b7SAlex Bligh progress = true; 592db1a4972SPaolo Bonzini } 593e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 5943c053411SLiu Ping Fan 5953c053411SLiu Ping Fan out: 5963c053411SLiu Ping Fan qemu_event_set(&timer_list->timers_done_ev); 597f9a976b7SAlex Bligh return progress; 598db1a4972SPaolo Bonzini } 599db1a4972SPaolo Bonzini 60040daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type) 60140daca54SAlex Bligh { 6027bf8fbdeSAlex Bligh return timerlist_run_timers(main_loop_tlg.tl[type]); 60340daca54SAlex Bligh } 60440daca54SAlex Bligh 605d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg, 606d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, void *opaque) 607754d6a54SAlex Bligh { 608754d6a54SAlex Bligh QEMUClockType type; 609754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 610d5541d86SAlex Bligh tlg->tl[type] = timerlist_new(type, cb, opaque); 611754d6a54SAlex Bligh } 612754d6a54SAlex Bligh } 613754d6a54SAlex Bligh 614754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg) 615754d6a54SAlex Bligh { 616754d6a54SAlex Bligh QEMUClockType type; 617754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 618754d6a54SAlex Bligh timerlist_free(tlg->tl[type]); 619754d6a54SAlex Bligh } 620754d6a54SAlex Bligh } 621754d6a54SAlex Bligh 622754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 623754d6a54SAlex Bligh { 624754d6a54SAlex Bligh QEMUClockType type; 625754d6a54SAlex Bligh bool progress = false; 626754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 627754d6a54SAlex Bligh progress |= timerlist_run_timers(tlg->tl[type]); 628754d6a54SAlex Bligh } 629754d6a54SAlex Bligh return progress; 630754d6a54SAlex Bligh } 631754d6a54SAlex Bligh 632754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 633754d6a54SAlex Bligh { 634754d6a54SAlex Bligh int64_t deadline = -1; 635754d6a54SAlex Bligh QEMUClockType type; 636754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6378bd7f71dSPavel Dovgalyuk if (qemu_clock_use_for_deadline(type)) { 638754d6a54SAlex Bligh deadline = qemu_soonest_timeout(deadline, 6398bd7f71dSPavel Dovgalyuk timerlist_deadline_ns(tlg->tl[type])); 640754d6a54SAlex Bligh } 641754d6a54SAlex Bligh } 642754d6a54SAlex Bligh return deadline; 643754d6a54SAlex Bligh } 644754d6a54SAlex Bligh 64540daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type) 646db1a4972SPaolo Bonzini { 64740daca54SAlex Bligh switch (type) { 648db1a4972SPaolo Bonzini case QEMU_CLOCK_REALTIME: 649db1a4972SPaolo Bonzini return get_clock(); 650db1a4972SPaolo Bonzini default: 651db1a4972SPaolo Bonzini case QEMU_CLOCK_VIRTUAL: 652db1a4972SPaolo Bonzini if (use_icount) { 653db1a4972SPaolo Bonzini return cpu_get_icount(); 654db1a4972SPaolo Bonzini } else { 655db1a4972SPaolo Bonzini return cpu_get_clock(); 656db1a4972SPaolo Bonzini } 657db1a4972SPaolo Bonzini case QEMU_CLOCK_HOST: 6583c2d4c8aSDr. David Alan Gilbert return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); 6594e7fa73eSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 6608eda206eSPavel Dovgalyuk return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock()); 661691a0c9cSJan Kiszka } 662691a0c9cSJan Kiszka } 663691a0c9cSJan Kiszka 6643f53bc61SPaolo Bonzini void init_clocks(QEMUTimerListNotifyCB *notify_cb) 665db1a4972SPaolo Bonzini { 666ff83c66eSAlex Bligh QEMUClockType type; 667ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6683f53bc61SPaolo Bonzini qemu_clock_init(type, notify_cb); 669ff83c66eSAlex Bligh } 670ff83c66eSAlex Bligh 671cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 672cd758dd0SAlex Bligh prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 673cd758dd0SAlex Bligh #endif 674744ca8e3SPaolo Bonzini } 675db1a4972SPaolo Bonzini 676e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts) 677db1a4972SPaolo Bonzini { 678e93379b0SAlex Bligh return timer_pending(ts) ? ts->expire_time : -1; 679db1a4972SPaolo Bonzini } 680db1a4972SPaolo Bonzini 68140daca54SAlex Bligh bool qemu_clock_run_all_timers(void) 682db1a4972SPaolo Bonzini { 683f9a976b7SAlex Bligh bool progress = false; 684ff83c66eSAlex Bligh QEMUClockType type; 6856d327171SAlex Bligh 686ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6876b8f0187SPaolo Bonzini if (qemu_clock_use_for_deadline(type)) { 68840daca54SAlex Bligh progress |= qemu_clock_run_timers(type); 689ff83c66eSAlex Bligh } 6906b8f0187SPaolo Bonzini } 691158fd3ceSPeter Portante 692f9a976b7SAlex Bligh return progress; 693db1a4972SPaolo Bonzini } 694