qemu-timer.c 17.3 KB
Newer Older
Paolo Bonzini's avatar
Paolo Bonzini committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU System Emulator
 *
 * Copyright (c) 2003-2008 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

Peter Maydell's avatar
Peter Maydell committed
25
#include "qemu/osdep.h"
26
#include "qemu/main-loop.h"
27
#include "qemu/timer.h"
28
#include "sysemu/replay.h"
Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
29
#include "sysemu/sysemu.h"
30

31 32 33
#ifdef CONFIG_POSIX
#include <pthread.h>
#endif
34

35 36 37 38
#ifdef CONFIG_PPOLL
#include <poll.h>
#endif

39 40 41 42
#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
#include <sys/prctl.h>
#endif

Paolo Bonzini's avatar
Paolo Bonzini committed
43 44 45
/***********************************************************/
/* timers */

46
typedef struct QEMUClock {
47
    /* We rely on BQL to protect the timerlists */
48
    QLIST_HEAD(, QEMUTimerList) timerlists;
49 50 51

    NotifierList reset_notifiers;
    int64_t last;
52

53
    QEMUClockType type;
54
    bool enabled;
55
} QEMUClock;
Paolo Bonzini's avatar
Paolo Bonzini committed
56

57
QEMUTimerListGroup main_loop_tlg;
58
static QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
59 60 61 62 63 64 65 66 67

/* A QEMUTimerList is a list of timers attached to a clock. More
 * than one QEMUTimerList can be attached to each clock, for instance
 * used by different AioContexts / threads. Each clock also has
 * a list of the QEMUTimerLists associated with it, in order that
 * reenabling the clock can call all the notifiers.
 */

struct QEMUTimerList {
68
    QEMUClock *clock;
69
    QemuMutex active_timers_lock;
70 71
    QEMUTimer *active_timers;
    QLIST_ENTRY(QEMUTimerList) list;
72 73
    QEMUTimerListNotifyCB *notify_cb;
    void *notify_opaque;
74 75 76

    /* lightweight method to mark the end of timerlist's running */
    QemuEvent timers_done_ev;
Paolo Bonzini's avatar
Paolo Bonzini committed
77 78
};

79 80 81 82 83 84 85 86
/**
 * qemu_clock_ptr:
 * @type: type of clock
 *
 * Translate a clock type into a pointer to QEMUClock object.
 *
 * Returns: a pointer to the QEMUClock object
 */
87
static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
88 89 90 91
{
    return &qemu_clocks[type];
}

92
static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
93 94 95 96
{
    return timer_head && (timer_head->expire_time <= current_time);
}

97 98 99
QEMUTimerList *timerlist_new(QEMUClockType type,
                             QEMUTimerListNotifyCB *cb,
                             void *opaque)
100 101
{
    QEMUTimerList *timer_list;
102
    QEMUClock *clock = qemu_clock_ptr(type);
103 104

    timer_list = g_malloc0(sizeof(QEMUTimerList));
105
    qemu_event_init(&timer_list->timers_done_ev, true);
106
    timer_list->clock = clock;
107 108
    timer_list->notify_cb = cb;
    timer_list->notify_opaque = opaque;
109
    qemu_mutex_init(&timer_list->active_timers_lock);
110 111 112 113 114 115 116 117 118 119
    QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
    return timer_list;
}

void timerlist_free(QEMUTimerList *timer_list)
{
    assert(!timerlist_has_timers(timer_list));
    if (timer_list->clock) {
        QLIST_REMOVE(timer_list, list);
    }
120
    qemu_mutex_destroy(&timer_list->active_timers_lock);
121 122 123
    g_free(timer_list);
}

124
static void qemu_clock_init(QEMUClockType type)
Paolo Bonzini's avatar
Paolo Bonzini committed
125
{
126
    QEMUClock *clock = qemu_clock_ptr(type);
127

128 129 130
    /* Assert that the clock of type TYPE has not been initialized yet. */
    assert(main_loop_tlg.tl[type] == NULL);

Paolo Bonzini's avatar
Paolo Bonzini committed
131
    clock->type = type;
132
    clock->enabled = true;
133
    clock->last = INT64_MIN;
134
    QLIST_INIT(&clock->timerlists);
135
    notifier_list_init(&clock->reset_notifiers);
136
    main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
Paolo Bonzini's avatar
Paolo Bonzini committed
137 138
}

