16a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner/* 26a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * QEMU System Emulator 36a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * 46a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * Copyright (c) 2003-2008 Fabrice Bellard 56a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * 66a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * Permission is hereby granted, free of charge, to any person obtaining a copy 76a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * of this software and associated documentation files (the "Software"), to deal 86a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * in the Software without restriction, including without limitation the rights 96a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 106a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * copies of the Software, and to permit persons to whom the Software is 116a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * furnished to do so, subject to the following conditions: 126a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * 136a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * The above copyright notice and this permission notice shall be included in 146a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * all copies or substantial portions of the Software. 156a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * 166a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 176a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 186a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 196a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 206a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 216a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 226a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner * THE SOFTWARE. 236a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner */ 246a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 2534c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h" 266af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h" 271c31e3e43ce4cca85a707dfff631e5e102fdecedDavid 'Digit' Turner#include "ui/console.h" 286a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 296a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner#include "hw/hw.h" 306a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 31dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#include "qemu/thread.h" 32dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#include "qemu/timer.h" 33dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifdef CONFIG_POSIX 34dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#include <pthread.h> 356a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner#endif 366a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 37dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifdef CONFIG_PPOLL 38dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#include <poll.h> 39dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#endif 40dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 41dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 42dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#include <sys/prctl.h> 43dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#endif 446a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 456a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner/***********************************************************/ 466a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner/* timers */ 476a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 48dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnertypedef struct QEMUClock { 49dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* We rely on BQL to protect the timerlists */ 50dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_HEAD(, QEMUTimerList) timerlists; 51317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 52dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner NotifierList reset_notifiers; 53dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t last; 546a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 55dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 56dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool enabled; 57dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} QEMUClock; 58dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 59dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' TurnerQEMUTimerListGroup main_loop_tlg; 60dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' TurnerQEMUClock qemu_clocks[QEMU_CLOCK_MAX]; 61f9077a88a0b9edca081b0810dde73d108db087a6David 'Digit' Turner 62dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* A QEMUTimerList is a list of timers attached to a clock. More 63dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * than one QEMUTimerList can be attached to each clock, for instance 64dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * used by different AioContexts / threads. Each clock also has 65dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * a list of the QEMUTimerLists associated with it, in order that 66dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * reenabling the clock can call all the notifiers. 67dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 68dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 69dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstruct QEMUTimerList { 706a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner QEMUClock *clock; 71dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QemuMutex active_timers_lock; 72dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimer *active_timers; 73dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_ENTRY(QEMUTimerList) list; 74dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerListNotifyCB *notify_cb; 75dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner void *notify_opaque; 76dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 77dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* lightweight method to mark the end of timerlist's running */ 78dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QemuEvent timers_done_ev; 796a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner}; 806a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 81dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/** 82dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * qemu_clock_ptr: 83dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * @type: type of clock 84dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * 85dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * Translate a clock type into a pointer to QEMUClock object. 86dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * 87dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * Returns: a pointer to the QEMUClock object 88dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 89dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic inline QEMUClock *qemu_clock_ptr(QEMUClockType type) 90dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 91dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return &qemu_clocks[type]; 92dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 93dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 94dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) 95317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner{ 96317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner return timer_head && (timer_head->expire_time <= current_time); 97317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner} 98317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 99dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' TurnerQEMUTimerList *timerlist_new(QEMUClockType type, 100dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerListNotifyCB *cb, 101dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner void *opaque) 102dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 103dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list; 104dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 105dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 106dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list = g_malloc0(sizeof(QEMUTimerList)); 107dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_event_init(&timer_list->timers_done_ev, false); 108dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list->clock = clock; 109dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list->notify_cb = cb; 110dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list->notify_opaque = opaque; 111dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_init(&timer_list->active_timers_lock); 112dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list); 113dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timer_list; 114dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 1156a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 116dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timerlist_free(QEMUTimerList *timer_list) 117dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 118dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner assert(!timerlist_has_timers(timer_list)); 119dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (timer_list->clock) { 120dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_REMOVE(timer_list, list); 121dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 122dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_destroy(&timer_list->active_timers_lock); 123dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner g_free(timer_list); 124dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 1256a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 126dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic void qemu_clock_init(QEMUClockType type) 1276a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 128dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 129dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 1306a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner clock->type = type; 131dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner clock->enabled = true; 132dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner clock->last = INT64_MIN; 133dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_INIT(&clock->timerlists); 134dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner notifier_list_init(&clock->reset_notifiers); 135dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); 136dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 137dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 138dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool qemu_clock_use_for_deadline(QEMUClockType type) 139dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 140dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); 1416a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 1426a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 143dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid qemu_clock_notify(QEMUClockType type) 1446a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 145dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list; 146dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 147dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_FOREACH(timer_list, &clock->timerlists, list) { 148dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_notify(timer_list); 149dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 150dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 151dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 152dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* Disabling the clock will wait for related timerlists to stop 153dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * executing qemu_run_timers. Thus, this functions should not 154dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * be used from the callback of a timer that is based on @clock. 155dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * Doing so would cause a deadlock. 156dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * 157dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * Caller should hold BQL. 158dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 159dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid qemu_clock_enable(QEMUClockType type, bool enabled) 160dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 161dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 162dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *tl; 163dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool old = clock->enabled; 1646a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner clock->enabled = enabled; 165dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (enabled && !old) { 166dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_clock_notify(type); 167dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } else if (!enabled && old) { 168dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_FOREACH(tl, &clock->timerlists, list) { 169dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_event_wait(&tl->timers_done_ev); 170dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 171dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 172dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 173dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 174dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timerlist_has_timers(QEMUTimerList *timer_list) 175dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 176dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return !!timer_list->active_timers; 177dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 178dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 179dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool qemu_clock_has_timers(QEMUClockType type) 180dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 181dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timerlist_has_timers( 182dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner main_loop_tlg.tl[type]); 183dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 184dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 185dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timerlist_expired(QEMUTimerList *timer_list) 186dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 187dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t expire_time; 188dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 189dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 190dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_list->active_timers) { 191dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 192dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return false; 193dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 194dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner expire_time = timer_list->active_timers->expire_time; 195dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 196dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 197dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return expire_time < qemu_clock_get_ns(timer_list->clock->type); 1986a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 1996a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 200dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool qemu_clock_expired(QEMUClockType type) 201dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 202dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timerlist_expired( 203dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner main_loop_tlg.tl[type]); 204317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner} 205317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 206dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* 207dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * As above, but return -1 for no deadline, and do not cap to 2^32 208dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * as we know the result is always positive. 209dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 210dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 211dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint64_t timerlist_deadline_ns(QEMUTimerList *timer_list) 212dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 213dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t delta; 214dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t expire_time; 215dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 216dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_list->clock->enabled) { 217dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return -1; 218dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 219317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 220dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* The active timers list may be modified before the caller uses our return 221dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * value but ->notify_cb() is called when the deadline changes. Therefore 222dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * the caller should notice the change and there is no race condition. 223dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 224dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 225dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_list->active_timers) { 226dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 227dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return -1; 228317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner } 229dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner expire_time = timer_list->active_timers->expire_time; 230dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 231dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 232dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 233317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 234dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (delta <= 0) { 235dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return 0; 236dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 237317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 238f9077a88a0b9edca081b0810dde73d108db087a6David 'Digit' Turner return delta; 239317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner} 240317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 241dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* Calculate the soonest deadline across all timerlists attached 242dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * to the clock. This is used for the icount timeout so we 243dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * ignore whether or not the clock should be used in deadline 244dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * calculations. 245dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 246dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint64_t qemu_clock_deadline_ns_all(QEMUClockType type) 2476a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 248dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t deadline = -1; 249dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list; 250dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 251dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QLIST_FOREACH(timer_list, &clock->timerlists, list) { 252dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner deadline = qemu_soonest_timeout(deadline, 253dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_deadline_ns(timer_list)); 254dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 255dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return deadline; 256dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 2576a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 258dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' TurnerQEMUClockType timerlist_get_clock(QEMUTimerList *timer_list) 259dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 260dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timer_list->clock->type; 261dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 262dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 263dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' TurnerQEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) 264dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 265dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return main_loop_tlg.tl[type]; 266dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 267dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 268dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timerlist_notify(QEMUTimerList *timer_list) 269dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 270dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (timer_list->notify_cb) { 271dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list->notify_cb(timer_list->notify_opaque); 272dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } else { 273dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_notify_event(); 274dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 275dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 276dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 277dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* Transition function to convert a nanosecond timeout to ms 278dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * This is used where a system does not support ppoll 279dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 280dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint qemu_timeout_ns_to_ms(int64_t ns) 281dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 282dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t ms; 283dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (ns < 0) { 284dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return -1; 285dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 286dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 287dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!ns) { 288dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return 0; 289dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 290dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 291dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* Always round up, because it's better to wait too long than to wait too 292dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * little and effectively busy-wait 293dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 294dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ms = (ns + SCALE_MS - 1) / SCALE_MS; 295dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 296dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */ 297dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (ms > (int64_t) INT32_MAX) { 298dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ms = INT32_MAX; 299dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 300dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 301dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return (int) ms; 302dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 303dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 304dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifndef CONFIG_ANDROID // TODO(digit): Implement g_poll() 305dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* qemu implementation of g_poll which uses a nanosecond timeout but is 306dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner * otherwise identical to g_poll 307dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner */ 308dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) 309dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 310dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifdef CONFIG_PPOLL 311dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (timeout < 0) { 312dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return ppoll((struct pollfd *)fds, nfds, NULL, NULL); 313dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } else { 314dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner struct timespec ts; 315dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts.tv_sec = timeout / 1000000000LL; 316dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts.tv_nsec = timeout % 1000000000LL; 317dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return ppoll((struct pollfd *)fds, nfds, &ts, NULL); 318dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 319dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#else 320dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout)); 321dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#endif 322dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 323dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#endif // !CONFIG_ANDROID 324dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 325dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_init(QEMUTimer *ts, 326dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list, int scale, 327dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerCB *cb, void *opaque) 328dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 329dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts->timer_list = timer_list; 3306a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner ts->cb = cb; 3316a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner ts->opaque = opaque; 332317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner ts->scale = scale; 333dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts->expire_time = -1; 3346a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 3356a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 336dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_free(QEMUTimer *ts) 3376a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 338aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(ts); 3396a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 3406a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 341dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) 3426a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 3436a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner QEMUTimer **pt, *t; 3446a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 345dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts->expire_time = -1; 346dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner pt = &timer_list->active_timers; 3476a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner for(;;) { 3486a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner t = *pt; 3496a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner if (!t) 3506a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner break; 3516a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner if (t == ts) { 3526a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner *pt = t->next; 3536a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner break; 3546a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 3556a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner pt = &t->next; 3566a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 3576a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 3586a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 359dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic bool timer_mod_ns_locked(QEMUTimerList *timer_list, 360dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimer *ts, int64_t expire_time) 3616a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 3626a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner QEMUTimer **pt, *t; 3636a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 3646a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner /* add the timer in the sorted list */ 365dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner pt = &timer_list->active_timers; 366dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (;;) { 3676a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner t = *pt; 368dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_expired_ns(t, expire_time)) { 3696a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner break; 370317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner } 3716a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner pt = &t->next; 3726a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 373dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts->expire_time = MAX(expire_time, 0); 3746a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner ts->next = *pt; 3756a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner *pt = ts; 3766a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 377dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return pt == &timer_list->active_timers; 378dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 379dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 380dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerstatic void timerlist_rearm(QEMUTimerList *timer_list) 381dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 382dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner /* Interrupt execution to force deadline recalculation. */ 383dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_clock_warp(timer_list->clock->type); 384dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_notify(timer_list); 385dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 386dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 387dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* stop a timer, but do not dealloc it */ 388dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_del(QEMUTimer *ts) 389dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 390dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list = ts->timer_list; 391dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 392dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 393dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_del_locked(timer_list, ts); 394dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 395317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner} 396317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner 397317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner/* modify the current timer so that it will be fired when current_time 398317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner >= expire_time. The corresponding callback will be called. */ 399dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_mod_ns(QEMUTimer *ts, int64_t expire_time) 400317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner{ 401dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list = ts->timer_list; 402dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool rearm; 403dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 404dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 405dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_del_locked(timer_list, ts); 406dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 407dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 408dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 409dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (rearm) { 410dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_rearm(timer_list); 411dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 4126a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 4136a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 414dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner/* modify the current timer so that it will be fired when current_time 415dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner >= expire_time or the current deadline, whichever comes earlier. 416dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner The corresponding callback will be called. */ 417dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) 4186a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 419dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerList *timer_list = ts->timer_list; 420dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool rearm; 421dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 422dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 423dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (ts->expire_time == -1 || ts->expire_time > expire_time) { 424dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (ts->expire_time != -1) { 425dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_del_locked(timer_list, ts); 426dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 427dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner rearm = timer_mod_ns_locked(timer_list, ts, expire_time); 428dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } else { 429dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner rearm = false; 430dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 431dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 432dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 433dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (rearm) { 434dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_rearm(timer_list); 4356a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 4366a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 4376a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 438dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_mod(QEMUTimer *ts, int64_t expire_time) 4396a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 440dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_mod_ns(ts, expire_time * ts->scale); 4416a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 4426a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 443dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) 4446a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 445dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_mod_anticipate_ns(ts, expire_time * ts->scale); 446dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 447dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 448dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timer_pending(QEMUTimer *ts) 449dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 450dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return ts->expire_time >= 0; 451dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 452dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 453dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timer_expired(QEMUTimer *timer_head, int64_t current_time) 454dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 455dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timer_expired_ns(timer_head, current_time * timer_head->scale); 456dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 457dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 458dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timerlist_run_timers(QEMUTimerList *timer_list) 459dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 460dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimer *ts; 4616a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner int64_t current_time; 462dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool progress = false; 463dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerCB *cb; 464dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner void *opaque; 4656b512811e01d7c81348bfa9c29c21f788ccc0a8eDavid 'Digit' Turner 466dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_event_reset(&timer_list->timers_done_ev); 467dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_list->clock->enabled) { 468dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner goto out; 469dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 4706a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 471dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner current_time = qemu_clock_get_ns(timer_list->clock->type); 4726a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner for(;;) { 473dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_lock(&timer_list->active_timers_lock); 474dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts = timer_list->active_timers; 475dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (!timer_expired_ns(ts, current_time)) { 476dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 4776a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner break; 478317c9d54284844615b33a25834a63248bf1bfa73David 'Digit' Turner } 479dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 4806a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner /* remove timer from the list before calling the callback */ 481dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timer_list->active_timers = ts->next; 4826a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner ts->next = NULL; 483dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner ts->expire_time = -1; 484dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner cb = ts->cb; 485dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner opaque = ts->opaque; 486dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_mutex_unlock(&timer_list->active_timers_lock); 4876a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 4886a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner /* run the callback (the timer list can be modified) */ 489dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner cb(opaque); 490dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner progress = true; 4916a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 492dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 493dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerout: 494dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_event_set(&timer_list->timers_done_ev); 495dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return progress; 4966a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 4976a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 498dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool qemu_clock_run_timers(QEMUClockType type) 4996a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 500dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timerlist_run_timers(main_loop_tlg.tl[type]); 501dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 502dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 503dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timerlistgroup_init(QEMUTimerListGroup *tlg, 504dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUTimerListNotifyCB *cb, void *opaque) 505dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 506dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 507dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 508dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner tlg->tl[type] = timerlist_new(type, cb, opaque); 509dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 510dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 511dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 512dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid timerlistgroup_deinit(QEMUTimerListGroup *tlg) 513dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 514dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 515dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 516dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_free(tlg->tl[type]); 517dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 518dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 519dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 520dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) 521dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 522dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 523dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool progress = false; 524dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 525dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner progress |= timerlist_run_timers(tlg->tl[type]); 526dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 527dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return progress; 528dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 529dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 530dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) 531dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 532dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t deadline = -1; 533dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 534dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 535dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) { 536dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner deadline = qemu_soonest_timeout(deadline, 537dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner timerlist_deadline_ns( 538dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner tlg->tl[type])); 5396a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 5406a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 541dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return deadline; 5426a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 5436a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 544dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerint64_t qemu_clock_get_ns(QEMUClockType type) 5456a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 546dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner int64_t now, last; 547dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 548dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 549dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner switch (type) { 5506a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner case QEMU_CLOCK_REALTIME: 5516a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner return get_clock(); 5526a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner default: 5536a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner case QEMU_CLOCK_VIRTUAL: 5546a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner if (use_icount) { 5556a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner return cpu_get_icount(); 5566a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } else { 5576a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner return cpu_get_clock(); 5586a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 5596a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner case QEMU_CLOCK_HOST: 560dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner now = get_clock_realtime(); 561dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner last = clock->last; 562dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner clock->last = now; 563dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner if (now < last) { 564dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner notifier_list_notify(&clock->reset_notifiers, &now); 565dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner } 566dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return now; 5676a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 5686a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 5696a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 570dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid qemu_clock_register_reset_notifier(QEMUClockType type, 571dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner Notifier *notifier) 5726a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 573dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClock *clock = qemu_clock_ptr(type); 574dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner notifier_list_add(&clock->reset_notifiers, notifier); 5756a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 5766a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 577dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid qemu_clock_unregister_reset_notifier(QEMUClockType type, 578dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner Notifier *notifier) 5796a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 580dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner notifier_remove(notifier); 581dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 5826a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 583dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnervoid init_clocks(void) 584dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 585dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 586dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 587dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner qemu_clock_init(type); 5886a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 589dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 590dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK 591dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); 592dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner#endif 5936a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 5946a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 595dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turneruint64_t timer_expire_time_ns(QEMUTimer *ts) 5966a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner{ 597dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return timer_pending(ts) ? ts->expire_time : -1; 5986a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner} 5996a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner 600dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turnerbool qemu_clock_run_all_timers(void) 601dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner{ 602dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner bool progress = false; 603dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner QEMUClockType type; 604dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 605dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner for (type = 0; type < QEMU_CLOCK_MAX; type++) { 606dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner progress |= qemu_clock_run_timers(type); 6076a9ef1773bf874dea493ff3861782a1e577b67ddDavid Turner } 608dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner 609dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner return progress; 610dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner} 611