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 251ac0206bSPeter Maydell #include "qemu/main-loop.h" 261de7afc9SPaolo Bonzini #include "qemu/timer.h" 271ac0206bSPeter Maydell 2830ea8339SAnthony Liguori #ifdef CONFIG_POSIX 2930ea8339SAnthony Liguori #include <pthread.h> 3030ea8339SAnthony Liguori #endif 31bff9f8bfSStefan Weil 324e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 334e0c6529SAlex Bligh #include <poll.h> 344e0c6529SAlex Bligh #endif 354e0c6529SAlex Bligh 36cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 37cd758dd0SAlex Bligh #include <sys/prctl.h> 38cd758dd0SAlex Bligh #endif 39cd758dd0SAlex Bligh 40db1a4972SPaolo Bonzini /***********************************************************/ 41db1a4972SPaolo Bonzini /* timers */ 42db1a4972SPaolo Bonzini 43b4049b74SAlex Bligh typedef struct QEMUClock { 443c053411SLiu Ping Fan /* We rely on BQL to protect the timerlists */ 45ff83c66eSAlex Bligh QLIST_HEAD(, QEMUTimerList) timerlists; 46691a0c9cSJan Kiszka 47691a0c9cSJan Kiszka NotifierList reset_notifiers; 48691a0c9cSJan Kiszka int64_t last; 499a14b298SStefan Weil 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)); 102*e4efd8a4SPaolo 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 1217bf8fbdeSAlex Bligh static void qemu_clock_init(QEMUClockType type) 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; 1295e1ec7b2SStefan Weil clock->enabled = true; 1302ff68d07SPaolo Bonzini clock->last = INT64_MIN; 131ff83c66eSAlex Bligh QLIST_INIT(&clock->timerlists); 132691a0c9cSJan Kiszka notifier_list_init(&clock->reset_notifiers); 1337bf8fbdeSAlex Bligh main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); 134db1a4972SPaolo Bonzini } 135db1a4972SPaolo Bonzini 13640daca54SAlex Bligh bool qemu_clock_use_for_deadline(QEMUClockType type) 137ff83c66eSAlex Bligh { 13840daca54SAlex Bligh return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); 139ff83c66eSAlex Bligh } 140ff83c66eSAlex Bligh 14140daca54SAlex Bligh void qemu_clock_notify(QEMUClockType type) 142b1bbfe72SAlex Bligh { 143b1bbfe72SAlex Bligh QEMUTimerList *timer_list; 14440daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 145b1bbfe72SAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 146b1bbfe72SAlex Bligh timerlist_notify(timer_list); 147b1bbfe72SAlex Bligh } 148b1bbfe72SAlex Bligh } 149b1bbfe72SAlex Bligh 1503c053411SLiu Ping Fan /* Disabling the clock will wait for related timerlists to stop 1513c053411SLiu Ping Fan * executing qemu_run_timers. Thus, this functions should not 1523c053411SLiu Ping Fan * be used from the callback of a timer that is based on @clock. 1533c053411SLiu Ping Fan * Doing so would cause a deadlock. 1543c053411SLiu Ping Fan * 1553c053411SLiu Ping Fan * Caller should hold BQL. 1563c053411SLiu Ping Fan */ 15740daca54SAlex Bligh void qemu_clock_enable(QEMUClockType type, bool enabled) 158db1a4972SPaolo Bonzini { 15940daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 1603c053411SLiu Ping Fan QEMUTimerList *tl; 161fbdc14ebSPaolo Bonzini bool old = clock->enabled; 162db1a4972SPaolo Bonzini clock->enabled = enabled; 163fbdc14ebSPaolo Bonzini if (enabled && !old) { 16440daca54SAlex Bligh qemu_clock_notify(type); 1653c053411SLiu Ping Fan } else if (!enabled && old) { 1663c053411SLiu Ping Fan QLIST_FOREACH(tl, &clock->timerlists, list) { 1673c053411SLiu Ping Fan qemu_event_wait(&tl->timers_done_ev); 1683c053411SLiu Ping Fan } 169fbdc14ebSPaolo Bonzini } 170db1a4972SPaolo Bonzini } 171db1a4972SPaolo Bonzini 172ff83c66eSAlex Bligh bool timerlist_has_timers(QEMUTimerList *timer_list) 173dc2dfcf0SPaolo Bonzini { 174ff83c66eSAlex Bligh return !!timer_list->active_timers; 175dc2dfcf0SPaolo Bonzini } 176dc2dfcf0SPaolo Bonzini 17740daca54SAlex Bligh bool qemu_clock_has_timers(QEMUClockType type) 178dc2dfcf0SPaolo Bonzini { 17940daca54SAlex Bligh return timerlist_has_timers( 1807bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 181dc2dfcf0SPaolo Bonzini } 182dc2dfcf0SPaolo Bonzini 183ff83c66eSAlex Bligh bool timerlist_expired(QEMUTimerList *timer_list) 184ff83c66eSAlex Bligh { 185978f2205SStefan Hajnoczi int64_t expire_time; 186978f2205SStefan Hajnoczi 187978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 188978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 189978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 190978f2205SStefan Hajnoczi return false; 191978f2205SStefan Hajnoczi } 192978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 193978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 194978f2205SStefan Hajnoczi 195978f2205SStefan Hajnoczi return expire_time < qemu_clock_get_ns(timer_list->clock->type); 196ff83c66eSAlex Bligh } 197ff83c66eSAlex Bligh 19840daca54SAlex Bligh bool qemu_clock_expired(QEMUClockType type) 199ff83c66eSAlex Bligh { 20040daca54SAlex Bligh return timerlist_expired( 2017bf8fbdeSAlex Bligh main_loop_tlg.tl[type]); 202ff83c66eSAlex Bligh } 203ff83c66eSAlex Bligh 20402a03a9fSAlex Bligh /* 20502a03a9fSAlex Bligh * As above, but return -1 for no deadline, and do not cap to 2^32 20602a03a9fSAlex Bligh * as we know the result is always positive. 20702a03a9fSAlex Bligh */ 20802a03a9fSAlex Bligh 209ff83c66eSAlex Bligh int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) 21002a03a9fSAlex Bligh { 21102a03a9fSAlex Bligh int64_t delta; 212978f2205SStefan Hajnoczi int64_t expire_time; 21302a03a9fSAlex Bligh 214978f2205SStefan Hajnoczi if (!timer_list->clock->enabled) { 21502a03a9fSAlex Bligh return -1; 21602a03a9fSAlex Bligh } 21702a03a9fSAlex Bligh 218978f2205SStefan Hajnoczi /* The active timers list may be modified before the caller uses our return 219978f2205SStefan Hajnoczi * value but ->notify_cb() is called when the deadline changes. Therefore 220978f2205SStefan Hajnoczi * the caller should notice the change and there is no race condition. 221978f2205SStefan Hajnoczi */ 222978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 223978f2205SStefan Hajnoczi if (!timer_list->active_timers) { 224978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 225978f2205SStefan Hajnoczi return -1; 226978f2205SStefan Hajnoczi } 227978f2205SStefan Hajnoczi expire_time = timer_list->active_timers->expire_time; 228978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 229978f2205SStefan Hajnoczi 230978f2205SStefan Hajnoczi delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 23102a03a9fSAlex Bligh 23202a03a9fSAlex Bligh if (delta <= 0) { 23302a03a9fSAlex Bligh return 0; 23402a03a9fSAlex Bligh } 23502a03a9fSAlex Bligh 23602a03a9fSAlex Bligh return delta; 23702a03a9fSAlex Bligh } 23802a03a9fSAlex Bligh 239ac70aafcSAlex Bligh /* Calculate the soonest deadline across all timerlists attached 240ac70aafcSAlex Bligh * to the clock. This is used for the icount timeout so we 241ac70aafcSAlex Bligh * ignore whether or not the clock should be used in deadline 242ac70aafcSAlex Bligh * calculations. 243ac70aafcSAlex Bligh */ 24440daca54SAlex Bligh int64_t qemu_clock_deadline_ns_all(QEMUClockType type) 245ac70aafcSAlex Bligh { 246ac70aafcSAlex Bligh int64_t deadline = -1; 247ac70aafcSAlex Bligh QEMUTimerList *timer_list; 24840daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 249ac70aafcSAlex Bligh QLIST_FOREACH(timer_list, &clock->timerlists, list) { 250ac70aafcSAlex Bligh deadline = qemu_soonest_timeout(deadline, 251ac70aafcSAlex Bligh timerlist_deadline_ns(timer_list)); 252ac70aafcSAlex Bligh } 253ac70aafcSAlex Bligh return deadline; 254ac70aafcSAlex Bligh } 255ac70aafcSAlex Bligh 25640daca54SAlex Bligh QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) 257ff83c66eSAlex Bligh { 25840daca54SAlex Bligh return timer_list->clock->type; 259ff83c66eSAlex Bligh } 260ff83c66eSAlex Bligh 26140daca54SAlex Bligh QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) 262ff83c66eSAlex Bligh { 2637bf8fbdeSAlex Bligh return main_loop_tlg.tl[type]; 264ff83c66eSAlex Bligh } 265ff83c66eSAlex Bligh 266d5541d86SAlex Bligh void timerlist_notify(QEMUTimerList *timer_list) 267d5541d86SAlex Bligh { 268d5541d86SAlex Bligh if (timer_list->notify_cb) { 269d5541d86SAlex Bligh timer_list->notify_cb(timer_list->notify_opaque); 270d5541d86SAlex Bligh } else { 271d5541d86SAlex Bligh qemu_notify_event(); 272d5541d86SAlex Bligh } 273d5541d86SAlex Bligh } 274d5541d86SAlex Bligh 27502a03a9fSAlex Bligh /* Transition function to convert a nanosecond timeout to ms 27602a03a9fSAlex Bligh * This is used where a system does not support ppoll 27702a03a9fSAlex Bligh */ 27802a03a9fSAlex Bligh int qemu_timeout_ns_to_ms(int64_t ns) 27902a03a9fSAlex Bligh { 28002a03a9fSAlex Bligh int64_t ms; 28102a03a9fSAlex Bligh if (ns < 0) { 28202a03a9fSAlex Bligh return -1; 28302a03a9fSAlex Bligh } 28402a03a9fSAlex Bligh 28502a03a9fSAlex Bligh if (!ns) { 28602a03a9fSAlex Bligh return 0; 28702a03a9fSAlex Bligh } 28802a03a9fSAlex Bligh 28902a03a9fSAlex Bligh /* Always round up, because it's better to wait too long than to wait too 29002a03a9fSAlex Bligh * little and effectively busy-wait 29102a03a9fSAlex Bligh */ 29202a03a9fSAlex Bligh ms = (ns + SCALE_MS - 1) / SCALE_MS; 29302a03a9fSAlex Bligh 29402a03a9fSAlex Bligh /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ 29502a03a9fSAlex Bligh if (ms > (int64_t) INT32_MAX) { 29602a03a9fSAlex Bligh ms = INT32_MAX; 29702a03a9fSAlex Bligh } 29802a03a9fSAlex Bligh 29902a03a9fSAlex Bligh return (int) ms; 30002a03a9fSAlex Bligh } 30102a03a9fSAlex Bligh 30202a03a9fSAlex Bligh 3034e0c6529SAlex Bligh /* qemu implementation of g_poll which uses a nanosecond timeout but is 3044e0c6529SAlex Bligh * otherwise identical to g_poll 3054e0c6529SAlex Bligh */ 3064e0c6529SAlex Bligh int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) 3074e0c6529SAlex Bligh { 3084e0c6529SAlex Bligh #ifdef CONFIG_PPOLL 3094e0c6529SAlex Bligh if (timeout < 0) { 3104e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, NULL, NULL); 3114e0c6529SAlex Bligh } else { 3124e0c6529SAlex Bligh struct timespec ts; 313490309fcSPeter Maydell int64_t tvsec = timeout / 1000000000LL; 314490309fcSPeter Maydell /* Avoid possibly overflowing and specifying a negative number of 315490309fcSPeter Maydell * seconds, which would turn a very long timeout into a busy-wait. 316490309fcSPeter Maydell */ 317490309fcSPeter Maydell if (tvsec > (int64_t)INT32_MAX) { 318490309fcSPeter Maydell tvsec = INT32_MAX; 319490309fcSPeter Maydell } 320490309fcSPeter Maydell ts.tv_sec = tvsec; 3214e0c6529SAlex Bligh ts.tv_nsec = timeout % 1000000000LL; 3224e0c6529SAlex Bligh return ppoll((struct pollfd *)fds, nfds, &ts, NULL); 3234e0c6529SAlex Bligh } 3244e0c6529SAlex Bligh #else 3254e0c6529SAlex Bligh return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); 3264e0c6529SAlex Bligh #endif 3274e0c6529SAlex Bligh } 3284e0c6529SAlex Bligh 3294e0c6529SAlex Bligh 330f186aa97SPaolo Bonzini void timer_init_tl(QEMUTimer *ts, 331ff83c66eSAlex Bligh QEMUTimerList *timer_list, int scale, 3324a998740SPaolo Bonzini QEMUTimerCB *cb, void *opaque) 333db1a4972SPaolo Bonzini { 334ff83c66eSAlex Bligh ts->timer_list = timer_list; 335db1a4972SPaolo Bonzini ts->cb = cb; 336db1a4972SPaolo Bonzini ts->opaque = opaque; 3374a998740SPaolo Bonzini ts->scale = scale; 3383db1ee7cSPaolo Bonzini ts->expire_time = -1; 339ff83c66eSAlex Bligh } 340ff83c66eSAlex Bligh 341cd1bd53aSPaolo Bonzini void timer_deinit(QEMUTimer *ts) 342cd1bd53aSPaolo Bonzini { 343cd1bd53aSPaolo Bonzini assert(ts->expire_time == -1); 344cd1bd53aSPaolo Bonzini ts->timer_list = NULL; 345cd1bd53aSPaolo Bonzini } 346cd1bd53aSPaolo Bonzini 34740daca54SAlex Bligh void timer_free(QEMUTimer *ts) 348db1a4972SPaolo Bonzini { 3497267c094SAnthony Liguori g_free(ts); 350db1a4972SPaolo Bonzini } 351db1a4972SPaolo Bonzini 352978f2205SStefan Hajnoczi static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) 353db1a4972SPaolo Bonzini { 354db1a4972SPaolo Bonzini QEMUTimer **pt, *t; 355db1a4972SPaolo Bonzini 3563db1ee7cSPaolo Bonzini ts->expire_time = -1; 357978f2205SStefan Hajnoczi pt = &timer_list->active_timers; 358db1a4972SPaolo Bonzini for(;;) { 359db1a4972SPaolo Bonzini t = *pt; 360db1a4972SPaolo Bonzini if (!t) 361db1a4972SPaolo Bonzini break; 362db1a4972SPaolo Bonzini if (t == ts) { 363db1a4972SPaolo Bonzini *pt = t->next; 364db1a4972SPaolo Bonzini break; 365db1a4972SPaolo Bonzini } 366db1a4972SPaolo Bonzini pt = &t->next; 367db1a4972SPaolo Bonzini } 368db1a4972SPaolo Bonzini } 369db1a4972SPaolo Bonzini 3700f809e5fSPaolo Bonzini static bool timer_mod_ns_locked(QEMUTimerList *timer_list, 3710f809e5fSPaolo Bonzini QEMUTimer *ts, int64_t expire_time) 3720f809e5fSPaolo Bonzini { 3730f809e5fSPaolo Bonzini QEMUTimer **pt, *t; 3740f809e5fSPaolo Bonzini 3750f809e5fSPaolo Bonzini /* add the timer in the sorted list */ 3760f809e5fSPaolo Bonzini pt = &timer_list->active_timers; 3770f809e5fSPaolo Bonzini for (;;) { 3780f809e5fSPaolo Bonzini t = *pt; 3790f809e5fSPaolo Bonzini if (!timer_expired_ns(t, expire_time)) { 3800f809e5fSPaolo Bonzini break; 3810f809e5fSPaolo Bonzini } 3820f809e5fSPaolo Bonzini pt = &t->next; 3830f809e5fSPaolo Bonzini } 3840f809e5fSPaolo Bonzini ts->expire_time = MAX(expire_time, 0); 3850f809e5fSPaolo Bonzini ts->next = *pt; 3860f809e5fSPaolo Bonzini *pt = ts; 3870f809e5fSPaolo Bonzini 3880f809e5fSPaolo Bonzini return pt == &timer_list->active_timers; 3890f809e5fSPaolo Bonzini } 3900f809e5fSPaolo Bonzini 3910f809e5fSPaolo Bonzini static void timerlist_rearm(QEMUTimerList *timer_list) 3920f809e5fSPaolo Bonzini { 3930f809e5fSPaolo Bonzini /* Interrupt execution to force deadline recalculation. */ 3940f809e5fSPaolo Bonzini qemu_clock_warp(timer_list->clock->type); 3950f809e5fSPaolo Bonzini timerlist_notify(timer_list); 3960f809e5fSPaolo Bonzini } 3970f809e5fSPaolo Bonzini 398978f2205SStefan Hajnoczi /* stop a timer, but do not dealloc it */ 399978f2205SStefan Hajnoczi void timer_del(QEMUTimer *ts) 400978f2205SStefan Hajnoczi { 401978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 402978f2205SStefan Hajnoczi 403cd1bd53aSPaolo Bonzini if (timer_list) { 404978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 405978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 406978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 407978f2205SStefan Hajnoczi } 408cd1bd53aSPaolo Bonzini } 409978f2205SStefan Hajnoczi 410db1a4972SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 411db1a4972SPaolo Bonzini >= expire_time. The corresponding callback will be called. */ 41240daca54SAlex Bligh void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) 413db1a4972SPaolo Bonzini { 414978f2205SStefan Hajnoczi QEMUTimerList *timer_list = ts->timer_list; 4150f809e5fSPaolo Bonzini bool rearm; 416db1a4972SPaolo Bonzini 417978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 418978f2205SStefan Hajnoczi timer_del_locked(timer_list, ts); 4190f809e5fSPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 420978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 421db1a4972SPaolo Bonzini 4220f809e5fSPaolo Bonzini if (rearm) { 4230f809e5fSPaolo Bonzini timerlist_rearm(timer_list); 424db1a4972SPaolo Bonzini } 425db1a4972SPaolo Bonzini } 426db1a4972SPaolo Bonzini 427add40e97SPaolo Bonzini /* modify the current timer so that it will be fired when current_time 428add40e97SPaolo Bonzini >= expire_time or the current deadline, whichever comes earlier. 429add40e97SPaolo Bonzini The corresponding callback will be called. */ 430add40e97SPaolo Bonzini void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) 431add40e97SPaolo Bonzini { 432add40e97SPaolo Bonzini QEMUTimerList *timer_list = ts->timer_list; 433add40e97SPaolo Bonzini bool rearm; 434add40e97SPaolo Bonzini 435add40e97SPaolo Bonzini qemu_mutex_lock(&timer_list->active_timers_lock); 436add40e97SPaolo Bonzini if (ts->expire_time == -1 || ts->expire_time > expire_time) { 437add40e97SPaolo Bonzini if (ts->expire_time != -1) { 438add40e97SPaolo Bonzini timer_del_locked(timer_list, ts); 439add40e97SPaolo Bonzini } 440add40e97SPaolo Bonzini rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 441add40e97SPaolo Bonzini } else { 442add40e97SPaolo Bonzini rearm = false; 443add40e97SPaolo Bonzini } 444add40e97SPaolo Bonzini qemu_mutex_unlock(&timer_list->active_timers_lock); 445add40e97SPaolo Bonzini 446add40e97SPaolo Bonzini if (rearm) { 447add40e97SPaolo Bonzini timerlist_rearm(timer_list); 448add40e97SPaolo Bonzini } 449add40e97SPaolo Bonzini } 450add40e97SPaolo Bonzini 45140daca54SAlex Bligh void timer_mod(QEMUTimer *ts, int64_t expire_time) 4524a998740SPaolo Bonzini { 45340daca54SAlex Bligh timer_mod_ns(ts, expire_time * ts->scale); 4544a998740SPaolo Bonzini } 4554a998740SPaolo Bonzini 456add40e97SPaolo Bonzini void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) 457add40e97SPaolo Bonzini { 458add40e97SPaolo Bonzini timer_mod_anticipate_ns(ts, expire_time * ts->scale); 459add40e97SPaolo Bonzini } 460add40e97SPaolo Bonzini 461e93379b0SAlex Bligh bool timer_pending(QEMUTimer *ts) 462db1a4972SPaolo Bonzini { 4633db1ee7cSPaolo Bonzini return ts->expire_time >= 0; 464db1a4972SPaolo Bonzini } 465db1a4972SPaolo Bonzini 466e93379b0SAlex Bligh bool timer_expired(QEMUTimer *timer_head, int64_t current_time) 467db1a4972SPaolo Bonzini { 468e93379b0SAlex Bligh return timer_expired_ns(timer_head, current_time * timer_head->scale); 469db1a4972SPaolo Bonzini } 470db1a4972SPaolo Bonzini 471ff83c66eSAlex Bligh bool timerlist_run_timers(QEMUTimerList *timer_list) 472db1a4972SPaolo Bonzini { 473144b97c2SPaolo Bonzini QEMUTimer *ts; 474db1a4972SPaolo Bonzini int64_t current_time; 475f9a976b7SAlex Bligh bool progress = false; 476978f2205SStefan Hajnoczi QEMUTimerCB *cb; 477978f2205SStefan Hajnoczi void *opaque; 478db1a4972SPaolo Bonzini 4793c053411SLiu Ping Fan qemu_event_reset(&timer_list->timers_done_ev); 480ff83c66eSAlex Bligh if (!timer_list->clock->enabled) { 4813c053411SLiu Ping Fan goto out; 482ff83c66eSAlex Bligh } 483db1a4972SPaolo Bonzini 48440daca54SAlex Bligh current_time = qemu_clock_get_ns(timer_list->clock->type); 485db1a4972SPaolo Bonzini for(;;) { 486978f2205SStefan Hajnoczi qemu_mutex_lock(&timer_list->active_timers_lock); 487ff83c66eSAlex Bligh ts = timer_list->active_timers; 488e93379b0SAlex Bligh if (!timer_expired_ns(ts, current_time)) { 489978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 490db1a4972SPaolo Bonzini break; 49145c7b37fSStefan Weil } 492978f2205SStefan Hajnoczi 493db1a4972SPaolo Bonzini /* remove timer from the list before calling the callback */ 494ff83c66eSAlex Bligh timer_list->active_timers = ts->next; 495db1a4972SPaolo Bonzini ts->next = NULL; 4963db1ee7cSPaolo Bonzini ts->expire_time = -1; 497978f2205SStefan Hajnoczi cb = ts->cb; 498978f2205SStefan Hajnoczi opaque = ts->opaque; 499978f2205SStefan Hajnoczi qemu_mutex_unlock(&timer_list->active_timers_lock); 500db1a4972SPaolo Bonzini 501db1a4972SPaolo Bonzini /* run the callback (the timer list can be modified) */ 502978f2205SStefan Hajnoczi cb(opaque); 503f9a976b7SAlex Bligh progress = true; 504db1a4972SPaolo Bonzini } 5053c053411SLiu Ping Fan 5063c053411SLiu Ping Fan out: 5073c053411SLiu Ping Fan qemu_event_set(&timer_list->timers_done_ev); 508f9a976b7SAlex Bligh return progress; 509db1a4972SPaolo Bonzini } 510db1a4972SPaolo Bonzini 51140daca54SAlex Bligh bool qemu_clock_run_timers(QEMUClockType type) 51240daca54SAlex Bligh { 5137bf8fbdeSAlex Bligh return timerlist_run_timers(main_loop_tlg.tl[type]); 51440daca54SAlex Bligh } 51540daca54SAlex Bligh 516d5541d86SAlex Bligh void timerlistgroup_init(QEMUTimerListGroup *tlg, 517d5541d86SAlex Bligh QEMUTimerListNotifyCB *cb, void *opaque) 518754d6a54SAlex Bligh { 519754d6a54SAlex Bligh QEMUClockType type; 520754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 521d5541d86SAlex Bligh tlg->tl[type] = timerlist_new(type, cb, opaque); 522754d6a54SAlex Bligh } 523754d6a54SAlex Bligh } 524754d6a54SAlex Bligh 525754d6a54SAlex Bligh void timerlistgroup_deinit(QEMUTimerListGroup *tlg) 526754d6a54SAlex Bligh { 527754d6a54SAlex Bligh QEMUClockType type; 528754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 529754d6a54SAlex Bligh timerlist_free(tlg->tl[type]); 530754d6a54SAlex Bligh } 531754d6a54SAlex Bligh } 532754d6a54SAlex Bligh 533754d6a54SAlex Bligh bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 534754d6a54SAlex Bligh { 535754d6a54SAlex Bligh QEMUClockType type; 536754d6a54SAlex Bligh bool progress = false; 537754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 538754d6a54SAlex Bligh progress |= timerlist_run_timers(tlg->tl[type]); 539754d6a54SAlex Bligh } 540754d6a54SAlex Bligh return progress; 541754d6a54SAlex Bligh } 542754d6a54SAlex Bligh 543754d6a54SAlex Bligh int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 544754d6a54SAlex Bligh { 545754d6a54SAlex Bligh int64_t deadline = -1; 546754d6a54SAlex Bligh QEMUClockType type; 547754d6a54SAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 54840daca54SAlex Bligh if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) { 549754d6a54SAlex Bligh deadline = qemu_soonest_timeout(deadline, 550754d6a54SAlex Bligh timerlist_deadline_ns( 551754d6a54SAlex Bligh tlg->tl[type])); 552754d6a54SAlex Bligh } 553754d6a54SAlex Bligh } 554754d6a54SAlex Bligh return deadline; 555754d6a54SAlex Bligh } 556754d6a54SAlex Bligh 55740daca54SAlex Bligh int64_t qemu_clock_get_ns(QEMUClockType type) 558db1a4972SPaolo Bonzini { 559691a0c9cSJan Kiszka int64_t now, last; 56040daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 561691a0c9cSJan Kiszka 56240daca54SAlex Bligh switch (type) { 563db1a4972SPaolo Bonzini case QEMU_CLOCK_REALTIME: 564db1a4972SPaolo Bonzini return get_clock(); 565db1a4972SPaolo Bonzini default: 566db1a4972SPaolo Bonzini case QEMU_CLOCK_VIRTUAL: 567db1a4972SPaolo Bonzini if (use_icount) { 568db1a4972SPaolo Bonzini return cpu_get_icount(); 569db1a4972SPaolo Bonzini } else { 570db1a4972SPaolo Bonzini return cpu_get_clock(); 571db1a4972SPaolo Bonzini } 572db1a4972SPaolo Bonzini case QEMU_CLOCK_HOST: 573691a0c9cSJan Kiszka now = get_clock_realtime(); 574691a0c9cSJan Kiszka last = clock->last; 575691a0c9cSJan Kiszka clock->last = now; 576fb1a3a05SPaul Donohue if (now < last || now > (last + get_max_clock_jump())) { 577691a0c9cSJan Kiszka notifier_list_notify(&clock->reset_notifiers, &now); 578db1a4972SPaolo Bonzini } 579691a0c9cSJan Kiszka return now; 5804e7fa73eSPavel Dovgalyuk case QEMU_CLOCK_VIRTUAL_RT: 5814e7fa73eSPavel Dovgalyuk return cpu_get_clock(); 582691a0c9cSJan Kiszka } 583691a0c9cSJan Kiszka } 584691a0c9cSJan Kiszka 58540daca54SAlex Bligh void qemu_clock_register_reset_notifier(QEMUClockType type, 58640daca54SAlex Bligh Notifier *notifier) 58740daca54SAlex Bligh { 58840daca54SAlex Bligh QEMUClock *clock = qemu_clock_ptr(type); 589691a0c9cSJan Kiszka notifier_list_add(&clock->reset_notifiers, notifier); 590691a0c9cSJan Kiszka } 591691a0c9cSJan Kiszka 59240daca54SAlex Bligh void qemu_clock_unregister_reset_notifier(QEMUClockType type, 59340daca54SAlex Bligh Notifier *notifier) 594691a0c9cSJan Kiszka { 59531552529SPaolo Bonzini notifier_remove(notifier); 596db1a4972SPaolo Bonzini } 597db1a4972SPaolo Bonzini 598db1a4972SPaolo Bonzini void init_clocks(void) 599db1a4972SPaolo Bonzini { 600ff83c66eSAlex Bligh QEMUClockType type; 601ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 6027bf8fbdeSAlex Bligh qemu_clock_init(type); 603ff83c66eSAlex Bligh } 604ff83c66eSAlex Bligh 605cd758dd0SAlex Bligh #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 606cd758dd0SAlex Bligh prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 607cd758dd0SAlex Bligh #endif 608744ca8e3SPaolo Bonzini } 609db1a4972SPaolo Bonzini 610e93379b0SAlex Bligh uint64_t timer_expire_time_ns(QEMUTimer *ts) 611db1a4972SPaolo Bonzini { 612e93379b0SAlex Bligh return timer_pending(ts) ? ts->expire_time : -1; 613db1a4972SPaolo Bonzini } 614db1a4972SPaolo Bonzini 61540daca54SAlex Bligh bool qemu_clock_run_all_timers(void) 616db1a4972SPaolo Bonzini { 617f9a976b7SAlex Bligh bool progress = false; 618ff83c66eSAlex Bligh QEMUClockType type; 6196d327171SAlex Bligh 620ff83c66eSAlex Bligh for (type = 0; type < QEMU_CLOCK_MAX; type++) { 62140daca54SAlex Bligh progress |= qemu_clock_run_timers(type); 622ff83c66eSAlex Bligh } 623158fd3ceSPeter Portante 624f9a976b7SAlex Bligh return progress; 625db1a4972SPaolo Bonzini } 626