1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "qemu/main-loop.h"
27#include "qemu/timer.h"
28#include "sysemu/replay.h"
29#include "sysemu/sysemu.h"
30#include "sysemu/cpus.h"
31
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
46
47typedef struct QEMUClock {
48
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
62
63
64
65
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
77 QemuEvent timers_done_ev;
78};
79
80
81
82
83
84
85
86
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, true);
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, QEMUTimerListNotifyCB *notify_cb)
126{
127 QEMUClock *clock = qemu_clock_ptr(type);
128
129
130 assert(main_loop_tlg.tl[type] == NULL);
131
132 clock->type = type;
133 clock->enabled = (type == QEMU_CLOCK_VIRTUAL ? false : 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, notify_cb, 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
155
156
157
158
159
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 !!atomic_read(&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 if (!atomic_read(&timer_list->active_timers)) {
192 return false;
193 }
194
195 qemu_mutex_lock(&timer_list->active_timers_lock);
196 if (!timer_list->active_timers) {
197 qemu_mutex_unlock(&timer_list->active_timers_lock);
198 return false;
199 }
200 expire_time = timer_list->active_timers->expire_time;
201 qemu_mutex_unlock(&timer_list->active_timers_lock);
202
203 return expire_time <= qemu_clock_get_ns(timer_list->clock->type);
204}
205
206bool qemu_clock_expired(QEMUClockType type)
207{
208 return timerlist_expired(
209 main_loop_tlg.tl[type]);
210}
211
212
213
214
215
216
217int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
218{
219 int64_t delta;
220 int64_t expire_time;
221
222 if (!atomic_read(&timer_list->active_timers)) {
223 return -1;
224 }
225
226 if (!timer_list->clock->enabled) {
227 return -1;
228 }
229
230
231
232
233
234 qemu_mutex_lock(&timer_list->active_timers_lock);
235 if (!timer_list->active_timers) {
236 qemu_mutex_unlock(&timer_list->active_timers_lock);
237 return -1;
238 }
239 expire_time = timer_list->active_timers->expire_time;
240 qemu_mutex_unlock(&timer_list->active_timers_lock);
241
242 delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
243
244 if (delta <= 0) {
245 return 0;
246 }
247
248 return delta;
249}
250
251
252
253
254
255
256int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
257{
258 int64_t deadline = -1;
259 QEMUTimerList *timer_list;
260 QEMUClock *clock = qemu_clock_ptr(type);
261 QLIST_FOREACH(timer_list, &clock->timerlists, list) {
262 deadline = qemu_soonest_timeout(deadline,
263 timerlist_deadline_ns(timer_list));
264 }
265 return deadline;
266}
267
268QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
269{
270 return timer_list->clock->type;
271}
272
273QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
274{
275 return main_loop_tlg.tl[type];
276}
277
278void timerlist_notify(QEMUTimerList *timer_list)
279{
280 if (timer_list->notify_cb) {
281 timer_list->notify_cb(timer_list->notify_opaque, timer_list->clock->type);
282 } else {
283 qemu_notify_event();
284 }
285}
286
287
288
289
290int qemu_timeout_ns_to_ms(int64_t ns)
291{
292 int64_t ms;
293 if (ns < 0) {
294 return -1;
295 }
296
297 if (!ns) {
298 return 0;
299 }
300
301
302
303
304 ms = DIV_ROUND_UP(ns, SCALE_MS);
305
306
307 if (ms > (int64_t) INT32_MAX) {
308 ms = INT32_MAX;
309 }
310
311 return (int) ms;
312}
313
314
315
316
317
318int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
319{
320#ifdef CONFIG_PPOLL
321 if (timeout < 0) {
322 return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
323 } else {
324 struct timespec ts;
325 int64_t tvsec = timeout / 1000000000LL;
326
327
328
329 if (tvsec > (int64_t)INT32_MAX) {
330 tvsec = INT32_MAX;
331 }
332 ts.tv_sec = tvsec;
333 ts.tv_nsec = timeout % 1000000000LL;
334 return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
335 }
336#else
337 return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
338#endif
339}
340
341
342void timer_init_tl(QEMUTimer *ts,
343 QEMUTimerList *timer_list, int scale,
344 QEMUTimerCB *cb, void *opaque)
345{
346 ts->timer_list = timer_list;
347 ts->cb = cb;
348 ts->opaque = opaque;
349 ts->scale = scale;
350 ts->expire_time = -1;
351}
352
353void timer_deinit(QEMUTimer *ts)
354{
355 assert(ts->expire_time == -1);
356 ts->timer_list = NULL;
357}
358
359static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
360{
361 QEMUTimer **pt, *t;
362
363 ts->expire_time = -1;
364 pt = &timer_list->active_timers;
365 for(;;) {
366 t = *pt;
367 if (!t)
368 break;
369 if (t == ts) {
370 atomic_set(pt, t->next);
371 break;
372 }
373 pt = &t->next;
374 }
375}
376
377static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
378 QEMUTimer *ts, int64_t expire_time)
379{
380 QEMUTimer **pt, *t;
381
382
383 pt = &timer_list->active_timers;
384 for (;;) {
385 t = *pt;
386 if (!timer_expired_ns(t, expire_time)) {
387 break;
388 }
389 pt = &t->next;
390 }
391 ts->expire_time = MAX(expire_time, 0);
392 ts->next = *pt;
393 atomic_set(pt, ts);
394
395 return pt == &timer_list->active_timers;
396}
397
398static void timerlist_rearm(QEMUTimerList *timer_list)
399{
400
401 if (timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
402 qemu_start_warp_timer();
403 }
404 timerlist_notify(timer_list);
405}
406
407
408void timer_del(QEMUTimer *ts)
409{
410 QEMUTimerList *timer_list = ts->timer_list;
411
412 if (timer_list) {
413 qemu_mutex_lock(&timer_list->active_timers_lock);
414 timer_del_locked(timer_list, ts);
415 qemu_mutex_unlock(&timer_list->active_timers_lock);
416 }
417}
418
419
420
421void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
422{
423 QEMUTimerList *timer_list = ts->timer_list;
424 bool rearm;
425
426 qemu_mutex_lock(&timer_list->active_timers_lock);
427 timer_del_locked(timer_list, ts);
428 rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
429 qemu_mutex_unlock(&timer_list->active_timers_lock);
430
431 if (rearm) {
432 timerlist_rearm(timer_list);
433 }
434}
435
436
437
438
439void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
440{
441 QEMUTimerList *timer_list = ts->timer_list;
442 bool rearm;
443
444 qemu_mutex_lock(&timer_list->active_timers_lock);
445 if (ts->expire_time == -1 || ts->expire_time > expire_time) {
446 if (ts->expire_time != -1) {
447 timer_del_locked(timer_list, ts);
448 }
449 rearm = timer_mod_ns_locked(timer_list, ts, expire_time);
450 } else {
451 rearm = false;
452 }
453 qemu_mutex_unlock(&timer_list->active_timers_lock);
454
455 if (rearm) {
456 timerlist_rearm(timer_list);
457 }
458}
459
460void timer_mod(QEMUTimer *ts, int64_t expire_time)
461{
462 timer_mod_ns(ts, expire_time * ts->scale);
463}
464
465void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time)
466{
467 timer_mod_anticipate_ns(ts, expire_time * ts->scale);
468}
469
470bool timer_pending(QEMUTimer *ts)
471{
472 return ts->expire_time >= 0;
473}
474
475bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
476{
477 return timer_expired_ns(timer_head, current_time * timer_head->scale);
478}
479
480bool timerlist_run_timers(QEMUTimerList *timer_list)
481{
482 QEMUTimer *ts;
483 int64_t current_time;
484 bool progress = false;
485 QEMUTimerCB *cb;
486 void *opaque;
487
488 if (!atomic_read(&timer_list->active_timers)) {
489 return false;
490 }
491
492 qemu_event_reset(&timer_list->timers_done_ev);
493 if (!timer_list->clock->enabled) {
494 goto out;
495 }
496
497 switch (timer_list->clock->type) {
498 case QEMU_CLOCK_REALTIME:
499 break;
500 default:
501 case QEMU_CLOCK_VIRTUAL:
502 if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
503 goto out;
504 }
505 break;
506 case QEMU_CLOCK_HOST:
507 if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
508 goto out;
509 }
510 break;
511 case QEMU_CLOCK_VIRTUAL_RT:
512 if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) {
513 goto out;
514 }
515 break;
516 }
517
518 current_time = qemu_clock_get_ns(timer_list->clock->type);
519 for(;;) {
520 qemu_mutex_lock(&timer_list->active_timers_lock);
521 ts = timer_list->active_timers;
522 if (!timer_expired_ns(ts, current_time)) {
523 qemu_mutex_unlock(&timer_list->active_timers_lock);
524 break;
525 }
526
527
528 timer_list->active_timers = ts->next;
529 ts->next = NULL;
530 ts->expire_time = -1;
531 cb = ts->cb;
532 opaque = ts->opaque;
533 qemu_mutex_unlock(&timer_list->active_timers_lock);
534
535
536 cb(opaque);
537 progress = true;
538 }
539
540out:
541 qemu_event_set(&timer_list->timers_done_ev);
542 return progress;
543}
544
545bool qemu_clock_run_timers(QEMUClockType type)
546{
547 return timerlist_run_timers(main_loop_tlg.tl[type]);
548}
549
550void timerlistgroup_init(QEMUTimerListGroup *tlg,
551 QEMUTimerListNotifyCB *cb, void *opaque)
552{
553 QEMUClockType type;
554 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
555 tlg->tl[type] = timerlist_new(type, cb, opaque);
556 }
557}
558
559void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
560{
561 QEMUClockType type;
562 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
563 timerlist_free(tlg->tl[type]);
564 }
565}
566
567bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
568{
569 QEMUClockType type;
570 bool progress = false;
571 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
572 progress |= timerlist_run_timers(tlg->tl[type]);
573 }
574 return progress;
575}
576
577int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
578{
579 int64_t deadline = -1;
580 QEMUClockType type;
581 bool play = replay_mode == REPLAY_MODE_PLAY;
582 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
583 if (qemu_clock_use_for_deadline(type)) {
584 if (!play || type == QEMU_CLOCK_REALTIME) {
585 deadline = qemu_soonest_timeout(deadline,
586 timerlist_deadline_ns(tlg->tl[type]));
587 } else {
588
589
590 qemu_clock_get_ns(type);
591 }
592 }
593 }
594 return deadline;
595}
596
597int64_t qemu_clock_get_ns(QEMUClockType type)
598{
599 int64_t now, last;
600 QEMUClock *clock = qemu_clock_ptr(type);
601
602 switch (type) {
603 case QEMU_CLOCK_REALTIME:
604 return get_clock();
605 default:
606 case QEMU_CLOCK_VIRTUAL:
607 if (use_icount) {
608 return cpu_get_icount();
609 } else {
610 return cpu_get_clock();
611 }
612 case QEMU_CLOCK_HOST:
613 now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
614 last = clock->last;
615 clock->last = now;
616 if (now < last || now > (last + get_max_clock_jump())) {
617 notifier_list_notify(&clock->reset_notifiers, &now);
618 }
619 return now;
620 case QEMU_CLOCK_VIRTUAL_RT:
621 return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
622 }
623}
624
625void qemu_clock_register_reset_notifier(QEMUClockType type,
626 Notifier *notifier)
627{
628 QEMUClock *clock = qemu_clock_ptr(type);
629 notifier_list_add(&clock->reset_notifiers, notifier);
630}
631
632void qemu_clock_unregister_reset_notifier(QEMUClockType type,
633 Notifier *notifier)
634{
635 notifier_remove(notifier);
636}
637
638void init_clocks(QEMUTimerListNotifyCB *notify_cb)
639{
640 QEMUClockType type;
641 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
642 qemu_clock_init(type, notify_cb);
643 }
644
645#ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
646 prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
647#endif
648}
649
650uint64_t timer_expire_time_ns(QEMUTimer *ts)
651{
652 return timer_pending(ts) ? ts->expire_time : -1;
653}
654
655bool qemu_clock_run_all_timers(void)
656{
657 bool progress = false;
658 QEMUClockType type;
659
660 for (type = 0; type < QEMU_CLOCK_MAX; type++) {
661 if (qemu_clock_use_for_deadline(type)) {
662 progress |= qemu_clock_run_timers(type);
663 }
664 }
665
666 return progress;
667}
668