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