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;
  59static QEMUClock 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    /* Assert that the clock of type TYPE has not been initialized yet. */
 130    assert(main_loop_tlg.tl[type] == NULL);
 131
 132    clock->type = type;
 133    clock->enabled = true;
 134    clock->last = INT64_MIN;
 135    QLIST_INIT(&clock->timerlists);
 136    notifier_list_init(&clock->reset_notifiers);
 137    main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
 138}
 139
 140bool qemu_clock_use_for_deadline(QEMUClockType type)
 141{
 142    return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
 143}
 144
 145void qemu_clock_notify(QEMUClockType type)
 146{
 147    QEMUTimerList *timer_list;
 148    QEMUClock *clock = qemu_clock_ptr(type);
 149    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
 150        timerlist_notify(timer_list);
 151    }
 152}
 153
 154/* Disabling the clock will wait for related timerlists to stop
 155 * executing qemu_run_timers.  Thus, this functions should not
 156 * be used from the callback of a timer that is based on @clock.
 157 * Doing so would cause a deadlock.
 158 *
 159 * Caller should hold BQL.
 160 */
 161void qemu_clock_enable(QEMUClockType type, bool enabled)
 162{
 163    QEMUClock *clock = qemu_clock_ptr(type);
 164    QEMUTimerList *tl;
 165    bool old = clock->enabled;
 166    clock->enabled = enabled;
 167    if (enabled && !old) {
 168        qemu_clock_notify(type);
 169    } else if (!enabled && old) {
 170        QLIST_FOREACH(tl, &clock->timerlists, list) {
 171            qemu_event_wait(&tl->timers_done_ev);
 172        }
 173    }
 174}
 175
 176bool timerlist_has_timers(QEMUTimerList *timer_list)
 177{
 178    return !!timer_list->active_timers;
 179}
 180
 181bool qemu_clock_has_timers(QEMUClockType type)
 182{
 183    return timerlist_has_timers(
 184        main_loop_tlg.tl[type]);
 185}
 186
 187bool timerlist_expired(QEMUTimerList *timer_list)
 188{
 189    int64_t expire_time;
 190
 191    qemu_mutex_lock(&timer_list->active_timers_lock);
 192    if (!timer_list->active_timers) {
 193        qemu_mutex_unlock(&timer_list->active_timers_lock);
 194        return false;
 195    }
 196    expire_time = timer_list->active_timers->expire_time;
 197    qemu_mutex_unlock(&timer_list->active_timers_lock);
 198
 199    return expire_time < qemu_clock_get_ns(timer_list->clock->type);
 200}
 201
 202bool qemu_clock_expired(QEMUClockType type)
 203{
 204    return timerlist_expired(
 205        main_loop_tlg.tl[type]);
 206}
 207
 208/*
 209 * As above, but return -1 for no deadline, and do not cap to 2^32
 210 * as we know the result is always positive.
 211 */
 212
 213int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
 214{
 215    int64_t delta;
 216    int64_t expire_time;
 217
 218    if (!timer_list->clock->enabled) {
 219        return -1;
 220    }
 221
 222    /* The active timers list may be modified before the caller uses our return
 223     * value but ->notify_cb() is called when the deadline changes.  Therefore
 224     * the caller should notice the change and there is no race condition.
 225     */
 226    qemu_mutex_lock(&timer_list->active_timers_lock);
 227    if (!timer_list->active_timers) {
 228        qemu_mutex_unlock(&timer_list->active_timers_lock);
 229        return -1;
 230    }
 231    expire_time = timer_list->active_timers->expire_time;
 232    qemu_mutex_unlock(&timer_list->active_timers_lock);
 233
 234    delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
 235
 236    if (delta <= 0) {
 237        return 0;
 238    }
 239
 240    return delta;
 241}
 242
 243/* Calculate the soonest deadline across all timerlists attached
 244 * to the clock. This is used for the icount timeout so we
 245 * ignore whether or not the clock should be used in deadline
 246 * calculations.
 247 */
 248int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
 249{
 250    int64_t deadline = -1;
 251    QEMUTimerList *timer_list;
 252    QEMUClock *clock = qemu_clock_ptr(type);
 253    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
 254        deadline = qemu_soonest_timeout(deadline,
 255                                        timerlist_deadline_ns(timer_list));
 256    }
 257    return deadline;
 258}
 259
 260QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
 261{
 262    return timer_list->clock->type;
 263}
 264
 265QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
 266{
 267    return main_loop_tlg.tl[type];
 268}
 269
 270void timerlist_notify(QEMUTimerList *timer_list)
 271{
 272    if (timer_list->notify_cb) {
 273        timer_list->notify_cb(timer_list->notify_opaque);
 274    } else {
 275        qemu_notify_event();
 276    }
 277}
 278
 279/* Transition function to convert a nanosecond timeout to ms
 280 * This is used where a system does not support ppoll
 281 */
 282int qemu_timeout_ns_to_ms(int64_t ns)
 283{
 284    int64_t ms;
 285    if (ns < 0) {
 286        return -1;
 287    }
 288
 289    if (!ns) {
 290        return 0;
 291    }
 292
 293    /* Always round up, because it's better to wait too long than to wait too
 294     * little and effectively busy-wait
 295     */
 296    ms = (ns + SCALE_MS - 1) / SCALE_MS;
 297
 298    /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
 299    if (ms > (int64_t) INT32_MAX) {
 300        ms = INT32_MAX;
 301    }
 302
 303    return (int) ms;
 304}
 305
 306
 307/* qemu implementation of g_poll which uses a nanosecond timeout but is
 308 * otherwise identical to g_poll
 309 */
 310int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
 311{
 312#ifdef CONFIG_PPOLL
 313    if (timeout < 0) {
 314        return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
 315    } else {
 316        struct timespec ts;
 317        ts.tv_sec = timeout / 1000000000LL;
 318        ts.tv_nsec = timeout % 1000000000LL;
 319        return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
 320    }
 321#else
 322    return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
 323#endif
 324}
 325
 326
 327void timer_init(QEMUTimer *ts,
 328                QEMUTimerList *timer_list, int scale,
 329                QEMUTimerCB *cb, void *opaque)
 330{
 331    ts->timer_list = timer_list;
 332    ts->cb = cb;
 333    ts->opaque = opaque;
 334    ts->scale = scale;
 335    ts->expire_time = -1;
 336}
 337
 338void timer_free(QEMUTimer *ts)
 339{
 340    g_free(ts);
 341}
 342
 343static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
 344{
 345    QEMUTimer **pt, *t;
 346
 347    ts->expire_time = -1;
 348    pt = &timer_list->active_timers;
 349    for(;;) {
 350        t = *pt;
 351        if (!t)
 352            break;
 353        if (t == ts) {
 354            *pt = t->next;
 355            break;
 356        }
 357        pt = &t->next;
 358    }
 359}
 360
 361static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
 362                                QEMUTimer *ts, int64_t expire_time)
 363{
 364    QEMUTimer **pt, *t;
 365
 366    /* add the timer in the sorted list */
 367    pt = &timer_list->active_timers;
 368    for (;;) {
 369        t = *pt;
 370        if (!timer_expired_ns(t, expire_time)) {
 371            break;
 372        }
 373        pt = &t->next;
 374    }
 375    ts->expire_time = MAX(expire_time, 0);
 376    ts->next = *pt;
 377    *pt = ts;
 378
 379    return pt == &timer_list->active_timers;
 380}
 381
 382static void timerlist_rearm(QEMUTimerList *timer_list)
 383{
 384    /* Interrupt execution to force deadline recalculation.  */
 385    qemu_clock_warp(timer_list->clock->type);
 386    timerlist_notify(timer_list);
 387}
 388
 389/* stop a timer, but do not dealloc it */
 390void timer_del(QEMUTimer *ts)
 391{
 392    QEMUTimerList *timer_list = ts->timer_list;
 393
 394    qemu_mutex_lock(&timer_list->active_timers_lock);
 395    timer_del_locked(timer_list, ts);
 396    qemu_mutex_unlock(&timer_list->active_timers_lock);
 397}
 398
 399/* modify the current timer so that it will be fired when current_time
 400   >= expire_time. The corresponding callback will be called. */
 401void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
 402{
 403    QEMUTimerList *timer_list = ts->timer_list;
 404    bool rearm;
 405
 406    qemu_mutex_lock(&timer_list->active_timers_lock);
 407    timer_del_locked(timer_list, ts);
 408    rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
 409    qemu_mutex_unlock(&timer_list->active_timers_lock);
 410
 411    if (rearm) {
 412        timerlist_rearm(timer_list);
 413    }
 414}
 415
 416/* modify the current timer so that it will be fired when current_time
 417   >= expire_time or the current deadline, whichever comes earlier.
 418   The corresponding callback will be called. */
 419void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
 420{
 421    QEMUTimerList *timer_list = ts->timer_list;
 422    bool rearm;
 423
 424    qemu_mutex_lock(&timer_list->active_timers_lock);
 425    if (ts->expire_time == -1 || ts->expire_time > expire_time) {
 426        if (ts->expire_time != -1) {
 427            timer_del_locked(timer_list, ts);
 428        }
 429        rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
 430    } else {
 431        rearm = false;
 432    }
 433    qemu_mutex_unlock(&timer_list->active_timers_lock);
 434
 435    if (rearm) {
 436        timerlist_rearm(timer_list);
 437    }
 438}
 439
 440void timer_mod(QEMUTimer *ts, int64_t expire_time)
 441{
 442    timer_mod_ns(ts, expire_time * ts->scale);
 443}
 444
 445void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
 446{
 447    timer_mod_anticipate_ns(ts, expire_time * ts->scale);
 448}
 449
 450bool timer_pending(QEMUTimer *ts)
 451{
 452    return ts->expire_time >= 0;
 453}
 454
 455bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
 456{
 457    return timer_expired_ns(timer_head, current_time * timer_head->scale);
 458}
 459
 460bool timerlist_run_timers(QEMUTimerList *timer_list)
 461{
 462    QEMUTimer *ts;
 463    int64_t current_time;
 464    bool progress = false;
 465    QEMUTimerCB *cb;
 466    void *opaque;
 467
 468    qemu_event_reset(&timer_list->timers_done_ev);
 469    if (!timer_list->clock->enabled) {
 470        goto out;
 471    }
 472
 473    current_time = qemu_clock_get_ns(timer_list->clock->type);
 474    for(;;) {
 475        qemu_mutex_lock(&timer_list->active_timers_lock);
 476        ts = timer_list->active_timers;
 477        if (!timer_expired_ns(ts, current_time)) {
 478            qemu_mutex_unlock(&timer_list->active_timers_lock);
 479            break;
 480        }
 481
 482        /* remove timer from the list before calling the callback */
 483        timer_list->active_timers = ts->next;
 484        ts->next = NULL;
 485        ts->expire_time = -1;
 486        cb = ts->cb;
 487        opaque = ts->opaque;
 488        qemu_mutex_unlock(&timer_list->active_timers_lock);
 489
 490        /* run the callback (the timer list can be modified) */
 491        cb(opaque);
 492        progress = true;
 493    }
 494
 495out:
 496    qemu_event_set(&timer_list->timers_done_ev);
 497    return progress;
 498}
 499
 500bool qemu_clock_run_timers(QEMUClockType type)
 501{
 502    return timerlist_run_timers(main_loop_tlg.tl[type]);
 503}
 504
 505void timerlistgroup_init(QEMUTimerListGroup *tlg,
 506                         QEMUTimerListNotifyCB *cb, void *opaque)
 507{
 508    QEMUClockType type;
 509    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 510        tlg->tl[type] = timerlist_new(type, cb, opaque);
 511    }
 512}
 513
 514void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
 515{
 516    QEMUClockType type;
 517    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 518        timerlist_free(tlg->tl[type]);
 519    }
 520}
 521
 522bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
 523{
 524    QEMUClockType type;
 525    bool progress = false;
 526    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 527        progress |= timerlist_run_timers(tlg->tl[type]);
 528    }
 529    return progress;
 530}
 531
 532int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
 533{
 534    int64_t deadline = -1;
 535    QEMUClockType type;
 536    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 537        if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
 538            deadline = qemu_soonest_timeout(deadline,
 539                                            timerlist_deadline_ns(
 540                                                tlg->tl[type]));
 541        }
 542    }
 543    return deadline;
 544}
 545
 546int64_t qemu_clock_get_ns(QEMUClockType type)
 547{
 548    int64_t now, last;
 549    QEMUClock *clock = qemu_clock_ptr(type);
 550
 551    switch (type) {
 552    case QEMU_CLOCK_REALTIME:
 553        return get_clock();
 554    default:
 555    case QEMU_CLOCK_VIRTUAL:
 556        if (use_icount) {
 557            return cpu_get_icount();
 558        } else {
 559            return cpu_get_clock();
 560        }
 561    case QEMU_CLOCK_HOST:
 562        now = get_clock_realtime();
 563        last = clock->last;
 564        clock->last = now;
 565        if (now < last) {
 566            notifier_list_notify(&clock->reset_notifiers, &now);
 567        }
 568        return now;
 569    }
 570}
 571
 572void qemu_clock_register_reset_notifier(QEMUClockType type,
 573                                        Notifier *notifier)
 574{
 575    QEMUClock *clock = qemu_clock_ptr(type);
 576    notifier_list_add(&clock->reset_notifiers, notifier);
 577}
 578
 579void qemu_clock_unregister_reset_notifier(QEMUClockType type,
 580                                          Notifier *notifier)
 581{
 582    notifier_remove(notifier);
 583}
 584
 585void init_clocks(void)
 586{
 587    QEMUClockType type;
 588    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 589        qemu_clock_init(type);
 590    }
 591
 592#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
 593    prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
 594#endif
 595}
 596
 597uint64_t timer_expire_time_ns(QEMUTimer *ts)
 598{
 599    return timer_pending(ts) ? ts->expire_time : -1;
 600}
 601
 602bool qemu_clock_run_all_timers(void)
 603{
 604    bool progress = false;
 605    QEMUClockType type;
 606
 607    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
 608        progress |= qemu_clock_run_timers(type);
 609    }
 610
 611    return progress;
 612}
 613