139
bool qemu_clock_use_for_deadline(QEMUClockType type)
140
{
141
    return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
142 143
}

144
void qemu_clock_notify(QEMUClockType type)
145 146
{
    QEMUTimerList *timer_list;
147
    QEMUClock *clock = qemu_clock_ptr(type);
148 149 150 151 152
    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
        timerlist_notify(timer_list);
    }
}

153 154 155 156 157 158 159
/* Disabling the clock will wait for related timerlists to stop
 * executing qemu_run_timers.  Thus, this functions should not
 * be used from the callback of a timer that is based on @clock.
 * Doing so would cause a deadlock.
 *
 * Caller should hold BQL.
 */
160
void qemu_clock_enable(QEMUClockType type, bool enabled)
Paolo Bonzini's avatar
Paolo Bonzini committed
161
{
162
    QEMUClock *clock = qemu_clock_ptr(type);
163
    QEMUTimerList *tl;
164
    bool old = clock->enabled;
Paolo Bonzini's avatar
Paolo Bonzini committed
165
    clock->enabled = enabled;
166
    if (enabled && !old) {
167
        qemu_clock_notify(type);
168 169 170 171
    } else if (!enabled && old) {
        QLIST_FOREACH(tl, &clock->timerlists, list) {
            qemu_event_wait(&tl->timers_done_ev);
        }
172
    }
Paolo Bonzini's avatar
Paolo Bonzini committed
173 174
}

175
bool timerlist_has_timers(QEMUTimerList *timer_list)
176
{
177
    return !!timer_list->active_timers;
178 179
}

180
bool qemu_clock_has_timers(QEMUClockType type)
181
{
182
    return timerlist_has_timers(
183
        main_loop_tlg.tl[type]);
184 185
}

186 187
bool timerlist_expired(QEMUTimerList *timer_list)
{
188 189 190 191 192 193 194 195 196 197 198
    int64_t expire_time;

    qemu_mutex_lock(&timer_list->active_timers_lock);
    if (!timer_list->active_timers) {
        qemu_mutex_unlock(&timer_list->active_timers_lock);
        return false;
    }
    expire_time = timer_list->active_timers->expire_time;
    qemu_mutex_unlock(&timer_list->active_timers_lock);

    return expire_time < qemu_clock_get_ns(timer_list->clock->type);
199 200
}

201
bool qemu_clock_expired(QEMUClockType type)
202
{
203
    return timerlist_expired(
204
        main_loop_tlg.tl[type]);
205 206
}

207 208 209 210 211
/*
 * As above, but return -1 for no deadline, and do not cap to 2^32
 * as we know the result is always positive.
 */

212
int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
213 214
{
    int64_t delta;
215
    int64_t expire_time;
216

217
    if (!timer_list->clock->enabled) {
218 219 220
        return -1;
    }

221 222 223 224 225 226 227 228 229 230 231 232 233
    /* The active timers list may be modified before the caller uses our return
     * value but ->notify_cb() is called when the deadline changes.  Therefore
     * the caller should notice the change and there is no race condition.
     */
    qemu_mutex_lock(&timer_list->active_timers_lock);
    if (!timer_list->active_timers) {
        qemu_mutex_unlock(&timer_list->active_timers_lock);
        return -1;
    }
    expire_time = timer_list->active_timers->expire_time;
    qemu_mutex_unlock(&timer_list->active_timers_lock);

    delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
234 235 236 237 238 239 240 241

    if (delta <= 0) {
        return 0;
    }

    return delta;
}

242 243 244 245 246
/* Calculate the soonest deadline across all timerlists attached
 * to the clock. This is used for the icount timeout so we
 * ignore whether or not the clock should be used in deadline
 * calculations.
 */
247
int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
248 249 250
{
    int64_t deadline = -1;
    QEMUTimerList *timer_list;
251
    QEMUClock *clock = qemu_clock_ptr(type);
252 253 254 255 256 257 258
    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
        deadline = qemu_soonest_timeout(deadline,
                                        timerlist_deadline_ns(timer_list));
    }
    return deadline;
}

259
QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
260
{
261
    return timer_list->clock->type;
262 263
}

264
QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
265
{
266
    return main_loop_tlg.tl[type];
267 268
}

