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" 32740b1759SClaudio Fontana #include "sysemu/qtest.h" 331ac0206bSPeter Maydell 3430ea8339SAnthony Liguori #ifdef CONFIG_POSIX 3530ea8339SAnthony Liguori #include <pthread.h> 3630ea8339SAnthony Liguori #endif 37bff9f8bfSStefan Weil 384e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 394e0c6529SAlex Bligh #include <poll.h> 404e0c6529SAlex Bligh #endif 414e0c6529SAlex Bligh 42cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 43cd758dd0SAlex Bligh #include <sys/prctl.h> 44cd758dd0SAlex Bligh #endif 45cd758dd0SAlex Bligh 46db1a4972SPaolo Bonzini /***********************************************************/ 47db1a4972SPaolo Bonzini /* timers */ 48db1a4972SPaolo Bonzini 49b4049b74SAlex Bligh typedef struct QEMUClock { 503c053411SLiu Ping Fan /* We rely on BQL to protect the timerlists */ 51ff83c66eSAlex Bligh QLIST_HEAD(, QEMUTimerList) timerlists; 52691a0c9cSJan Kiszka 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 1243f53bc61SPaolo Bonzini static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb) 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); 133ff83c66eSAlex Bligh QLIST_INIT(&clock->timerlists); 1343f53bc61SPaolo Bonzini main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL); 135db1a4972SPaolo Bonzini } 136db1a4972SPaolo Bonzini 13740daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type) 138ff83c66eSAlex Bligh { 139740b1759SClaudio Fontana return !(icount_enabled() && (type == QEMU_CLOCK_VIRTUAL)); 140ff83c66eSAlex Bligh } 141ff83c66eSAlex Bligh 14240daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type) 143b1bbfe72SAlex Bligh { 144b1bbfe72SAlex Bligh QEMUTimerList *timer_list; 14540daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 146b1bbfe72SAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 147b1bbfe72SAlex Bligh timerlist_notify(timer_list); 148b1bbfe72SAlex Bligh } 149b1bbfe72SAlex Bligh } 150b1bbfe72SAlex Bligh 1513c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop 1523c053411SLiu Ping Fan * executing qemu_run_timers. Thus, this functions should not 1533c053411SLiu Ping Fan * be used from the callback of a timer that is based on @clock. 1543c053411SLiu Ping Fan * Doing so would cause a deadlock. 1553c053411SLiu Ping Fan * 1563c053411SLiu Ping Fan * Caller should hold BQL. 1573c053411SLiu Ping Fan */ 15840daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled) 159db1a4972SPaolo Bonzini { 16040daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 1613c053411SLiu Ping Fan QEMUTimerList *tl; 162fbdc14ebSPaolo Bonzini bool old = clock->enabled; 163db1a4972SPaolo Bonzini clock->enabled = enabled; 164fbdc14ebSPaolo Bonzini if (enabled && !old) { 16540daca54SAlex Bligh qemu_clock_notify(type); 1663c053411SLiu Ping Fan } else if (!enabled && old) { 1673c053411SLiu Ping Fan QLIST_FOREACH(tl, &clock->timerlists, list) { 1683c053411SLiu Ping Fan qemu_event_wait(&tl->timers_done_ev); 1693c053411SLiu Ping Fan } 170fbdc14ebSPaolo Bonzini } 171db1a4972SPaolo Bonzini } 172db1a4972SPaolo Bonzini 173ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list) 174dc2dfcf0SPaolo Bonzini { 175d73415a3SStefan Hajnoczi return !!qatomic_read(&timer_list->active_timers); 176dc2dfcf0SPaolo Bonzini } 177dc2dfcf0SPaolo Bonzini 17840daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type) 179dc2dfcf0SPaolo Bonzini { 18040daca54SAlex Bligh return timerlist_has_timers( 1817bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 182dc2dfcf0SPaolo Bonzini } 183dc2dfcf0SPaolo Bonzini 184ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list) 185ff83c66eSAlex Bligh { 186978f2205SStefan Hajnoczi int64_t expire_time; 187978f2205SStefan Hajnoczi 188d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 1898caa05d8SPaolo Bonzini return false; 1908caa05d8SPaolo Bonzini } 1918caa05d8SPaolo Bonzini 1923284c3ddSStefan Hajnoczi WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 193978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 194978f2205SStefan Hajnoczi return false; 195978f2205SStefan Hajnoczi } 196978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 1973284c3ddSStefan Hajnoczi } 198978f2205SStefan Hajnoczi 19933bef0b9SPaolo Bonzini return expire_time <= qemu_clock_get_ns(timer_list->clock->type); 200ff83c66eSAlex Bligh } 201ff83c66eSAlex Bligh 20240daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type) 203ff83c66eSAlex Bligh { 20440daca54SAlex Bligh return timerlist_expired( 2057bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 206ff83c66eSAlex Bligh } 207ff83c66eSAlex Bligh 20802a03a9fSAlex Bligh /* 20902a03a9fSAlex Bligh * As above, but return -1 for no deadline, and do not cap to 2^32 21002a03a9fSAlex Bligh * as we know the result is always positive. 21102a03a9fSAlex Bligh */ 21202a03a9fSAlex Bligh 213ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) 21402a03a9fSAlex Bligh { 21502a03a9fSAlex Bligh int64_t delta; 216978f2205SStefan Hajnoczi int64_t expire_time; 21702a03a9fSAlex Bligh 218d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 2198caa05d8SPaolo Bonzini return -1; 2208caa05d8SPaolo Bonzini } 2218caa05d8SPaolo Bonzini 222978f2205SStefan Hajnoczi if (!timer_list->clock->enabled) { 22302a03a9fSAlex Bligh return -1; 22402a03a9fSAlex Bligh } 22502a03a9fSAlex Bligh 226978f2205SStefan Hajnoczi /* The active timers list may be modified before the caller uses our return 227978f2205SStefan Hajnoczi * value but ->notify_cb() is called when the deadline changes. Therefore 228978f2205SStefan Hajnoczi * the caller should notice the change and there is no race condition. 229978f2205SStefan Hajnoczi */ 2303284c3ddSStefan Hajnoczi WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 231978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 232978f2205SStefan Hajnoczi return -1; 233978f2205SStefan Hajnoczi } 234978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 2353284c3ddSStefan Hajnoczi } 236978f2205SStefan Hajnoczi 237978f2205SStefan Hajnoczi delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 23802a03a9fSAlex Bligh 23902a03a9fSAlex Bligh if (delta <= 0) { 24002a03a9fSAlex Bligh return 0; 24102a03a9fSAlex Bligh } 24202a03a9fSAlex Bligh 24302a03a9fSAlex Bligh return delta; 24402a03a9fSAlex Bligh } 24502a03a9fSAlex Bligh 246ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached 247ac70aafcSAlex Bligh * to the clock. This is used for the icount timeout so we 248ac70aafcSAlex Bligh * ignore whether or not the clock should be used in deadline 249ac70aafcSAlex Bligh * calculations. 250ac70aafcSAlex Bligh */ 251dcb15780SPavel Dovgalyuk int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) 252ac70aafcSAlex Bligh { 253ac70aafcSAlex Bligh int64_t deadline = -1; 254dcb15780SPavel Dovgalyuk int64_t delta; 255dcb15780SPavel Dovgalyuk int64_t expire_time; 256dcb15780SPavel Dovgalyuk QEMUTimer *ts; 257ac70aafcSAlex Bligh QEMUTimerList *timer_list; 25840daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 259dcb15780SPavel Dovgalyuk 260dcb15780SPavel Dovgalyuk if (!clock->enabled) { 261dcb15780SPavel Dovgalyuk return -1; 262dcb15780SPavel Dovgalyuk } 263dcb15780SPavel Dovgalyuk 264ac70aafcSAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 265dcb15780SPavel Dovgalyuk qemu_mutex_lock(&timer_list->active_timers_lock); 266dcb15780SPavel Dovgalyuk ts = timer_list->active_timers; 267dcb15780SPavel Dovgalyuk /* Skip all external timers */ 268dcb15780SPavel Dovgalyuk while (ts && (ts->attributes & ~attr_mask)) { 269dcb15780SPavel Dovgalyuk ts = ts->next; 270dcb15780SPavel Dovgalyuk } 271dcb15780SPavel Dovgalyuk if (!ts) { 272dcb15780SPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 273dcb15780SPavel Dovgalyuk continue; 274dcb15780SPavel Dovgalyuk } 275dcb15780SPavel Dovgalyuk expire_time = ts->expire_time; 276dcb15780SPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 277dcb15780SPavel Dovgalyuk 278dcb15780SPavel Dovgalyuk delta = expire_time - qemu_clock_get_ns(type); 279dcb15780SPavel Dovgalyuk if (delta <= 0) { 280dcb15780SPavel Dovgalyuk delta = 0; 281dcb15780SPavel Dovgalyuk } 282dcb15780SPavel Dovgalyuk deadline = qemu_soonest_timeout(deadline, delta); 283ac70aafcSAlex Bligh } 284ac70aafcSAlex Bligh return deadline; 285ac70aafcSAlex Bligh } 286ac70aafcSAlex Bligh 28740daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) 288ff83c66eSAlex Bligh { 28940daca54SAlex Bligh return timer_list->clock->type; 290ff83c66eSAlex Bligh } 291ff83c66eSAlex Bligh 29240daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) 293ff83c66eSAlex Bligh { 2947bf8fbdeSAlex Bligh return main_loop_tlg.tl[type]; 295ff83c66eSAlex Bligh } 296ff83c66eSAlex Bligh 297d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list) 298d5541d86SAlex Bligh { 299d5541d86SAlex Bligh if (timer_list->notify_cb) { 3003f53bc61SPaolo Bonzini timer_list->notify_cb(timer_list->notify_opaque, timer_list->clock->type); 301d5541d86SAlex Bligh } else { 302d5541d86SAlex Bligh qemu_notify_event(); 303d5541d86SAlex Bligh } 304d5541d86SAlex Bligh } 305d5541d86SAlex Bligh 30602a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms 30702a03a9fSAlex Bligh * This is used where a system does not support ppoll 30802a03a9fSAlex Bligh */ 30902a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns) 31002a03a9fSAlex Bligh { 31102a03a9fSAlex Bligh int64_t ms; 31202a03a9fSAlex Bligh if (ns < 0) { 31302a03a9fSAlex Bligh return -1; 31402a03a9fSAlex Bligh } 31502a03a9fSAlex Bligh 31602a03a9fSAlex Bligh if (!ns) { 31702a03a9fSAlex Bligh return 0; 31802a03a9fSAlex Bligh } 31902a03a9fSAlex Bligh 32002a03a9fSAlex Bligh /* Always round up, because it's better to wait too long than to wait too 32102a03a9fSAlex Bligh * little and effectively busy-wait 32202a03a9fSAlex Bligh */ 3235029b969SLaurent Vivier ms = DIV_ROUND_UP(ns, SCALE_MS); 32402a03a9fSAlex Bligh 32502a03a9fSAlex Bligh /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ 3265bd34354SFrediano Ziglio return MIN(ms, INT32_MAX); 32702a03a9fSAlex Bligh } 32802a03a9fSAlex Bligh 32902a03a9fSAlex Bligh 3304e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is 3314e0c6529SAlex Bligh * otherwise identical to g_poll 3324e0c6529SAlex Bligh */ 3334e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) 3344e0c6529SAlex Bligh { 3354e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 3364e0c6529SAlex Bligh if (timeout < 0) { 3374e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, NULL, NULL); 3384e0c6529SAlex Bligh } else { 3394e0c6529SAlex Bligh struct timespec ts; 340490309fcSPeter Maydell int64_t tvsec = timeout / 1000000000LL; 341490309fcSPeter Maydell /* Avoid possibly overflowing and specifying a negative number of 342490309fcSPeter Maydell * seconds, which would turn a very long timeout into a busy-wait. 343490309fcSPeter Maydell */ 344490309fcSPeter Maydell if (tvsec > (int64_t)INT32_MAX) { 345490309fcSPeter Maydell tvsec = INT32_MAX; 346490309fcSPeter Maydell } 347490309fcSPeter Maydell ts.tv_sec = tvsec; 3484e0c6529SAlex Bligh ts.tv_nsec = timeout % 1000000000LL; 3494e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, &ts, NULL); 3504e0c6529SAlex Bligh } 3514e0c6529SAlex Bligh #else 3524e0c6529SAlex Bligh return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); 3534e0c6529SAlex Bligh #endif 3544e0c6529SAlex Bligh } 3554e0c6529SAlex Bligh 3564e0c6529SAlex Bligh 35789a603a0SArtem Pisarenko void timer_init_full(QEMUTimer *ts, 35889a603a0SArtem Pisarenko QEMUTimerListGroup *timer_list_group, QEMUClockType type, 35989a603a0SArtem Pisarenko int scale, int attributes, 3604a998740SPaolo Bonzini QEMUTimerCB *cb, void *opaque) 361db1a4972SPaolo Bonzini { 36289a603a0SArtem Pisarenko if (!timer_list_group) { 36389a603a0SArtem Pisarenko timer_list_group = &main_loop_tlg; 36489a603a0SArtem Pisarenko } 36589a603a0SArtem Pisarenko ts->timer_list = timer_list_group->tl[type]; 366db1a4972SPaolo Bonzini ts->cb = cb; 367db1a4972SPaolo Bonzini ts->opaque = opaque; 3684a998740SPaolo Bonzini ts->scale = scale; 36989a603a0SArtem Pisarenko ts->attributes = attributes; 3703db1ee7cSPaolo Bonzini ts->expire_time = -1; 371ff83c66eSAlex Bligh } 372ff83c66eSAlex Bligh 373cd1bd53aSPaolo Bonzini void timer_deinit(QEMUTimer *ts) 374cd1bd53aSPaolo Bonzini { 375cd1bd53aSPaolo Bonzini assert(ts->expire_time == -1); 376cd1bd53aSPaolo Bonzini ts->timer_list = NULL; 377cd1bd53aSPaolo Bonzini } 378cd1bd53aSPaolo Bonzini 379978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) 380db1a4972SPaolo Bonzini { 381db1a4972SPaolo Bonzini QEMUTimer **pt, *t; 382db1a4972SPaolo Bonzini 3833db1ee7cSPaolo Bonzini ts->expire_time = -1; 384978f2205SStefan Hajnoczi pt = &timer_list->active_timers; 385db1a4972SPaolo Bonzini for(;;) { 386db1a4972SPaolo Bonzini t = *pt; 387db1a4972SPaolo Bonzini if (!t) 388db1a4972SPaolo Bonzini break; 389db1a4972SPaolo Bonzini if (t == ts) { 390d73415a3SStefan Hajnoczi qatomic_set(pt, t->next); 391db1a4972SPaolo Bonzini break; 392db1a4972SPaolo Bonzini } 393db1a4972SPaolo Bonzini pt = &t->next; 394db1a4972SPaolo Bonzini } 395db1a4972SPaolo Bonzini } 396db1a4972SPaolo Bonzini 3970f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list, 3980f809e5fSPaolo Bonzini QEMUTimer *ts, int64_t expire_time) 3990f809e5fSPaolo Bonzini { 4000f809e5fSPaolo Bonzini QEMUTimer **pt, *t; 4010f809e5fSPaolo Bonzini 4020f809e5fSPaolo Bonzini /* add the timer in the sorted list */ 4030f809e5fSPaolo Bonzini pt = &timer_list->active_timers; 4040f809e5fSPaolo Bonzini for (;;) { 4050f809e5fSPaolo Bonzini t = *pt; 4060f809e5fSPaolo Bonzini if (!timer_expired_ns(t, expire_time)) { 4070f809e5fSPaolo Bonzini break; 4080f809e5fSPaolo Bonzini } 4090f809e5fSPaolo Bonzini pt = &t->next; 4100f809e5fSPaolo Bonzini } 4110f809e5fSPaolo Bonzini ts->expire_time = MAX(expire_time, 0); 4120f809e5fSPaolo Bonzini ts->next = *pt; 413d73415a3SStefan Hajnoczi qatomic_set(pt, ts); 4140f809e5fSPaolo Bonzini 4150f809e5fSPaolo Bonzini return pt == &timer_list->active_timers; 4160f809e5fSPaolo Bonzini } 4170f809e5fSPaolo Bonzini 4180f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list) 4190f809e5fSPaolo Bonzini { 4200f809e5fSPaolo Bonzini /* Interrupt execution to force deadline recalculation. */ 421740b1759SClaudio Fontana if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { 4228191d368SClaudio Fontana icount_start_warp_timer(); 423e76d1798SPavel Dovgalyuk } 4240f809e5fSPaolo Bonzini timerlist_notify(timer_list); 4250f809e5fSPaolo Bonzini } 4260f809e5fSPaolo Bonzini 427978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */ 428978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts) 429978f2205SStefan Hajnoczi { 430978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 431978f2205SStefan Hajnoczi 432cd1bd53aSPaolo Bonzini if (timer_list) { 433978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 434978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 435978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 436978f2205SStefan Hajnoczi } 437cd1bd53aSPaolo Bonzini } 438978f2205SStefan Hajnoczi 439db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 440db1a4972SPaolo Bonzini >= expire_time. The corresponding callback will be called. */ 44140daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) 442db1a4972SPaolo Bonzini { 443978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 4440f809e5fSPaolo Bonzini bool rearm; 445db1a4972SPaolo Bonzini 446978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 447978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 4480f809e5fSPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 449978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 450db1a4972SPaolo Bonzini 4510f809e5fSPaolo Bonzini if (rearm) { 4520f809e5fSPaolo Bonzini timerlist_rearm(timer_list); 453db1a4972SPaolo Bonzini } 454db1a4972SPaolo Bonzini } 455db1a4972SPaolo Bonzini 456add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 457add40e97SPaolo Bonzini >= expire_time or the current deadline, whichever comes earlier. 458add40e97SPaolo Bonzini The corresponding callback will be called. */ 459add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) 460add40e97SPaolo Bonzini { 461add40e97SPaolo Bonzini QEMUTimerList *timer_list = ts->timer_list; 462add40e97SPaolo Bonzini bool rearm; 463add40e97SPaolo Bonzini 4646e8a355dSDaniel Brodsky WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 465add40e97SPaolo Bonzini if (ts->expire_time == -1 || ts->expire_time > expire_time) { 466add40e97SPaolo Bonzini if (ts->expire_time != -1) { 467add40e97SPaolo Bonzini timer_del_locked(timer_list, ts); 468add40e97SPaolo Bonzini } 469add40e97SPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 470add40e97SPaolo Bonzini } else { 471add40e97SPaolo Bonzini rearm = false; 472add40e97SPaolo Bonzini } 4736e8a355dSDaniel Brodsky } 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; 506db1a4972SPaolo Bonzini 507d73415a3SStefan Hajnoczi if (!qatomic_read(&timer_list->active_timers)) { 5088caa05d8SPaolo Bonzini return false; 5098caa05d8SPaolo Bonzini } 5108caa05d8SPaolo Bonzini 5113c053411SLiu Ping Fan qemu_event_reset(&timer_list->timers_done_ev); 5128caa05d8SPaolo Bonzini if (!timer_list->clock->enabled) { 5133c053411SLiu Ping Fan goto out; 514ff83c66eSAlex Bligh } 515db1a4972SPaolo Bonzini 5168bd7f71dSPavel Dovgalyuk switch (timer_list->clock->type) { 5178bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_REALTIME: 5188bd7f71dSPavel Dovgalyuk break; 5198bd7f71dSPavel Dovgalyuk default: 5208bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL: 5218bd7f71dSPavel Dovgalyuk break; 5228bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_HOST: 5238bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) { 5248bd7f71dSPavel Dovgalyuk goto out; 5258bd7f71dSPavel Dovgalyuk } 5268bd7f71dSPavel Dovgalyuk break; 5278bd7f71dSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 5288bd7f71dSPavel Dovgalyuk if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) { 5298bd7f71dSPavel Dovgalyuk goto out; 5308bd7f71dSPavel Dovgalyuk } 5318bd7f71dSPavel Dovgalyuk break; 5328bd7f71dSPavel Dovgalyuk } 5338bd7f71dSPavel Dovgalyuk 534e81f8679SArtem Pisarenko /* 5353cf10b29SPhilippe Mathieu-Daudé * Extract expired timers from active timers list and process them. 536e81f8679SArtem Pisarenko * 537e81f8679SArtem Pisarenko * In rr mode we need "filtered" checkpointing for virtual clock. The 538e81f8679SArtem Pisarenko * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer, 539e81f8679SArtem Pisarenko * and that must only be done once since the clock value stays the same. Because 540e81f8679SArtem Pisarenko * non-EXTERNAL timers may appear in the timers list while it being processed, 541e81f8679SArtem Pisarenko * the checkpoint can be issued at a time until no timers are left and we are 542e81f8679SArtem Pisarenko * done". 543e81f8679SArtem Pisarenko */ 54440daca54SAlex Bligh current_time = qemu_clock_get_ns(timer_list->clock->type); 545978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 546e81f8679SArtem Pisarenko while ((ts = timer_list->active_timers)) { 547e93379b0SAlex Bligh if (!timer_expired_ns(ts, current_time)) { 548e81f8679SArtem Pisarenko /* No expired timers left. The checkpoint can be skipped 549e81f8679SArtem Pisarenko * if no timers fired or they were all external. 550e81f8679SArtem Pisarenko */ 551db1a4972SPaolo Bonzini break; 55245c7b37fSStefan Weil } 553677a3babSPavel Dovgalyuk /* Checkpoint for virtual clock is redundant in cases where 554677a3babSPavel Dovgalyuk * it's being triggered with only non-EXTERNAL timers, because 555677a3babSPavel Dovgalyuk * these timers don't change guest state directly. 556e81f8679SArtem Pisarenko */ 557677a3babSPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE 558677a3babSPavel Dovgalyuk && timer_list->clock->type == QEMU_CLOCK_VIRTUAL 559677a3babSPavel Dovgalyuk && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL) 560677a3babSPavel Dovgalyuk && !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { 561677a3babSPavel Dovgalyuk qemu_mutex_unlock(&timer_list->active_timers_lock); 562677a3babSPavel Dovgalyuk goto out; 563e81f8679SArtem Pisarenko } 564978f2205SStefan Hajnoczi 565db1a4972SPaolo Bonzini /* remove timer from the list before calling the callback */ 566ff83c66eSAlex Bligh timer_list->active_timers = ts->next; 567db1a4972SPaolo Bonzini ts->next = NULL; 5683db1ee7cSPaolo Bonzini ts->expire_time = -1; 569978f2205SStefan Hajnoczi cb = ts->cb; 570978f2205SStefan Hajnoczi opaque = ts->opaque; 571db1a4972SPaolo Bonzini 572db1a4972SPaolo Bonzini /* run the callback (the timer list can be modified) */ 573e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 574978f2205SStefan Hajnoczi cb(opaque); 575e81f8679SArtem Pisarenko qemu_mutex_lock(&timer_list->active_timers_lock); 576e81f8679SArtem Pisarenko 577f9a976b7SAlex Bligh progress = true; 578db1a4972SPaolo Bonzini } 579e81f8679SArtem Pisarenko qemu_mutex_unlock(&timer_list->active_timers_lock); 5803c053411SLiu Ping Fan 5813c053411SLiu Ping Fan out: 5823c053411SLiu Ping Fan qemu_event_set(&timer_list->timers_done_ev); 583f9a976b7SAlex Bligh return progress; 584db1a4972SPaolo Bonzini } 585db1a4972SPaolo Bonzini 58640daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type) 58740daca54SAlex Bligh { 5887bf8fbdeSAlex Bligh return timerlist_run_timers(main_loop_tlg.tl[type]); 58940daca54SAlex Bligh } 59040daca54SAlex Bligh 591d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg, 592d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, void *opaque) 593754d6a54SAlex Bligh { 594754d6a54SAlex Bligh QEMUClockType type; 595754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 596d5541d86SAlex Bligh tlg->tl[type] = timerlist_new(type, cb, opaque); 597754d6a54SAlex Bligh } 598754d6a54SAlex Bligh } 599754d6a54SAlex Bligh 600754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg) 601754d6a54SAlex Bligh { 602754d6a54SAlex Bligh QEMUClockType type; 603754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 604754d6a54SAlex Bligh timerlist_free(tlg->tl[type]); 605754d6a54SAlex Bligh } 606754d6a54SAlex Bligh } 607754d6a54SAlex Bligh 608754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 609754d6a54SAlex Bligh { 610754d6a54SAlex Bligh QEMUClockType type; 611754d6a54SAlex Bligh bool progress = false; 612754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 613754d6a54SAlex Bligh progress |= timerlist_run_timers(tlg->tl[type]); 614754d6a54SAlex Bligh } 615754d6a54SAlex Bligh return progress; 616754d6a54SAlex Bligh } 617754d6a54SAlex Bligh 618754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 619754d6a54SAlex Bligh { 620754d6a54SAlex Bligh int64_t deadline = -1; 621754d6a54SAlex Bligh QEMUClockType type; 622754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6238bd7f71dSPavel Dovgalyuk if (qemu_clock_use_for_deadline(type)) { 624754d6a54SAlex Bligh deadline = qemu_soonest_timeout(deadline, 6258bd7f71dSPavel Dovgalyuk timerlist_deadline_ns(tlg->tl[type])); 626754d6a54SAlex Bligh } 627754d6a54SAlex Bligh } 628754d6a54SAlex Bligh return deadline; 629754d6a54SAlex Bligh } 630754d6a54SAlex Bligh 63140daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type) 632db1a4972SPaolo Bonzini { 63340daca54SAlex Bligh switch (type) { 634db1a4972SPaolo Bonzini case QEMU_CLOCK_REALTIME: 635db1a4972SPaolo Bonzini return get_clock(); 636db1a4972SPaolo Bonzini default: 637db1a4972SPaolo Bonzini case QEMU_CLOCK_VIRTUAL: 638*430065daSClaudio Fontana return cpus_get_virtual_clock(); 639db1a4972SPaolo Bonzini case QEMU_CLOCK_HOST: 6403c2d4c8aSDr. David Alan Gilbert return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); 6414e7fa73eSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 6428eda206eSPavel Dovgalyuk return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock()); 643691a0c9cSJan Kiszka } 644691a0c9cSJan Kiszka } 645691a0c9cSJan Kiszka 6463f53bc61SPaolo Bonzini void init_clocks(QEMUTimerListNotifyCB *notify_cb) 647db1a4972SPaolo Bonzini { 648ff83c66eSAlex Bligh QEMUClockType type; 649ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6503f53bc61SPaolo Bonzini qemu_clock_init(type, notify_cb); 651ff83c66eSAlex Bligh } 652ff83c66eSAlex Bligh 653cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 654cd758dd0SAlex Bligh prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 655cd758dd0SAlex Bligh #endif 656744ca8e3SPaolo Bonzini } 657db1a4972SPaolo Bonzini 658e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts) 659db1a4972SPaolo Bonzini { 660e93379b0SAlex Bligh return timer_pending(ts) ? ts->expire_time : -1; 661db1a4972SPaolo Bonzini } 662db1a4972SPaolo Bonzini 66340daca54SAlex Bligh bool qemu_clock_run_all_timers(void) 664db1a4972SPaolo Bonzini { 665f9a976b7SAlex Bligh bool progress = false; 666ff83c66eSAlex Bligh QEMUClockType type; 6676d327171SAlex Bligh 668ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6696b8f0187SPaolo Bonzini if (qemu_clock_use_for_deadline(type)) { 67040daca54SAlex Bligh progress |= qemu_clock_run_timers(type); 671ff83c66eSAlex Bligh } 6726b8f0187SPaolo Bonzini } 673158fd3ceSPeter Portante 674f9a976b7SAlex Bligh return progress; 675db1a4972SPaolo Bonzini } 676