qemu-timer.c 15.9 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.
 */

25
#include "sysemu/sysemu.h"
26
#include "monitor/monitor.h"
27
#include "ui/console.h"
Paolo Bonzini's avatar
Paolo Bonzini committed
28 29 30

#include "hw/hw.h"

31
#include "qemu/timer.h"
32 33 34
#ifdef CONFIG_POSIX
#include <pthread.h>
#endif
35

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

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

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

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

    NotifierList reset_notifiers;
    int64_t last;
53

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

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

/* 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 {
69
    QEMUClock *clock;
70
    QemuMutex active_timers_lock;
71 72
    QEMUTimer *active_timers;
    QLIST_ENTRY(QEMUTimerList) list;
73 74
    QEMUTimerListNotifyCB *notify_cb;
    void *notify_opaque;
75 76 77

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

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

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

98 99 100
QEMUTimerList *timerlist_new(QEMUClockType type,
                             QEMUTimerListNotifyCB *cb,
                             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 109
    timer_list->notify_cb = cb;
    timer_list->notify_opaque = opaque;
110
    qemu_mutex_init(&timer_list->active_timers_lock);
111 112 113 114 115 116 117 118 119 120
    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);
    }
121
    qemu_mutex_destroy(&timer_list->active_timers_lock);
122 123 124
    g_free(timer_list);
}

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

129 130 131
    /* 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
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);
Paolo Bonzini's avatar
Paolo Bonzini committed
138 139
}

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

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

154 155 156 157 158 159 160
/* 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.
 */
161
void qemu_clock_enable(QEMUClockType type, bool enabled)
Paolo Bonzini's avatar
Paolo Bonzini committed
162
{
163
    QEMUClock *clock = qemu_clock_ptr(type);
164
    QEMUTimerList *tl;
165
    bool old = clock->enabled;
Paolo Bonzini's avatar
Paolo Bonzini committed
166
    clock->enabled = enabled;
167
    if (enabled && !old) {
168
        qemu_clock_notify(type);
169 170 171 172
    } else if (!enabled && old) {
        QLIST_FOREACH(tl, &clock->timerlists, list) {
            qemu_event_wait(&tl->timers_done_ev);
        }
173
    }
Paolo Bonzini's avatar
Paolo Bonzini committed
174 175
}

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

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

187 188
bool timerlist_expired(QEMUTimerList *timer_list)
{
189 190 191 192 193 194 195 196 197 198 199
    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);
200 201
}

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

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

213
int64_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 220 221
        return -1;
    }

222 223 224 225 226 227 228 229 230 231 232 233 234
    /* 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);
235 236 237 238 239 240 241 242

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

    return delta;
}

243 244 245 246 247
/* 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.
 */
248
int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
249 250 251
{
    int64_t deadline = -1;
    QEMUTimerList *timer_list;
252
    QEMUClock *clock = qemu_clock_ptr(type);
253 254 255 256 257 258 259
    QLIST_FOREACH(timer_list, &clock->timerlists, list) {
        deadline = qemu_soonest_timeout(deadline,
                                        timerlist_deadline_ns(timer_list));
    }
    return deadline;
}

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

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

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

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
/* 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
     */
    ms = (ns + SCALE_MS - 1) / SCALE_MS;

    /* 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;
}


307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
/* 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;
        ts.tv_sec = timeout / 1000000000LL;
        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
}


327 328 329
void timer_init(QEMUTimer *ts,
                QEMUTimerList *timer_list, int scale,
                QEMUTimerCB *cb, void *opaque)
Paolo Bonzini's avatar
Paolo Bonzini committed
330
{
331
    ts->timer_list = timer_list;
Paolo Bonzini's avatar
Paolo Bonzini committed
332 333
    ts->cb = cb;
    ts->opaque = opaque;
334
    ts->scale = scale;
335
    ts->expire_time = -1;
336 337
}

338
void timer_free(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
339
{
340
    g_free(ts);
Paolo Bonzini's avatar
Paolo Bonzini committed
341 342
}

343
static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
344 345 346
{
    QEMUTimer **pt, *t;

347
    ts->expire_time = -1;
348
    pt = &timer_list->active_timers;
Paolo Bonzini's avatar
Paolo Bonzini committed
349 350 351 352 353 354 355 356 357 358 359 360
    for(;;) {
        t = *pt;
        if (!t)
            break;
        if (t == ts) {
            *pt = t->next;
            break;
        }
        pt = &t->next;
    }
}

361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
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.  */
    qemu_clock_warp(timer_list->clock->type);
    timerlist_notify(timer_list);
}

389 390 391 392 393 394 395 396 397 398
/* stop a timer, but do not dealloc it */
void timer_del(QEMUTimer *ts)
{
    QEMUTimerList *timer_list = ts->timer_list;

    qemu_mutex_lock(&timer_list->active_timers_lock);
    timer_del_locked(timer_list, ts);
    qemu_mutex_unlock(&timer_list->active_timers_lock);
}

Paolo Bonzini's avatar
Paolo Bonzini committed
399 400
/* modify the current timer so that it will be fired when current_time
   >= expire_time. The corresponding callback will be called. */
401
void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
Paolo Bonzini's avatar
Paolo Bonzini committed
402
{
403
    QEMUTimerList *timer_list = ts->timer_list;
404
    bool rearm;
Paolo Bonzini's avatar
Paolo Bonzini committed
405

406 407
    qemu_mutex_lock(&timer_list->active_timers_lock);
    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);