269 270 271 272 273 274 275 276 277
void timerlist_notify(QEMUTimerList *timer_list)
{
    if (timer_list->notify_cb) {
        timer_list->notify_cb(timer_list->notify_opaque);
    } else {
        qemu_notify_event();
    }
}

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
/* Transition function to convert a nanosecond timeout to ms
 * This is used where a system does not support ppoll
 */
int qemu_timeout_ns_to_ms(int64_t ns)
{
    int64_t ms;
    if (ns < 0) {
        return -1;
    }

    if (!ns) {
        return 0;
    }

    /* Always round up, because it's better to wait too long than to wait too
     * little and effectively busy-wait
     */
295
    ms = DIV_ROUND_UP(ns, SCALE_MS);
296 297 298 299 300 301 302 303 304 305

    /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
    if (ms > (int64_t) INT32_MAX) {
        ms = INT32_MAX;
    }

    return (int) ms;
}


306 307 308 309 310 311 312 313 314 315
/* qemu implementation of g_poll which uses a nanosecond timeout but is
 * otherwise identical to g_poll
 */
int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
{
#ifdef CONFIG_PPOLL
    if (timeout < 0) {
        return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
    } else {
        struct timespec ts;
316 317 318 319 320 321 322 323
        int64_t tvsec = timeout / 1000000000LL;
        /* Avoid possibly overflowing and specifying a negative number of
         * seconds, which would turn a very long timeout into a busy-wait.
         */
        if (tvsec > (int64_t)INT32_MAX) {
            tvsec = INT32_MAX;
        }
        ts.tv_sec = tvsec;
324 325 326 327 328 329 330 331 332
        ts.tv_nsec = timeout % 1000000000LL;
        return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
    }
#else
    return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
#endif
}


333 334 335
void timer_init_tl(QEMUTimer *ts,
                   QEMUTimerList *timer_list, int scale,
                   QEMUTimerCB *cb, void *opaque)
Paolo Bonzini's avatar
Paolo Bonzini committed
336
{
337
    ts->timer_list = timer_list;
Paolo Bonzini's avatar
Paolo Bonzini committed
338 339
    ts->cb = cb;
    ts->opaque = opaque;
340
    ts->scale = scale;
341
    ts->expire_time = -1;
342 343
}

344 345 346 347 348 349
void timer_deinit(QEMUTimer *ts)
{
    assert(ts->expire_time == -1);
    ts->timer_list = NULL;
}

