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 259c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 2683c9089eSPaolo Bonzini #include "monitor/monitor.h" 2728ecbaeeSPaolo Bonzini #include "ui/console.h" 28db1a4972SPaolo Bonzini 29db1a4972SPaolo Bonzini #include "hw/hw.h" 30db1a4972SPaolo Bonzini 311de7afc9SPaolo Bonzini #include "qemu/timer.h" 3230ea8339SAnthony Liguori #ifdef CONFIG_POSIX 3330ea8339SAnthony Liguori #include <pthread.h> 3430ea8339SAnthony Liguori #endif 35bff9f8bfSStefan Weil 364e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 374e0c6529SAlex Bligh #include <poll.h> 384e0c6529SAlex Bligh #endif 394e0c6529SAlex Bligh 40cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 41cd758dd0SAlex Bligh #include <sys/prctl.h> 42cd758dd0SAlex Bligh #endif 43cd758dd0SAlex Bligh 44db1a4972SPaolo Bonzini /***********************************************************/ 45db1a4972SPaolo Bonzini /* timers */ 46db1a4972SPaolo Bonzini 47b4049b74SAlex Bligh typedef struct QEMUClock { 483c053411SLiu Ping Fan /* We rely on BQL to protect the timerlists */ 49ff83c66eSAlex Bligh QLIST_HEAD(, QEMUTimerList) timerlists; 50691a0c9cSJan Kiszka 51691a0c9cSJan Kiszka NotifierList reset_notifiers; 52691a0c9cSJan Kiszka int64_t last; 539a14b298SStefan Weil 54ff83c66eSAlex Bligh QEMUClockType type; 559a14b298SStefan Weil bool enabled; 56b4049b74SAlex Bligh } QEMUClock; 57db1a4972SPaolo Bonzini 58754d6a54SAlex Bligh QEMUTimerListGroup main_loop_tlg; 59fbdb664cSStefan Weil static QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; 60ff83c66eSAlex Bligh 61ff83c66eSAlex Bligh /* A QEMUTimerList is a list of timers attached to a clock. More 62ff83c66eSAlex Bligh * than one QEMUTimerList can be attached to each clock, for instance 63ff83c66eSAlex Bligh * used by different AioContexts / threads. Each clock also has 64ff83c66eSAlex Bligh * a list of the QEMUTimerLists associated with it, in order that 65ff83c66eSAlex Bligh * reenabling the clock can call all the notifiers. 66ff83c66eSAlex Bligh */ 67ff83c66eSAlex Bligh 68ff83c66eSAlex Bligh struct QEMUTimerList { 699a14b298SStefan Weil QEMUClock *clock; 70978f2205SStefan Hajnoczi QemuMutex active_timers_lock; 71ff83c66eSAlex Bligh QEMUTimer *active_timers; 72ff83c66eSAlex Bligh QLIST_ENTRY(QEMUTimerList) list; 73d5541d86SAlex Bligh QEMUTimerListNotifyCB *notify_cb; 74d5541d86SAlex Bligh void *notify_opaque; 753c053411SLiu Ping Fan 763c053411SLiu Ping Fan /* lightweight method to mark the end of timerlist's running */ 773c053411SLiu Ping Fan QemuEvent timers_done_ev; 78db1a4972SPaolo Bonzini }; 79db1a4972SPaolo Bonzini 807bf8fbdeSAlex Bligh /** 817bf8fbdeSAlex Bligh * qemu_clock_ptr: 827bf8fbdeSAlex Bligh * @type: type of clock 837bf8fbdeSAlex Bligh * 847bf8fbdeSAlex Bligh * Translate a clock type into a pointer to QEMUClock object. 857bf8fbdeSAlex Bligh * 867bf8fbdeSAlex Bligh * Returns: a pointer to the QEMUClock object 877bf8fbdeSAlex Bligh */ 88b4049b74SAlex Bligh static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) 897bf8fbdeSAlex Bligh { 907bf8fbdeSAlex Bligh return &qemu_clocks[type]; 917bf8fbdeSAlex Bligh } 927bf8fbdeSAlex Bligh 93e93379b0SAlex Bligh static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) 9445c7b37fSStefan Weil { 9545c7b37fSStefan Weil return timer_head && (timer_head->expire_time <= current_time); 9645c7b37fSStefan Weil } 9745c7b37fSStefan Weil 987bf8fbdeSAlex Bligh QEMUTimerList *timerlist_new(QEMUClockType type, 99d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, 100d5541d86SAlex Bligh void *opaque) 101ff83c66eSAlex Bligh { 102ff83c66eSAlex Bligh QEMUTimerList *timer_list; 1037bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 104ff83c66eSAlex Bligh 105ff83c66eSAlex Bligh timer_list = g_malloc0(sizeof(QEMUTimerList)); 1063c053411SLiu Ping Fan qemu_event_init(&timer_list->timers_done_ev, false); 107ff83c66eSAlex Bligh timer_list->clock = clock; 108d5541d86SAlex Bligh timer_list->notify_cb = cb; 109d5541d86SAlex Bligh timer_list->notify_opaque = opaque; 110978f2205SStefan Hajnoczi qemu_mutex_init(&timer_list->active_timers_lock); 111ff83c66eSAlex Bligh QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); 112ff83c66eSAlex Bligh return timer_list; 113ff83c66eSAlex Bligh } 114ff83c66eSAlex Bligh 115ff83c66eSAlex Bligh void timerlist_free(QEMUTimerList *timer_list) 116ff83c66eSAlex Bligh { 117ff83c66eSAlex Bligh assert(!timerlist_has_timers(timer_list)); 118ff83c66eSAlex Bligh if (timer_list->clock) { 119ff83c66eSAlex Bligh QLIST_REMOVE(timer_list, list); 120ff83c66eSAlex Bligh } 121978f2205SStefan Hajnoczi qemu_mutex_destroy(&timer_list->active_timers_lock); 122ff83c66eSAlex Bligh g_free(timer_list); 123ff83c66eSAlex Bligh } 124ff83c66eSAlex Bligh 1257bf8fbdeSAlex Bligh static void qemu_clock_init(QEMUClockType type) 126db1a4972SPaolo Bonzini { 1277bf8fbdeSAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 128691a0c9cSJan Kiszka 12902ce232cSKirill Batuzov /* Assert that the clock of type TYPE has not been initialized yet. */ 13002ce232cSKirill Batuzov assert(main_loop_tlg.tl[type] == NULL); 13102ce232cSKirill Batuzov 132db1a4972SPaolo Bonzini clock->type = type; 1335e1ec7b2SStefan Weil clock->enabled = true; 1342ff68d07SPaolo Bonzini clock->last = INT64_MIN; 135ff83c66eSAlex Bligh QLIST_INIT(&clock->timerlists); 136691a0c9cSJan Kiszka notifier_list_init(&clock->reset_notifiers); 1377bf8fbdeSAlex Bligh main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); 138db1a4972SPaolo Bonzini } 139db1a4972SPaolo Bonzini 14040daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type) 141ff83c66eSAlex Bligh { 14240daca54SAlex Bligh return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); 143ff83c66eSAlex Bligh } 144ff83c66eSAlex Bligh 14540daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type) 146b1bbfe72SAlex Bligh { 147b1bbfe72SAlex Bligh QEMUTimerList *timer_list; 14840daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 149b1bbfe72SAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 150b1bbfe72SAlex Bligh timerlist_notify(timer_list); 151b1bbfe72SAlex Bligh } 152b1bbfe72SAlex Bligh } 153b1bbfe72SAlex Bligh 1543c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop 1553c053411SLiu Ping Fan * executing qemu_run_timers. Thus, this functions should not 1563c053411SLiu Ping Fan * be used from the callback of a timer that is based on @clock. 1573c053411SLiu Ping Fan * Doing so would cause a deadlock. 1583c053411SLiu Ping Fan * 1593c053411SLiu Ping Fan * Caller should hold BQL. 1603c053411SLiu Ping Fan */ 16140daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled) 162db1a4972SPaolo Bonzini { 16340daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 1643c053411SLiu Ping Fan QEMUTimerList *tl; 165fbdc14ebSPaolo Bonzini bool old = clock->enabled; 166db1a4972SPaolo Bonzini clock->enabled = enabled; 167fbdc14ebSPaolo Bonzini if (enabled && !old) { 16840daca54SAlex Bligh qemu_clock_notify(type); 1693c053411SLiu Ping Fan } else if (!enabled && old) { 1703c053411SLiu Ping Fan QLIST_FOREACH(tl, &clock->timerlists, list) { 1713c053411SLiu Ping Fan qemu_event_wait(&tl->timers_done_ev); 1723c053411SLiu Ping Fan } 173fbdc14ebSPaolo Bonzini } 174db1a4972SPaolo Bonzini } 175db1a4972SPaolo Bonzini 176ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list) 177dc2dfcf0SPaolo Bonzini { 178ff83c66eSAlex Bligh return !!timer_list->active_timers; 179dc2dfcf0SPaolo Bonzini } 180dc2dfcf0SPaolo Bonzini 18140daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type) 182dc2dfcf0SPaolo Bonzini { 18340daca54SAlex Bligh return timerlist_has_timers( 1847bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 185dc2dfcf0SPaolo Bonzini } 186dc2dfcf0SPaolo Bonzini 187ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list) 188ff83c66eSAlex Bligh { 189978f2205SStefan Hajnoczi int64_t expire_time; 190978f2205SStefan Hajnoczi 191978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 192978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 193978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 194978f2205SStefan Hajnoczi return false; 195978f2205SStefan Hajnoczi } 196978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 197978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 198978f2205SStefan Hajnoczi 199978f2205SStefan Hajnoczi 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 218978f2205SStefan Hajnoczi if (!timer_list->clock->enabled) { 21902a03a9fSAlex Bligh return -1; 22002a03a9fSAlex Bligh } 22102a03a9fSAlex Bligh 222978f2205SStefan Hajnoczi /* The active timers list may be modified before the caller uses our return 223978f2205SStefan Hajnoczi * value but ->notify_cb() is called when the deadline changes. Therefore 224978f2205SStefan Hajnoczi * the caller should notice the change and there is no race condition. 225978f2205SStefan Hajnoczi */ 226978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 227978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 228978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 229978f2205SStefan Hajnoczi return -1; 230978f2205SStefan Hajnoczi } 231978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 232978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 233978f2205SStefan Hajnoczi 234978f2205SStefan Hajnoczi delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 23502a03a9fSAlex Bligh 23602a03a9fSAlex Bligh if (delta <= 0) { 23702a03a9fSAlex Bligh return 0; 23802a03a9fSAlex Bligh } 23902a03a9fSAlex Bligh 24002a03a9fSAlex Bligh return delta; 24102a03a9fSAlex Bligh } 24202a03a9fSAlex Bligh 243ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached 244ac70aafcSAlex Bligh * to the clock. This is used for the icount timeout so we 245ac70aafcSAlex Bligh * ignore whether or not the clock should be used in deadline 246ac70aafcSAlex Bligh * calculations. 247ac70aafcSAlex Bligh */ 24840daca54SAlex Bligh int64_t qemu_clock_deadline_ns_all(QEMUClockType type) 249ac70aafcSAlex Bligh { 250ac70aafcSAlex Bligh int64_t deadline = -1; 251ac70aafcSAlex Bligh QEMUTimerList *timer_list; 25240daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 253ac70aafcSAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 254ac70aafcSAlex Bligh deadline = qemu_soonest_timeout(deadline, 255ac70aafcSAlex Bligh timerlist_deadline_ns(timer_list)); 256ac70aafcSAlex Bligh } 257ac70aafcSAlex Bligh return deadline; 258ac70aafcSAlex Bligh } 259ac70aafcSAlex Bligh 26040daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) 261ff83c66eSAlex Bligh { 26240daca54SAlex Bligh return timer_list->clock->type; 263ff83c66eSAlex Bligh } 264ff83c66eSAlex Bligh 26540daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) 266ff83c66eSAlex Bligh { 2677bf8fbdeSAlex Bligh return main_loop_tlg.tl[type]; 268ff83c66eSAlex Bligh } 269ff83c66eSAlex Bligh 270d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list) 271d5541d86SAlex Bligh { 272d5541d86SAlex Bligh if (timer_list->notify_cb) { 273d5541d86SAlex Bligh timer_list->notify_cb(timer_list->notify_opaque); 274d5541d86SAlex Bligh } else { 275d5541d86SAlex Bligh qemu_notify_event(); 276d5541d86SAlex Bligh } 277d5541d86SAlex Bligh } 278d5541d86SAlex Bligh 27902a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms 28002a03a9fSAlex Bligh * This is used where a system does not support ppoll 28102a03a9fSAlex Bligh */ 28202a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns) 28302a03a9fSAlex Bligh { 28402a03a9fSAlex Bligh int64_t ms; 28502a03a9fSAlex Bligh if (ns < 0) { 28602a03a9fSAlex Bligh return -1; 28702a03a9fSAlex Bligh } 28802a03a9fSAlex Bligh 28902a03a9fSAlex Bligh if (!ns) { 29002a03a9fSAlex Bligh return 0; 29102a03a9fSAlex Bligh } 29202a03a9fSAlex Bligh 29302a03a9fSAlex Bligh /* Always round up, because it's better to wait too long than to wait too 29402a03a9fSAlex Bligh * little and effectively busy-wait 29502a03a9fSAlex Bligh */ 29602a03a9fSAlex Bligh ms = (ns + SCALE_MS - 1) / SCALE_MS; 29702a03a9fSAlex Bligh 29802a03a9fSAlex Bligh /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ 29902a03a9fSAlex Bligh if (ms > (int64_t) INT32_MAX) { 30002a03a9fSAlex Bligh ms = INT32_MAX; 30102a03a9fSAlex Bligh } 30202a03a9fSAlex Bligh 30302a03a9fSAlex Bligh return (int) ms; 30402a03a9fSAlex Bligh } 30502a03a9fSAlex Bligh 30602a03a9fSAlex Bligh 3074e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is 3084e0c6529SAlex Bligh * otherwise identical to g_poll 3094e0c6529SAlex Bligh */ 3104e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) 3114e0c6529SAlex Bligh { 3124e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 3134e0c6529SAlex Bligh if (timeout < 0) { 3144e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, NULL, NULL); 3154e0c6529SAlex Bligh } else { 3164e0c6529SAlex Bligh struct timespec ts; 317*490309fcSPeter Maydell int64_t tvsec = timeout / 1000000000LL; 318*490309fcSPeter Maydell /* Avoid possibly overflowing and specifying a negative number of 319*490309fcSPeter Maydell * seconds, which would turn a very long timeout into a busy-wait. 320*490309fcSPeter Maydell */ 321*490309fcSPeter Maydell if (tvsec > (int64_t)INT32_MAX) { 322*490309fcSPeter Maydell tvsec = INT32_MAX; 323*490309fcSPeter Maydell } 324*490309fcSPeter Maydell ts.tv_sec = tvsec; 3254e0c6529SAlex Bligh ts.tv_nsec = timeout % 1000000000LL; 3264e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, &ts, NULL); 3274e0c6529SAlex Bligh } 3284e0c6529SAlex Bligh #else 3294e0c6529SAlex Bligh return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); 3304e0c6529SAlex Bligh #endif 3314e0c6529SAlex Bligh } 3324e0c6529SAlex Bligh 3334e0c6529SAlex Bligh 334ff83c66eSAlex Bligh void timer_init(QEMUTimer *ts, 335ff83c66eSAlex Bligh QEMUTimerList *timer_list, int scale, 3364a998740SPaolo Bonzini QEMUTimerCB *cb, void *opaque) 337db1a4972SPaolo Bonzini { 338ff83c66eSAlex Bligh ts->timer_list = timer_list; 339db1a4972SPaolo Bonzini ts->cb = cb; 340db1a4972SPaolo Bonzini ts->opaque = opaque; 3414a998740SPaolo Bonzini ts->scale = scale; 3423db1ee7cSPaolo Bonzini ts->expire_time = -1; 343ff83c66eSAlex Bligh } 344ff83c66eSAlex Bligh 34540daca54SAlex Bligh void timer_free(QEMUTimer *ts) 346db1a4972SPaolo Bonzini { 3477267c094SAnthony Liguori g_free(ts); 348db1a4972SPaolo Bonzini } 349db1a4972SPaolo Bonzini 350978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) 351db1a4972SPaolo Bonzini { 352db1a4972SPaolo Bonzini QEMUTimer **pt, *t; 353db1a4972SPaolo Bonzini 3543db1ee7cSPaolo Bonzini ts->expire_time = -1; 355978f2205SStefan Hajnoczi pt = &timer_list->active_timers; 356db1a4972SPaolo Bonzini for(;;) { 357db1a4972SPaolo Bonzini t = *pt; 358db1a4972SPaolo Bonzini if (!t) 359db1a4972SPaolo Bonzini break; 360db1a4972SPaolo Bonzini if (t == ts) { 361db1a4972SPaolo Bonzini *pt = t->next; 362db1a4972SPaolo Bonzini break; 363db1a4972SPaolo Bonzini } 364db1a4972SPaolo Bonzini pt = &t->next; 365db1a4972SPaolo Bonzini } 366db1a4972SPaolo Bonzini } 367db1a4972SPaolo Bonzini 3680f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list, 3690f809e5fSPaolo Bonzini QEMUTimer *ts, int64_t expire_time) 3700f809e5fSPaolo Bonzini { 3710f809e5fSPaolo Bonzini QEMUTimer **pt, *t; 3720f809e5fSPaolo Bonzini 3730f809e5fSPaolo Bonzini /* add the timer in the sorted list */ 3740f809e5fSPaolo Bonzini pt = &timer_list->active_timers; 3750f809e5fSPaolo Bonzini for (;;) { 3760f809e5fSPaolo Bonzini t = *pt; 3770f809e5fSPaolo Bonzini if (!timer_expired_ns(t, expire_time)) { 3780f809e5fSPaolo Bonzini break; 3790f809e5fSPaolo Bonzini } 3800f809e5fSPaolo Bonzini pt = &t->next; 3810f809e5fSPaolo Bonzini } 3820f809e5fSPaolo Bonzini ts->expire_time = MAX(expire_time, 0); 3830f809e5fSPaolo Bonzini ts->next = *pt; 3840f809e5fSPaolo Bonzini *pt = ts; 3850f809e5fSPaolo Bonzini 3860f809e5fSPaolo Bonzini return pt == &timer_list->active_timers; 3870f809e5fSPaolo Bonzini } 3880f809e5fSPaolo Bonzini 3890f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list) 3900f809e5fSPaolo Bonzini { 3910f809e5fSPaolo Bonzini /* Interrupt execution to force deadline recalculation. */ 3920f809e5fSPaolo Bonzini qemu_clock_warp(timer_list->clock->type); 3930f809e5fSPaolo Bonzini timerlist_notify(timer_list); 3940f809e5fSPaolo Bonzini } 3950f809e5fSPaolo Bonzini 396978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */ 397978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts) 398978f2205SStefan Hajnoczi { 399978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 400978f2205SStefan Hajnoczi 401978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 402978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 403978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 404978f2205SStefan Hajnoczi } 405978f2205SStefan Hajnoczi 406db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 407db1a4972SPaolo Bonzini >= expire_time. The corresponding callback will be called. */ 40840daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) 409db1a4972SPaolo Bonzini { 410978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 4110f809e5fSPaolo Bonzini bool rearm; 412db1a4972SPaolo Bonzini 413978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 414978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 4150f809e5fSPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 416978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 417db1a4972SPaolo Bonzini 4180f809e5fSPaolo Bonzini if (rearm) { 4190f809e5fSPaolo Bonzini timerlist_rearm(timer_list); 420db1a4972SPaolo Bonzini } 421db1a4972SPaolo Bonzini } 422db1a4972SPaolo Bonzini 423add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 424add40e97SPaolo Bonzini >= expire_time or the current deadline, whichever comes earlier. 425add40e97SPaolo Bonzini The corresponding callback will be called. */ 426add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) 427add40e97SPaolo Bonzini { 428add40e97SPaolo Bonzini QEMUTimerList *timer_list = ts->timer_list; 429add40e97SPaolo Bonzini bool rearm; 430add40e97SPaolo Bonzini 431add40e97SPaolo Bonzini qemu_mutex_lock(&timer_list->active_timers_lock); 432add40e97SPaolo Bonzini if (ts->expire_time == -1 || ts->expire_time > expire_time) { 433add40e97SPaolo Bonzini if (ts->expire_time != -1) { 434add40e97SPaolo Bonzini timer_del_locked(timer_list, ts); 435add40e97SPaolo Bonzini } 436add40e97SPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 437add40e97SPaolo Bonzini } else { 438add40e97SPaolo Bonzini rearm = false; 439add40e97SPaolo Bonzini } 440add40e97SPaolo Bonzini qemu_mutex_unlock(&timer_list->active_timers_lock); 441add40e97SPaolo Bonzini 442add40e97SPaolo Bonzini if (rearm) { 443add40e97SPaolo Bonzini timerlist_rearm(timer_list); 444add40e97SPaolo Bonzini } 445add40e97SPaolo Bonzini } 446add40e97SPaolo Bonzini 44740daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time) 4484a998740SPaolo Bonzini { 44940daca54SAlex Bligh timer_mod_ns(ts, expire_time * ts->scale); 4504a998740SPaolo Bonzini } 4514a998740SPaolo Bonzini 452add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) 453add40e97SPaolo Bonzini { 454add40e97SPaolo Bonzini timer_mod_anticipate_ns(ts, expire_time * ts->scale); 455add40e97SPaolo Bonzini } 456add40e97SPaolo Bonzini 457e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts) 458db1a4972SPaolo Bonzini { 4593db1ee7cSPaolo Bonzini return ts->expire_time >= 0; 460db1a4972SPaolo Bonzini } 461db1a4972SPaolo Bonzini 462e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time) 463db1a4972SPaolo Bonzini { 464e93379b0SAlex Bligh return timer_expired_ns(timer_head, current_time * timer_head->scale); 465db1a4972SPaolo Bonzini } 466db1a4972SPaolo Bonzini 467ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list) 468db1a4972SPaolo Bonzini { 469144b97c2SPaolo Bonzini QEMUTimer *ts; 470db1a4972SPaolo Bonzini int64_t current_time; 471f9a976b7SAlex Bligh bool progress = false; 472978f2205SStefan Hajnoczi QEMUTimerCB *cb; 473978f2205SStefan Hajnoczi void *opaque; 474db1a4972SPaolo Bonzini 4753c053411SLiu Ping Fan qemu_event_reset(&timer_list->timers_done_ev); 476ff83c66eSAlex Bligh if (!timer_list->clock->enabled) { 4773c053411SLiu Ping Fan goto out; 478ff83c66eSAlex Bligh } 479db1a4972SPaolo Bonzini 48040daca54SAlex Bligh current_time = qemu_clock_get_ns(timer_list->clock->type); 481db1a4972SPaolo Bonzini for(;;) { 482978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 483ff83c66eSAlex Bligh ts = timer_list->active_timers; 484e93379b0SAlex Bligh if (!timer_expired_ns(ts, current_time)) { 485978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 486db1a4972SPaolo Bonzini break; 48745c7b37fSStefan Weil } 488978f2205SStefan Hajnoczi 489db1a4972SPaolo Bonzini /* remove timer from the list before calling the callback */ 490ff83c66eSAlex Bligh timer_list->active_timers = ts->next; 491db1a4972SPaolo Bonzini ts->next = NULL; 4923db1ee7cSPaolo Bonzini ts->expire_time = -1; 493978f2205SStefan Hajnoczi cb = ts->cb; 494978f2205SStefan Hajnoczi opaque = ts->opaque; 495978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 496db1a4972SPaolo Bonzini 497db1a4972SPaolo Bonzini /* run the callback (the timer list can be modified) */ 498978f2205SStefan Hajnoczi cb(opaque); 499f9a976b7SAlex Bligh progress = true; 500db1a4972SPaolo Bonzini } 5013c053411SLiu Ping Fan 5023c053411SLiu Ping Fan out: 5033c053411SLiu Ping Fan qemu_event_set(&timer_list->timers_done_ev); 504f9a976b7SAlex Bligh return progress; 505db1a4972SPaolo Bonzini } 506db1a4972SPaolo Bonzini 50740daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type) 50840daca54SAlex Bligh { 5097bf8fbdeSAlex Bligh return timerlist_run_timers(main_loop_tlg.tl[type]); 51040daca54SAlex Bligh } 51140daca54SAlex Bligh 512d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg, 513d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, void *opaque) 514754d6a54SAlex Bligh { 515754d6a54SAlex Bligh QEMUClockType type; 516754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 517d5541d86SAlex Bligh tlg->tl[type] = timerlist_new(type, cb, opaque); 518754d6a54SAlex Bligh } 519754d6a54SAlex Bligh } 520754d6a54SAlex Bligh 521754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg) 522754d6a54SAlex Bligh { 523754d6a54SAlex Bligh QEMUClockType type; 524754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 525754d6a54SAlex Bligh timerlist_free(tlg->tl[type]); 526754d6a54SAlex Bligh } 527754d6a54SAlex Bligh } 528754d6a54SAlex Bligh 529754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 530754d6a54SAlex Bligh { 531754d6a54SAlex Bligh QEMUClockType type; 532754d6a54SAlex Bligh bool progress = false; 533754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 534754d6a54SAlex Bligh progress |= timerlist_run_timers(tlg->tl[type]); 535754d6a54SAlex Bligh } 536754d6a54SAlex Bligh return progress; 537754d6a54SAlex Bligh } 538754d6a54SAlex Bligh 539754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 540754d6a54SAlex Bligh { 541754d6a54SAlex Bligh int64_t deadline = -1; 542754d6a54SAlex Bligh QEMUClockType type; 543754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 54440daca54SAlex Bligh if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) { 545754d6a54SAlex Bligh deadline = qemu_soonest_timeout(deadline, 546754d6a54SAlex Bligh timerlist_deadline_ns( 547754d6a54SAlex Bligh tlg->tl[type])); 548754d6a54SAlex Bligh } 549754d6a54SAlex Bligh } 550754d6a54SAlex Bligh return deadline; 551754d6a54SAlex Bligh } 552754d6a54SAlex Bligh 55340daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type) 554db1a4972SPaolo Bonzini { 555691a0c9cSJan Kiszka int64_t now, last; 55640daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 557691a0c9cSJan Kiszka 55840daca54SAlex Bligh switch (type) { 559db1a4972SPaolo Bonzini case QEMU_CLOCK_REALTIME: 560db1a4972SPaolo Bonzini return get_clock(); 561db1a4972SPaolo Bonzini default: 562db1a4972SPaolo Bonzini case QEMU_CLOCK_VIRTUAL: 563db1a4972SPaolo Bonzini if (use_icount) { 564db1a4972SPaolo Bonzini return cpu_get_icount(); 565db1a4972SPaolo Bonzini } else { 566db1a4972SPaolo Bonzini return cpu_get_clock(); 567db1a4972SPaolo Bonzini } 568db1a4972SPaolo Bonzini case QEMU_CLOCK_HOST: 569691a0c9cSJan Kiszka now = get_clock_realtime(); 570691a0c9cSJan Kiszka last = clock->last; 571691a0c9cSJan Kiszka clock->last = now; 572691a0c9cSJan Kiszka if (now < last) { 573691a0c9cSJan Kiszka notifier_list_notify(&clock->reset_notifiers, &now); 574db1a4972SPaolo Bonzini } 575691a0c9cSJan Kiszka return now; 576691a0c9cSJan Kiszka } 577691a0c9cSJan Kiszka } 578691a0c9cSJan Kiszka 57940daca54SAlex Bligh void qemu_clock_register_reset_notifier(QEMUClockType type, 58040daca54SAlex Bligh Notifier *notifier) 58140daca54SAlex Bligh { 58240daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 583691a0c9cSJan Kiszka notifier_list_add(&clock->reset_notifiers, notifier); 584691a0c9cSJan Kiszka } 585691a0c9cSJan Kiszka 58640daca54SAlex Bligh void qemu_clock_unregister_reset_notifier(QEMUClockType type, 58740daca54SAlex Bligh Notifier *notifier) 588691a0c9cSJan Kiszka { 58931552529SPaolo Bonzini notifier_remove(notifier); 590db1a4972SPaolo Bonzini } 591db1a4972SPaolo Bonzini 592db1a4972SPaolo Bonzini void init_clocks(void) 593db1a4972SPaolo Bonzini { 594ff83c66eSAlex Bligh QEMUClockType type; 595ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 5967bf8fbdeSAlex Bligh qemu_clock_init(type); 597ff83c66eSAlex Bligh } 598ff83c66eSAlex Bligh 599cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 600cd758dd0SAlex Bligh prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 601cd758dd0SAlex Bligh #endif 602744ca8e3SPaolo Bonzini } 603db1a4972SPaolo Bonzini 604e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts) 605db1a4972SPaolo Bonzini { 606e93379b0SAlex Bligh return timer_pending(ts) ? ts->expire_time : -1; 607db1a4972SPaolo Bonzini } 608db1a4972SPaolo Bonzini 60940daca54SAlex Bligh bool qemu_clock_run_all_timers(void) 610db1a4972SPaolo Bonzini { 611f9a976b7SAlex Bligh bool progress = false; 612ff83c66eSAlex Bligh QEMUClockType type; 6136d327171SAlex Bligh 614ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 61540daca54SAlex Bligh progress |= qemu_clock_run_timers(type); 616ff83c66eSAlex Bligh } 617158fd3ceSPeter Portante 618f9a976b7SAlex Bligh return progress; 619db1a4972SPaolo Bonzini } 620