qemu/qemu-timer.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "sysemu/sysemu.h"
  26#include "monitor/monitor.h"
  27#include "ui/console.h"
  28
  29#include "hw/hw.h"
  30
  31#include "qemu/timer.h"
  32#ifdef CONFIG_POSIX
  33#include <pthread.h>
  34#endif
  35
  36#ifdef CONFIG_PPOLL
  37#include <poll.h>
  38#endif
  39
  40#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
  41#include <sys/prctl.h>
  42#endif
  43
  44/***********************************************************/
  45/* timers */
  46
  47typedef struct QEMUClock {
  48    /* We rely on BQL to protect the timerlists */
  49    QLIST_HEAD(, QEMUTimerList) timerlists;
  50
  51    NotifierList reset_notifiers;
  52    int64_t last;
  53
  54    QEMUClockType type;
  55    bool enabled;
  56} QEMUClock;
  57
  58QEMUTimerListGroup main_loop_tlg;
  59QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
  60
  61/* A QEMUTimerList is a list of timers attached to a clock. More
  62 * than one QEMUTimerList can be attached to each clock, for instance
  63 * used by different AioContexts / threads. Each clock also has
  64 * a list of the QEMUTimerLists associated with it, in order that
  65 * reenabling the clock can call all the notifiers.
  66 */
  67
  68struct QEMUTimerList {
  69    QEMUClock *clock;
  70    QemuMutex active_timers_lock;
  71    QEMUTimer *active_timers;
  72    QLIST_ENTRY(QEMUTimerList) list;
  73    QEMUTimerListNotifyCB *notify_cb;
  74    void *notify_opaque;
  75
  76    /* lightweight method to mark the end of timerlist's running */
  77    QemuEvent timers_done_ev;
  78};
  79
  80/**
  81 * qemu_clock_ptr:
  82 * @type: type of clock
  83 *
  84 * Translate a clock type into a pointer to QEMUClock object.
  85 *
  86 * Returns: a pointer to the QEMUClock object
  87 */
  88static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
  89{
  90    return &qemu_clocks[type];
  91}
  92
  93static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
  94{
  95    return timer_head && (timer_head->expire_time <= current_time);
  96}
  97
  98QEMUTimerList *timerlist_new(QEMUClockType type,
  99                             QEMUTimerListNotifyCB *cb,
 100                             void *opaque)
 101{
 102    QEMUTimerList *timer_list;
 103    QEMUClock *clock = qemu_clock_ptr(type);
 104
 105    timer_list = g_malloc0(sizeof(QEMUTimerList));
 106    qemu_event_init(&timer_list->timers_done_ev, false);
 107    timer_list->clock = clock;
 108    timer_list->notify_cb = cb;
 109    timer_list->notify_opaque = opaque;
 110    qemu_mutex_init(&timer_list->active_timers_lock);
 111    QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
 112    return timer_list;
 113}
 114
 115void timerlist_free(QEMUTimerList *timer_list)
 116{
 117    assert(!timerlist_has_timers(timer_list));
 118    if (timer_list->clock) {
 119        QLIST_REMOVE(timer_list, list);
 120    }
 121    qemu_mutex_destroy(&timer_list->active_timers_lock);
 122    g_free(timer_list);
 123}
 124
 125static void qemu_clock_init(QEMUClockType type)
 126{
 127    QEMUClock *clock = qemu_clock_ptr(type);
 128
 129    clock->type = type;
 130    clock->enabled = true;
 131    clock->last = INT64_MIN;
 132    QLIST_INIT(&clock->timerlists);
 133    notifier_list_init(&clock->reset_notifiers);
 134    main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
 135}
 136
 137bool qemu_clock_use_for_deadline(QEMUClockType type)
 138{
 139    return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
 140}
 141
 142void qemu_clock_notify(QEMUClockType type)
 143{
 144    QEMUTimerList *timer_list;
 145    QEMUClock *clock = qemu_clock_ptr(type);
 146    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
 147        timerlist_notify(timer_list);
 148    }
 149}
 150
 151/* Disabling the clock will wait for related timerlists to stop
 152 * executing qemu_run_timers.  Thus, this functions should not
 153 * be used from the callback of a timer that is based on @clock.
 154 * Doing so would cause a deadlock.
 155 *
 156 * Caller should hold BQL.
 157 */
 158void qemu_clock_enable(QEMUClockType type, bool enabled)
 159{
 160    QEMUClock *clock = qemu_clock_ptr(type);
 161    QEMUTimerList *tl;
 162    bool old = clock->enabled;
 163    clock->enabled = enabled;
 164    if (enabled && !old) {
 165        qemu_clock_notify(type);
 166    } else if (!enabled && old) {
 167        QLIST_FOREACH(tl, &clock->timerlists, list) {
 168            qemu_event_wait(&tl->timers_done_ev);
 169        }
 170    }
 171}
 172
 173bool timerlist_has_timers(QEMUTimerList *timer_list)
 174{
 175    return !!timer_list->active_timers;
 176}
 177
 178bool qemu_clock_has_timers(QEMUClockType type)
 179{
 180    return timerlist_has_timers(
 181        main_loop_tlg.tl[type]);
 182}
 183
 184bool timerlist_expired(QEMUTimerList *timer_list)
 185{
 186    int64_t expire_time;
 187
 188    qemu_mutex_lock(&timer_list->active_timers_lock);
 189    if (!timer_list->active_timers) {
 190        qemu_mutex_unlock(&timer_list->active_timers_lock);
 191        return false;
 192    }
 193    expire_time = timer_list->active_timers->expire_time;
 194    qemu_mutex_unlock(&timer_list->active_timers_lock);
 195
 196    return expire_time < qemu_clock_get_ns(timer_list->clock->type);
 197}
 198
 199bool qemu_clock_expired(QEMUClockType type)
 200{
 201    return timerlist_expired(
 202        main_loop_tlg.tl[type]);
 203}
 204
 205/*
 206 * As above, but return -1 for no deadline, and do not cap to 2^32
 207 * as we know the result is always positive.
 208 */
 209
 210int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
 211{
 212    int64_t delta;
 213    int64_t expire_time;
 214
 215    if (!timer_list->clock->enabled) {
 216        return -1;
 217    }
 218
 219    /* The active timers list may be modified before the caller uses our return
 220     * value but ->notify_cb() is called when the deadline changes.  Therefore
 221     * the caller should notice the change and there is no race condition.
 222     */
 223    qemu_mutex_lock(&timer_list->active_timers_lock);
 224    if (!timer_list->active_timers) {
 225        qemu_mutex_unlock(&timer_list->active_timers_lock);
 226        return -1;
 227    }
 228    expire_time = timer_list->active_timers->expire_time;
 229    qemu_mutex_unlock(&timer_list->active_timers_lock);
 230
 231    delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
 232
 233    if (delta <= 0) {
 234        return 0;
 235    }
 236
 237    return delta;
 238}
 239
 240/* Calculate the soonest deadline across all timerlists attached
 241 * to the clock. This is used for the icount timeout so we
 242 * ignore whether or not the clock should be used in deadline
 243 * calculations.
 244 */
 245int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
 246{
 247    int64_t deadline = -1;
 248    QEMUTimerList *timer_list;
 249    QEMUClock *clock = qemu_clock_ptr(type);
 250    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
 251        deadline = qemu_soonest_timeout(deadline,
 252                                        timerlist_deadline_ns(timer_list));
 253    }
 254    return deadline;
 255}
 256
 257QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
 258{
 259    return timer_list->clock->type;
 260}
 261
 262QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
 263{
 264    return main_loop_tlg.tl[type];
 265}
 266
 267void timerlist_notify(QEMUTimerList *timer_list)
 268{
 269    if (timer_list->notify_cb) {
 270        timer_list->notify_cb(timer_list->notify_opaque);
 271    } else {
 272        qemu_notify_event();
 273    }
 274}
 275
 276/* Transition function to convert a nanosecond timeout to ms
 277 * This is used where a system does not support ppoll
 278 */
 279int qemu_timeout_ns_to_ms(int64_t ns)
 280{
 281    int64_t ms;
 282    if (ns < 0) {
 283        return -1;
 284    }
 285
 286    if (!ns) {
 287        return 0;
 288    }
 289
 290    /* Always round up, because it's better to wait too long than to wait too
 291     * little and effectively busy-wait
 292     */
 293    ms = (ns + SCALE_MS - 1) / SCALE_MS;
 294
 295    /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
 296    if (ms > (int64_t) INT32_MAX) {
 297        ms = INT32_MAX;
 298    }
 299
 300    return (int) ms;
 301}
 302
 303
 304/* qemu implementation of g_poll which uses a nanosecond timeout but is
 305 * otherwise identical to g_poll
 306 */
 307int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
 308{
 309#ifdef CONFIG_PPOLL
 310    if (timeout < 0) {
 311        return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
 312    } else {
 313        struct timespec ts;
 314        ts.tv_sec = timeout / 1000000000LL;
 315        ts.tv_nsec = timeout % 1000000000LL;
 316        return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
 317    }
 318#else
 319    return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
 320#endif
 321}
 322
 323
 324void timer_init(QEMUTimer *ts,
 325                QEMUTimerList *timer_list, int scale,
 326                QEMUTimerCB *cb, void *opaque)
 327{
 328    ts->timer_list = timer_list;
 329    ts->cb = cb;
 330    ts->opaque = opaque;
 331    ts->scale = scale;
 332    ts->expire_time = -1;
 333}
 334
 335void timer_free(QEMUTimer *ts)
 336{
 337    g_free(ts);
 338}
 339
 340static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
 341{
 342    QEMUTimer **pt, *t;
 343
 344    ts->expire_time = -1;
 345    pt = &timer_list->active_timers;
 346    for(;;) {
 347        t = *pt;
 348        if (!t)
 349            break;
 350        if (t == ts) {
 351            *pt = t->next;
 352            break;
 353        }
 354        pt = &t->next;
 355    }
 356}
 357
 358static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
 359                                QEMUTimer *ts, int64_t expire_time)
 360{
 361    QEMUTimer **pt, *t;
 362
 363    /* add the timer in the sorted list */
 364    pt = &timer_list->active_timers;
 365    for (;;) {
 366        t = *pt;
 367        if (!timer_expired_ns(t, expire_time)) {
 368            break;
 369        }
 370        pt = &t->next;
 371    }
 372    ts->expire_time = MAX(expire_time, 0);
 373    ts->next = *pt;
 374    *pt = ts;
 375
 376    return pt == &timer_list->active_timers;
 377}
 378
 379static void timerlist_rearm(QEMUTimerList *timer_list)
 380{
 381    /* Interrupt execution to force deadline recalculation.  */
 382    qemu_clock_warp(timer_list->clock->type);
 383    timerlist_notify(timer_list);
 384}
 385
 386/* stop a timer, but do not dealloc it */
 387void timer_del(QEMUTimer *ts)
 388{
 389    QEMUTimerList *timer_list = ts->timer_list;
 390
 391    qemu_mutex_lock(&timer_list->active_timers_lock);
 392    timer_del_locked(timer_list, ts);
 393    qemu_mutex_unlock(&timer_list->active_timers_lock);
 394}
 395
 396/* modify the current timer so that it will be fired when current_time
 397   >= expire_time. The corresponding callback will be called. */
 398void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
 399{
 400    QEMUTimerList *timer_list = ts->timer_list;
 401    bool rearm;
 402
 403    qemu_mutex_lock(&timer_list->active_timers_lock);
 404    timer_del_locked(timer_list, ts);
 405    rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
 406    qemu_mutex_unlock(&timer_list->active_timers_lock);
 407
 408    if (rearm) {
 409        timerlist_rearm(timer_list);
 410    }
 411}
 412
 413/* modify the current timer so that it will be fired when current_time
 414   >= expire_time or the current deadline, whichever comes earlier.
 415   The corresponding callback will be called. */
 416void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
 417{
 418    QEMUTimerList *timer_list = ts->timer_list;
 419    bool rearm;
 420
 421    qemu_mutex_lock(&timer_list->active_timers_lock);
 422    if (ts->expire_time == -1 || ts->expire_time > expire_time) {
 423        if (ts->expire_time != -1) {
 424            timer_del_locked(timer_list, ts);
 425        }
 426        rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
 427    } else {
 428        rearm = false;
 429    }
 430    qemu_mutex_unlock(&timer_list->active_timers_lock);
 431
 432    if (rearm) {
 433        timerlist_rearm(timer_list);
 434    }
 435}
 436
 437void timer_mod(QEMUTimer *ts, int64_t expire_time)
 438{
 439    timer_mod_ns(ts, expire_time * ts->scale);
 440}
 441
 442void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
 443{
 444    timer_mod_anticipate_ns(ts, expire_time * ts->scale);
 445}
 446
 447bool timer_pending(QEMUTimer *ts)
 448{
 449    return ts->expire_time >= 0;
 450}
 451
 452bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
 453{
 454    return timer_expired_ns(timer_head, current_time * timer_head->scale);
 455}
 456
 457bool timerlist_run_timers(QEMUTimerList *timer_list)
 458{
 459    QEMUTimer *ts;
 460    int64_t current_time;
 461    bool progress = false;
 462    QEMUTimerCB *cb;
 463    void *opaque;
 464
 465    qemu_event_reset(&timer_list->timers_done_ev);
 466    if (!timer_list->clock->enabled) {
 467        goto out;
 468    }
 469
 470    current_time = qemu_clock_get_ns(timer_list->clock->type);
 471    for(;;) {
 472        qemu_mutex_lock(&timer_list->active_timers_lock);
 473        ts = timer_list->active_timers;
 474        if (!timer_expired_ns(ts, current_time)) {
 475            qemu_mutex_unlock(&timer_list->active_timers_lock);
 476            break;
 477        }
 478
 479        /* remove timer from the list before calling the callback */
 480        timer_list->active_timers = ts->next;
 481        ts->next = NULL;
 482        ts->expire_time = -1;
 483        cb = ts->cb;
 484        opaque = ts->opaque;
 485        qemu_mutex_unlock(&timer_list->active_timers_lock);
 486
 487        /* run the callback (the timer list can be modified) */
 488        cb(opaque);
 489        progress = true;
 490    }
 491
 492out:
 493    qemu_event_set(&timer_list->timers_done_ev);
 494    return progress;
 495}
 496
 497bool qemu_clock_run_timers(QEMUClockType type)
 498{
 499    return timerlist_run_timers(main_loop_tlg.tl[type]);
 500}
 501
 502void timerlistgroup_init(QEMUTimerListGroup *tlg,
 503                         QEMUTimerListNotifyCB *cb, void *opaque)
 504{
 505    QEMUClockType type;
 506    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 507        tlg->tl[type] = timerlist_new(type, cb, opaque);
 508    }
 509}
 510
 511void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
 512{
 513    QEMUClockType type;
 514    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 515        timerlist_free(tlg->tl[type]);
 516    }
 517}
 518
 519bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
 520{
 521    QEMUClockType type;
 522    bool progress = false;
 523    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 524        progress |= timerlist_run_timers(tlg->tl[type]);
 525    }
 526    return progress;
 527}
 528
 529int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
 530{
 531    int64_t deadline = -1;
 532    QEMUClockType type;
 533    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 534        if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
 535            deadline = qemu_soonest_timeout(deadline,
 536                                            timerlist_deadline_ns(
 537                                                tlg->tl[type]));
 538        }
 539    }
 540    return deadline;
 541}
 542
 543int64_t qemu_clock_get_ns(QEMUClockType type)
 544{
 545    int64_t now, last;
 546    QEMUClock *clock = qemu_clock_ptr(type);
 547
 548    switch (type) {
 549    case QEMU_CLOCK_REALTIME:
 550        return get_clock();
 551    default:
 552    case QEMU_CLOCK_VIRTUAL:
 553        if (use_icount) {
 554            return cpu_get_icount();
 555        } else {
 556            return cpu_get_clock();
 557        }
 558    case QEMU_CLOCK_HOST:
 559        now = get_clock_realtime();
 560        last = clock->last;
 561        clock->last = now;
 562        if (now < last) {
 563            notifier_list_notify(&clock->reset_notifiers, &now);
 564        }
 565        return now;
 566    }
 567}
 568
 569void qemu_clock_register_reset_notifier(QEMUClockType type,
 570                                        Notifier *notifier)
 571{
 572    QEMUClock *clock = qemu_clock_ptr(type);
 573    notifier_list_add(&clock->reset_notifiers, notifier);
 574}
 575
 576void qemu_clock_unregister_reset_notifier(QEMUClockType type,
 577                                          Notifier *notifier)
 578{
 579    notifier_remove(notifier);
 580}
 581
 582void init_clocks(void)
 583{
 584    QEMUClockType type;
 585    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 586        qemu_clock_init(type);
 587    }
 588
 589#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
 590    prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
 591#endif
 592}
 593
 594uint64_t timer_expire_time_ns(QEMUTimer *ts)
 595{
 596    return timer_pending(ts) ? ts->expire_time : -1;
 597}
 598
 599bool qemu_clock_run_all_timers(void)
 600{
 601    bool progress = false;
 602    QEMUClockType type;
 603
 604    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 605        progress |= qemu_clock_run_timers(type);
 606    }
 607
 608    return progress;
 609}
 610