350
void timer_free(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
351
{
352
    g_free(ts);
Paolo Bonzini's avatar
Paolo Bonzini committed
353 354
}

355
static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
356 357 358
{
    QEMUTimer **pt, *t;

359
    ts->expire_time = -1;
360
    pt = &timer_list->active_timers;
Paolo Bonzini's avatar
Paolo Bonzini committed
361 362 363 364 365 366 367 368 369 370 371 372
    for(;;) {
        t = *pt;
        if (!t)
            break;
        if (t == ts) {
            *pt = t->next;
            break;
        }
        pt = &t->next;
    }
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
                                QEMUTimer *ts, int64_t expire_time)
{
    QEMUTimer **pt, *t;

    /* add the timer in the sorted list */
    pt = &timer_list->active_timers;
    for (;;) {
        t = *pt;
        if (!timer_expired_ns(t, expire_time)) {
            break;
        }
        pt = &t->next;
    }
    ts->expire_time = MAX(expire_time, 0);
    ts->next = *pt;
    *pt = ts;

    return pt == &timer_list->active_timers;
}

static void timerlist_rearm(QEMUTimerList *timer_list)
{
    /* Interrupt execution to force deadline recalculation.  */
397 398 399
    if (timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
        qemu_start_warp_timer();
    }
400 401 402
    timerlist_notify(timer_list);
}

403 404 405 406 407
/* stop a timer, but do not dealloc it */
void timer_del(QEMUTimer *ts)
{
    QEMUTimerList *timer_list = ts->timer_list;

408 409 410 411 412
    if (timer_list) {
        qemu_mutex_lock(&timer_list->active_timers_lock);
        timer_del_locked(timer_list, ts);
        qemu_mutex_unlock(&timer_list->active_timers_lock);
    }
413 414
}

Paolo Bonzini's avatar
Paolo Bonzini committed
415 416
/* modify the current timer so that it will be fired when current_time
   >= expire_time. The corresponding callback will be called. */
417
void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
Paolo Bonzini's avatar
Paolo Bonzini committed
418
{
419
    QEMUTimerList *timer_list = ts->timer_list;
420
    bool rearm;
Paolo Bonzini's avatar
Paolo Bonzini committed
421

422 423
    qemu_mutex_lock(&timer_list->active_timers_lock);
    timer_del_locked(timer_list, ts);
424
    rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
425
    qemu_mutex_unlock(&timer_list->active_timers_lock);
Paolo Bonzini's avatar
Paolo Bonzini committed
426

427 428
    if (rearm) {
        timerlist_rearm(timer_list);
Paolo Bonzini's avatar
Paolo Bonzini committed
429 430 431
    }
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/* modify the current timer so that it will be fired when current_time
   >= expire_time or the current deadline, whichever comes earlier.
   The corresponding callback will be called. */
void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
{
    QEMUTimerList *timer_list = ts->timer_list;
    bool rearm;

    qemu_mutex_lock(&timer_list->active_timers_lock);
    if (ts->expire_time == -1 || ts->expire_time > expire_time) {
        if (ts->expire_time != -1) {
            timer_del_locked(timer_list, ts);
        }
        rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
    } else {
        rearm = false;
    }
    qemu_mutex_unlock(&timer_list->active_timers_lock);

    if (rearm) {
        timerlist_rearm(timer_list);
    }
}

456
void timer_mod(QEMUTimer *ts, int64_t expire_time)
457
{
458
    timer_mod_ns(ts, expire_time * ts->scale);
459 460
}

461 462 463 464 465
void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
{
    timer_mod_anticipate_ns(ts, expire_time * ts->scale);
}

466
bool timer_pending(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
467
{
468
    return ts->expire_time >= 0;
Paolo Bonzini's avatar
Paolo Bonzini committed
469 470
}

471
bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
Paolo Bonzini's avatar
Paolo Bonzini committed
472
{
473
    return timer_expired_ns(timer_head, current_time * timer_head->scale);
Paolo Bonzini's avatar
Paolo Bonzini committed
474 475
}

476
bool timerlist_run_timers(QEMUTimerList *timer_list)
Paolo Bonzini's avatar
Paolo Bonzini committed
477
{
478
    QEMUTimer *ts;
Paolo Bonzini's avatar
Paolo Bonzini committed
479
    int64_t current_time;
480
    bool progress = false;
481 482 483
    QEMUTimerCB *cb;
    void *opaque;

484
    qemu_event_reset(&timer_list->timers_done_ev);
Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
485
    if (!timer_list->clock->enabled || !timer_list->active_timers) {
486
        goto out;
487
    }
Paolo Bonzini's avatar
Paolo Bonzini committed
488

Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
    switch (timer_list->clock->type) {
    case QEMU_CLOCK_REALTIME:
        break;
    default:
    case QEMU_CLOCK_VIRTUAL:
        if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
            goto out;
        }
        break;
    case QEMU_CLOCK_HOST:
        if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
            goto out;
        }
        break;
    case QEMU_CLOCK_VIRTUAL_RT:
        if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) {
            goto out;
        }
        break;
    }

510
    current_time = qemu_clock_get_ns(timer_list->clock->type);
Paolo Bonzini's avatar
Paolo Bonzini committed
511
    for(;;) {
512
        qemu_mutex_lock(&timer_list->active_timers_lock);
513
        ts = timer_list->active_timers;
514
        if (!timer_expired_ns(ts, current_time)) {
515
            qemu_mutex_unlock(&timer_list->active_timers_lock);
Paolo Bonzini's avatar
Paolo Bonzini committed
516
            break;
517
        }
518

Paolo Bonzini's avatar
Paolo Bonzini committed
519
        /* remove timer from the list before calling the callback */
520
        timer_list->active_timers = ts->next;
Paolo Bonzini's avatar
Paolo Bonzini committed
521
        ts->next = NULL;
522
        ts->expire_time = -1;
523 524 525
        cb = ts->cb;
        opaque = ts->opaque;
        qemu_mutex_unlock(&timer_list->active_timers_lock);
Paolo Bonzini's avatar
Paolo Bonzini committed
526 527

        /* run the callback (the timer list can be modified) */
528
        cb(opaque);
529
        progress = true;
Paolo Bonzini's avatar
Paolo Bonzini committed
530
    }
531 532 533

out:
    qemu_event_set(&timer_list->timers_done_ev);
534
    return progress;
Paolo Bonzini's avatar
Paolo Bonzini committed
535 536
}