Paolo Bonzini's avatar
Paolo Bonzini committed
410

411 412
    if (rearm) {
        timerlist_rearm(timer_list);
Paolo Bonzini's avatar
Paolo Bonzini committed
413 414 415
    }
}

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/* 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);
    }
}

440
void timer_mod(QEMUTimer *ts, int64_t expire_time)
441
{
442
    timer_mod_ns(ts, expire_time * ts->scale);
443 444
}

445 446 447 448 449
void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
{
    timer_mod_anticipate_ns(ts, expire_time * ts->scale);
}

450
bool timer_pending(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
451
{
452
    return ts->expire_time >= 0;
Paolo Bonzini's avatar
Paolo Bonzini committed
453 454
}

455
bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
Paolo Bonzini's avatar
Paolo Bonzini committed
456
{
457
    return timer_expired_ns(timer_head, current_time * timer_head->scale);
Paolo Bonzini's avatar
Paolo Bonzini committed
458 459
}

460
bool timerlist_run_timers(QEMUTimerList *timer_list)
Paolo Bonzini's avatar
Paolo Bonzini committed
461
{
462
    QEMUTimer *ts;
Paolo Bonzini's avatar
Paolo Bonzini committed
463
    int64_t current_time;
464
    bool progress = false;
465 466 467
    QEMUTimerCB *cb;
    void *opaque;

468
    qemu_event_reset(&timer_list->timers_done_ev);
469
    if (!timer_list->clock->enabled) {
470
        goto out;
471
    }
Paolo Bonzini's avatar
Paolo Bonzini committed
472

473
    current_time = qemu_clock_get_ns(timer_list->clock->type);
Paolo Bonzini's avatar
Paolo Bonzini committed
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);
Paolo Bonzini's avatar
Paolo Bonzini committed
479
            break;
480
        }
481

Paolo Bonzini's avatar
Paolo Bonzini committed
482
        /* remove timer from the list before calling the callback */
483
        timer_list->active_timers = ts->next;
Paolo Bonzini's avatar
Paolo Bonzini committed
484
        ts->next = NULL;
485
        ts->expire_time = -1;
486 487 488
        cb = ts->cb;
        opaque = ts->opaque;
        qemu_mutex_unlock(&timer_list->active_timers_lock);
Paolo Bonzini's avatar
Paolo Bonzini committed
489 490

        /* run the callback (the timer list can be modified) */
491
        cb(opaque);
492
        progress = true;
Paolo Bonzini's avatar
Paolo Bonzini committed
493
    }
494 495 496

out:
    qemu_event_set(&timer_list->timers_done_ev);
497
    return progress;
Paolo Bonzini's avatar
Paolo Bonzini committed
498 499
}

500 501
bool qemu_clock_run_timers(QEMUClockType type)
{
502
    return timerlist_run_timers(main_loop_tlg.tl[type]);
503 504
}

505 506
void timerlistgroup_init(QEMUTimerListGroup *tlg,
                         QEMUTimerListNotifyCB *cb, void *opaque)
507 508 509
{
    QEMUClockType type;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
510
        tlg->tl[type] = timerlist_new(type, cb, opaque);
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
    }
}

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;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
537
        if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
538 539 540 541 542 543 544 545
            deadline = qemu_soonest_timeout(deadline,
                                            timerlist_deadline_ns(
                                                tlg->tl[type]));
        }
    }
    return deadline;
}

546
int64_t qemu_clock_get_ns(QEMUClockType type)
Paolo Bonzini's avatar
Paolo Bonzini committed
547
{
548
    int64_t now, last;
549
    QEMUClock *clock = qemu_clock_ptr(type);
550

551
    switch (type) {
Paolo Bonzini's avatar
Paolo Bonzini committed
552 553 554 555 556 557 558 559 560 561
    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:
562 563 564 565 566 567 568
        now = get_clock_realtime();
        last = clock->last;
        clock->last = now;
        if (now < last) {
            notifier_list_notify(&clock->reset_notifiers, &now);
        }
        return now;
Paolo Bonzini's avatar
Paolo Bonzini committed
569 570 571
    }
}

572 573 574 575
void qemu_clock_register_reset_notifier(QEMUClockType type,
                                        Notifier *notifier)
{
    QEMUClock *clock = qemu_clock_ptr(type);
576 577 578
    notifier_list_add(&clock->reset_notifiers, notifier);
}

579 580
void qemu_clock_unregister_reset_notifier(QEMUClockType type,
                                          Notifier *notifier)
581
{
582
    notifier_remove(notifier);
583 584
}

Paolo Bonzini's avatar
Paolo Bonzini committed
585 586
void init_clocks(void)
{
587 588
    QEMUClockType type;
    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
589
        qemu_clock_init(type);
590
    }
591

592 593 594
#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
    prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
#endif
Paolo Bonzini's avatar
Paolo Bonzini committed
595 596
}

597
uint64_t timer_expire_time_ns(QEMUTimer *ts)
Paolo Bonzini's avatar
Paolo Bonzini committed
598
{
599
    return timer_pending(ts) ? ts->expire_time : -1;
Paolo Bonzini's avatar
Paolo Bonzini committed
600 601
}

602
bool qemu_clock_run_all_timers(void)
Paolo Bonzini's avatar
Paolo Bonzini committed
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;
Paolo Bonzini's avatar
Paolo Bonzini committed
612
}