537 538
bool qemu_clock_run_timers(QEMUClockType type)
{
539
    return timerlist_run_timers(main_loop_tlg.tl[type]);
540 541
}

542 543
void timerlistgroup_init(QEMUTimerListGroup *tlg,
                         QEMUTimerListNotifyCB *cb, void *opaque)
544 545 546
{
    QEMUClockType type;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
547
        tlg->tl[type] = timerlist_new(type, cb, opaque);
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
    }
}

void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
{
    QEMUClockType type;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
        timerlist_free(tlg->tl[type]);
    }
}

bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
{
    QEMUClockType type;
    bool progress = false;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
        progress |= timerlist_run_timers(tlg->tl[type]);
    }
    return progress;
}

int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
{
    int64_t deadline = -1;
    QEMUClockType type;
Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
573
    bool play = replay_mode == REPLAY_MODE_PLAY;
574
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
575 576 577 578 579 580 581 582 583
        if (qemu_clock_use_for_deadline(type)) {
            if (!play || type == QEMU_CLOCK_REALTIME) {
                deadline = qemu_soonest_timeout(deadline,
                                                timerlist_deadline_ns(tlg->tl[type]));
            } else {
                /* Read clock from the replay file and
                   do not calculate the deadline, based on virtual clock. */
                qemu_clock_get_ns(type);
            }
584 585 586 587 588
        }
    }
    return deadline;
}

589
int64_t qemu_clock_get_ns(QEMUClockType type)
Paolo Bonzini's avatar
Paolo Bonzini committed
590
{
591
    int64_t now, last;
592
    QEMUClock *clock = qemu_clock_ptr(type);
593

594
    switch (type) {
Paolo Bonzini's avatar
Paolo Bonzini committed
595 596 597 598 599 600 601 602 603 604
    case QEMU_CLOCK_REALTIME:
        return get_clock();
    default:
    case QEMU_CLOCK_VIRTUAL:
        if (use_icount) {
            return cpu_get_icount();
        } else {
            return cpu_get_clock();
        }
    case QEMU_CLOCK_HOST:
605
        now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
606 607
        last = clock->last;
        clock->last = now;
Pavel Dovgalyuk's avatar
Pavel Dovgalyuk committed
608
        if (now < last || now > (last + get_max_clock_jump())) {
609 610 611
            notifier_list_notify(&clock->reset_notifiers, &now);
        }
        return now;
612
    case QEMU_CLOCK_VIRTUAL_RT:
613
        return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
Paolo Bonzini's avatar
Paolo Bonzini committed
614 615 616
    }
}

617 618 619 620
void qemu_clock_register_reset_notifier(QEMUClockType type,
                                        Notifier *notifier)
{
    QEMUClock *clock = qemu_clock_ptr(type);
621 622 623
    notifier_list_add(&clock->reset_notifiers, notifier);
}

624 625
void qemu_clock_unregister_reset_notifier(QEMUClockType type,
                                          Notifier *notifier)
626
{
627
    notifier_remove(notifier);
628 629
}

Paolo Bonzini's avatar
Paolo Bonzini committed
630 631
void init_clocks(void)
{
632 633
    QEMUClockType type;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
634
        qemu_clock_init(type);
635
    }
636

637 638 639
#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
    prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
#endif
Paolo Bonzini's avatar
Paolo Bonzini committed
640 641
}

642
uint64_t timer_expire_time_ns(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
643
{
644
    return timer_pending(ts) ? ts->expire_time : -1;
Paolo Bonzini's avatar
Paolo Bonzini committed
645 646
}

647
bool qemu_clock_run_all_timers(void)
Paolo Bonzini's avatar
Paolo Bonzini committed
648
{
649
    bool progress = false;
650
    QEMUClockType type;
651

652
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
653
        progress |= qemu_clock_run_timers(type);
654
    }
655

656
    return progress;
Paolo Bonzini's avatar
Paolo Bonzini committed
657
}