blob: ae855092d36b223140878675a0aae64093ff338d [file] [log] [blame]
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +02001/*
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-timer.h"
26#include "console.h"
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +020027#include "android/utils/system.h"
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020028
29extern QEMUClock* rtc_clock;
30
31#include <unistd.h>
32#include <fcntl.h>
33#include <time.h>
34#include <errno.h>
35#include <sys/time.h>
36#include <signal.h>
37#ifdef __FreeBSD__
38#include <sys/param.h>
39#endif
40
41#ifdef __linux__
42#include <sys/ioctl.h>
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020043#endif
44
45#ifdef _WIN32
46#include <windows.h>
47#include <mmsystem.h>
48#endif
49
50#include "qemu-timer.h"
51
52/***********************************************************/
53/* real time host monotonic timer */
54
55
56static int64_t get_clock_realtime(void)
57{
58 struct timeval tv;
59
60 gettimeofday(&tv, NULL);
61 return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
62}
63
64#ifdef WIN32
65
66static int64_t clock_freq;
67
68static void init_get_clock(void)
69{
70 LARGE_INTEGER freq;
71 int ret;
72 ret = QueryPerformanceFrequency(&freq);
73 if (ret == 0) {
74 fprintf(stderr, "Could not calibrate ticks\n");
75 exit(1);
76 }
77 clock_freq = freq.QuadPart;
78}
79
80static int64_t get_clock(void)
81{
82 LARGE_INTEGER ti;
83 QueryPerformanceCounter(&ti);
84 return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq);
85}
86
87#else
88
89static int use_rt_clock;
90
91static void init_get_clock(void)
92{
93 use_rt_clock = 0;
94#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
95 || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
96 {
97 struct timespec ts;
98 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
99 use_rt_clock = 1;
100 }
101 }
102#endif
103}
104
105static int64_t get_clock(void)
106{
107#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
108 || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
109 if (use_rt_clock) {
110 struct timespec ts;
111 clock_gettime(CLOCK_MONOTONIC, &ts);
112 return ts.tv_sec * 1000000000LL + ts.tv_nsec;
113 } else
114#endif
115 {
116 /* XXX: using gettimeofday leads to problems if the date
117 changes, so it should be avoided. */
118 return get_clock_realtime();
119 }
120}
121#endif
122
123/***********************************************************/
124/* guest cycle counter */
125
126typedef struct TimersState {
127 int64_t cpu_ticks_prev;
128 int64_t cpu_ticks_offset;
129 int64_t cpu_clock_offset;
130 int32_t cpu_ticks_enabled;
131 int64_t dummy;
132} TimersState;
133
134TimersState timers_state;
135
136/* return the host CPU cycle counter and handle stop/restart */
137int64_t cpu_get_ticks(void)
138{
139 if (!timers_state.cpu_ticks_enabled) {
140 return timers_state.cpu_ticks_offset;
141 } else {
142 int64_t ticks;
143 ticks = cpu_get_real_ticks();
144 if (timers_state.cpu_ticks_prev > ticks) {
145 /* Note: non increasing ticks may happen if the host uses
146 software suspend */
147 timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
148 }
149 timers_state.cpu_ticks_prev = ticks;
150 return ticks + timers_state.cpu_ticks_offset;
151 }
152}
153
154/* return the host CPU monotonic timer and handle stop/restart */
155static int64_t cpu_get_clock(void)
156{
157 int64_t ti;
158 if (!timers_state.cpu_ticks_enabled) {
159 return timers_state.cpu_clock_offset;
160 } else {
161 ti = get_clock();
162 return ti + timers_state.cpu_clock_offset;
163 }
164}
165
166/* enable cpu_get_ticks() */
167void cpu_enable_ticks(void)
168{
169 if (!timers_state.cpu_ticks_enabled) {
170 timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
171 timers_state.cpu_clock_offset -= get_clock();
172 timers_state.cpu_ticks_enabled = 1;
173 }
174}
175
176/* disable cpu_get_ticks() : the clock is stopped. You must not call
177 cpu_get_ticks() after that. */
178void cpu_disable_ticks(void)
179{
180 if (timers_state.cpu_ticks_enabled) {
181 timers_state.cpu_ticks_offset = cpu_get_ticks();
182 timers_state.cpu_clock_offset = cpu_get_clock();
183 timers_state.cpu_ticks_enabled = 0;
184 }
185}
186
187/***********************************************************/
188/* timers */
189
190#define QEMU_CLOCK_REALTIME 0
191#define QEMU_CLOCK_VIRTUAL 1
192#define QEMU_CLOCK_HOST 2
193
194struct QEMUClock {
195 int type;
196 int enabled;
197 /* XXX: add frequency */
198};
199
200struct QEMUTimer {
201 QEMUClock *clock;
202 int64_t expire_time;
203 QEMUTimerCB *cb;
204 void *opaque;
205 struct QEMUTimer *next;
206};
207
208struct qemu_alarm_timer {
209 char const *name;
210 int (*start)(struct qemu_alarm_timer *t);
211 void (*stop)(struct qemu_alarm_timer *t);
212 void (*rearm)(struct qemu_alarm_timer *t);
213 void *priv;
214
215 char expired;
216 char pending;
217};
218
219static struct qemu_alarm_timer *alarm_timer;
220
221int qemu_alarm_pending(void)
222{
223 return alarm_timer->pending;
224}
225
226static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
227{
228 return !!t->rearm;
229}
230
231static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
232{
233 if (!alarm_has_dynticks(t))
234 return;
235
236 t->rearm(t);
237}
238
239/* TODO: MIN_TIMER_REARM_US should be optimized */
240#define MIN_TIMER_REARM_US 250
241
242#ifdef _WIN32
243
244struct qemu_alarm_win32 {
245 MMRESULT timerId;
246 unsigned int period;
247} alarm_win32_data = {0, 0};
248
249static int win32_start_timer(struct qemu_alarm_timer *t);
250static void win32_stop_timer(struct qemu_alarm_timer *t);
251static void win32_rearm_timer(struct qemu_alarm_timer *t);
252
253#else
254
255static int unix_start_timer(struct qemu_alarm_timer *t);
256static void unix_stop_timer(struct qemu_alarm_timer *t);
257
258#ifdef __linux__
259
260static int dynticks_start_timer(struct qemu_alarm_timer *t);
261static void dynticks_stop_timer(struct qemu_alarm_timer *t);
262static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
263
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200264#endif /* __linux__ */
265
266#endif /* _WIN32 */
267
268static struct qemu_alarm_timer alarm_timers[] = {
269#ifndef _WIN32
270#ifdef __linux__
271 {"dynticks", dynticks_start_timer,
272 dynticks_stop_timer, dynticks_rearm_timer, NULL},
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200273#endif
274 {"unix", unix_start_timer, unix_stop_timer, NULL, NULL},
275#else
276 {"dynticks", win32_start_timer,
277 win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
278 {"win32", win32_start_timer,
279 win32_stop_timer, NULL, &alarm_win32_data},
280#endif
281 {NULL, }
282};
283
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200284#define QEMU_NUM_CLOCKS 3
285
286QEMUClock *rt_clock;
287QEMUClock *vm_clock;
288QEMUClock *host_clock;
289
290static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
291
292static QEMUClock *qemu_new_clock(int type)
293{
294 QEMUClock *clock;
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +0200295 ANEW0(clock);
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200296 clock->type = type;
297 clock->enabled = 1;
298 return clock;
299}
300
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200301QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
302{
303 QEMUTimer *ts;
304
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +0200305 ANEW0(ts);
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200306 ts->clock = clock;
307 ts->cb = cb;
308 ts->opaque = opaque;
309 return ts;
310}
311
312void qemu_free_timer(QEMUTimer *ts)
313{
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +0200314 AFREE(ts);
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200315}
316
317/* stop a timer, but do not dealloc it */
318void qemu_del_timer(QEMUTimer *ts)
319{
320 QEMUTimer **pt, *t;
321
322 /* NOTE: this code must be signal safe because
323 qemu_timer_expired() can be called from a signal. */
324 pt = &active_timers[ts->clock->type];
325 for(;;) {
326 t = *pt;
327 if (!t)
328 break;
329 if (t == ts) {
330 *pt = t->next;
331 break;
332 }
333 pt = &t->next;
334 }
335}
336
337/* modify the current timer so that it will be fired when current_time
338 >= expire_time. The corresponding callback will be called. */
339void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
340{
341 QEMUTimer **pt, *t;
342
343 qemu_del_timer(ts);
344
345 /* add the timer in the sorted list */
346 /* NOTE: this code must be signal safe because
347 qemu_timer_expired() can be called from a signal. */
348 pt = &active_timers[ts->clock->type];
349 for(;;) {
350 t = *pt;
351 if (!t)
352 break;
353 if (t->expire_time > expire_time)
354 break;
355 pt = &t->next;
356 }
357 ts->expire_time = expire_time;
358 ts->next = *pt;
359 *pt = ts;
360
361 /* Rearm if necessary */
362 if (pt == &active_timers[ts->clock->type]) {
363 if (!alarm_timer->pending) {
364 qemu_rearm_alarm_timer(alarm_timer);
365 }
366 }
367}
368
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200369int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
370{
371 if (!timer_head)
372 return 0;
373 return (timer_head->expire_time <= current_time);
374}
375
376static void qemu_run_timers(QEMUClock *clock)
377{
378 QEMUTimer **ptimer_head, *ts;
379 int64_t current_time;
380
381 if (!clock->enabled)
382 return;
383
384 current_time = qemu_get_clock (clock);
385 ptimer_head = &active_timers[clock->type];
386 for(;;) {
387 ts = *ptimer_head;
388 if (!ts || ts->expire_time > current_time)
389 break;
390 /* remove timer from the list before calling the callback */
391 *ptimer_head = ts->next;
392 ts->next = NULL;
393
394 /* run the callback (the timer list can be modified) */
395 ts->cb(ts->opaque);
396 }
397}
398
399int64_t qemu_get_clock(QEMUClock *clock)
400{
401 switch(clock->type) {
402 case QEMU_CLOCK_REALTIME:
403 return get_clock() / 1000000;
404 default:
405 case QEMU_CLOCK_VIRTUAL:
406 return cpu_get_clock();
407 case QEMU_CLOCK_HOST:
408 return get_clock_realtime();
409 }
410}
411
412int64_t qemu_get_clock_ns(QEMUClock *clock)
413{
414 switch(clock->type) {
415 case QEMU_CLOCK_REALTIME:
416 return get_clock();
417 default:
418 case QEMU_CLOCK_VIRTUAL:
419 return cpu_get_clock();
420 case QEMU_CLOCK_HOST:
421 return get_clock_realtime();
422 }
423}
424
425void init_clocks(void)
426{
427 init_get_clock();
428 rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
429 vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
430 host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
431
432 rtc_clock = host_clock;
433}
434
435void qemu_run_all_timers(void)
436{
437 alarm_timer->pending = 0;
438
439 /* rearm timer, if not periodic */
440 if (alarm_timer->expired) {
441 alarm_timer->expired = 0;
442 qemu_rearm_alarm_timer(alarm_timer);
443 }
444
445 /* vm time timers */
446 qemu_run_timers(vm_clock);
447
448 qemu_run_timers(rt_clock);
449 qemu_run_timers(host_clock);
450}
451
452#ifdef _WIN32
453static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
454 DWORD_PTR dwUser, DWORD_PTR dw1,
455 DWORD_PTR dw2)
456#else
457static void host_alarm_handler(int host_signum)
458#endif
459{
460 struct qemu_alarm_timer *t = alarm_timer;
461 if (!t)
462 return;
463
464#if 0
465#define DISP_FREQ 1000
466 {
467 static int64_t delta_min = INT64_MAX;
468 static int64_t delta_max, delta_cum, last_clock, delta, ti;
469 static int count;
470 ti = qemu_get_clock(vm_clock);
471 if (last_clock != 0) {
472 delta = ti - last_clock;
473 if (delta < delta_min)
474 delta_min = delta;
475 if (delta > delta_max)
476 delta_max = delta;
477 delta_cum += delta;
478 if (++count == DISP_FREQ) {
479 printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
480 muldiv64(delta_min, 1000000, get_ticks_per_sec()),
481 muldiv64(delta_max, 1000000, get_ticks_per_sec()),
482 muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()),
483 (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ));
484 count = 0;
485 delta_min = INT64_MAX;
486 delta_max = 0;
487 delta_cum = 0;
488 }
489 }
490 last_clock = ti;
491 }
492#endif
493 if (alarm_has_dynticks(t) ||
494 (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
495 qemu_get_clock(vm_clock))) ||
496 qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME],
497 qemu_get_clock(rt_clock)) ||
498 qemu_timer_expired(active_timers[QEMU_CLOCK_HOST],
499 qemu_get_clock(host_clock))) {
500
501 t->expired = alarm_has_dynticks(t);
502 t->pending = 1;
503 }
504}
505
506int64_t qemu_next_deadline(void)
507{
508 /* To avoid problems with overflow limit this to 2^32. */
509 int64_t delta = INT32_MAX;
510
511 if (active_timers[QEMU_CLOCK_VIRTUAL]) {
512 delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
513 qemu_get_clock(vm_clock);
514 }
515 if (active_timers[QEMU_CLOCK_HOST]) {
516 int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
517 qemu_get_clock(host_clock);
518 if (hdelta < delta)
519 delta = hdelta;
520 }
521
522 if (delta < 0)
523 delta = 0;
524
525 return delta;
526}
527
528#ifndef _WIN32
529
530#if defined(__linux__)
531
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200532static uint64_t qemu_next_deadline_dyntick(void)
533{
534 int64_t delta;
535 int64_t rtdelta;
536
537 delta = (qemu_next_deadline() + 999) / 1000;
538
539 if (active_timers[QEMU_CLOCK_REALTIME]) {
540 rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
541 qemu_get_clock(rt_clock))*1000;
542 if (rtdelta < delta)
543 delta = rtdelta;
544 }
545
546 if (delta < MIN_TIMER_REARM_US)
547 delta = MIN_TIMER_REARM_US;
548
549 return delta;
550}
551
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200552static int dynticks_start_timer(struct qemu_alarm_timer *t)
553{
554 struct sigevent ev;
555 timer_t host_timer;
556 struct sigaction act;
557
558 sigfillset(&act.sa_mask);
559 act.sa_flags = 0;
560 act.sa_handler = host_alarm_handler;
561
562 sigaction(SIGALRM, &act, NULL);
563
564 /*
565 * Initialize ev struct to 0 to avoid valgrind complaining
566 * about uninitialized data in timer_create call
567 */
568 memset(&ev, 0, sizeof(ev));
569 ev.sigev_value.sival_int = 0;
570 ev.sigev_notify = SIGEV_SIGNAL;
571 ev.sigev_signo = SIGALRM;
572
573 if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
574 perror("timer_create");
575
576 /* disable dynticks */
577 fprintf(stderr, "Dynamic Ticks disabled\n");
578
579 return -1;
580 }
581
582 t->priv = (void *)(long)host_timer;
583
584 return 0;
585}
586
587static void dynticks_stop_timer(struct qemu_alarm_timer *t)
588{
589 timer_t host_timer = (timer_t)(long)t->priv;
590
591 timer_delete(host_timer);
592}
593
594static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
595{
596 timer_t host_timer = (timer_t)(long)t->priv;
597 struct itimerspec timeout;
598 int64_t nearest_delta_us = INT64_MAX;
599 int64_t current_us;
600
601 assert(alarm_has_dynticks(t));
602 if (!active_timers[QEMU_CLOCK_REALTIME] &&
603 !active_timers[QEMU_CLOCK_VIRTUAL] &&
604 !active_timers[QEMU_CLOCK_HOST])
605 return;
606
607 nearest_delta_us = qemu_next_deadline_dyntick();
608
609 /* check whether a timer is already running */
610 if (timer_gettime(host_timer, &timeout)) {
611 perror("gettime");
612 fprintf(stderr, "Internal timer error: aborting\n");
613 exit(1);
614 }
615 current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
616 if (current_us && current_us <= nearest_delta_us)
617 return;
618
619 timeout.it_interval.tv_sec = 0;
620 timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
621 timeout.it_value.tv_sec = nearest_delta_us / 1000000;
622 timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
623 if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
624 perror("settime");
625 fprintf(stderr, "Internal timer error: aborting\n");
626 exit(1);
627 }
628}
629
630#endif /* defined(__linux__) */
631
632static int unix_start_timer(struct qemu_alarm_timer *t)
633{
634 struct sigaction act;
635 struct itimerval itv;
636 int err;
637
638 /* timer signal */
639 sigfillset(&act.sa_mask);
640 act.sa_flags = 0;
641 act.sa_handler = host_alarm_handler;
642
643 sigaction(SIGALRM, &act, NULL);
644
645 itv.it_interval.tv_sec = 0;
646 /* for i386 kernel 2.6 to get 1 ms */
647 itv.it_interval.tv_usec = 999;
648 itv.it_value.tv_sec = 0;
649 itv.it_value.tv_usec = 10 * 1000;
650
651 err = setitimer(ITIMER_REAL, &itv, NULL);
652 if (err)
653 return -1;
654
655 return 0;
656}
657
658static void unix_stop_timer(struct qemu_alarm_timer *t)
659{
660 struct itimerval itv;
661
662 memset(&itv, 0, sizeof(itv));
663 setitimer(ITIMER_REAL, &itv, NULL);
664}
665
666#endif /* !defined(_WIN32) */
667
668
669#ifdef _WIN32
670
671static int win32_start_timer(struct qemu_alarm_timer *t)
672{
673 TIMECAPS tc;
674 struct qemu_alarm_win32 *data = t->priv;
675 UINT flags;
676
677 memset(&tc, 0, sizeof(tc));
678 timeGetDevCaps(&tc, sizeof(tc));
679
680 data->period = tc.wPeriodMin;
681 timeBeginPeriod(data->period);
682
683 flags = TIME_CALLBACK_FUNCTION;
684 if (alarm_has_dynticks(t))
685 flags |= TIME_ONESHOT;
686 else
687 flags |= TIME_PERIODIC;
688
689 data->timerId = timeSetEvent(1, // interval (ms)
690 data->period, // resolution
691 host_alarm_handler, // function
692 (DWORD)t, // parameter
693 flags);
694
695 if (!data->timerId) {
696 fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
697 GetLastError());
698 timeEndPeriod(data->period);
699 return -1;
700 }
701
702 return 0;
703}
704
705static void win32_stop_timer(struct qemu_alarm_timer *t)
706{
707 struct qemu_alarm_win32 *data = t->priv;
708
709 timeKillEvent(data->timerId);
710 timeEndPeriod(data->period);
711}
712
713static void win32_rearm_timer(struct qemu_alarm_timer *t)
714{
715 struct qemu_alarm_win32 *data = t->priv;
716
717 assert(alarm_has_dynticks(t));
718 if (!active_timers[QEMU_CLOCK_REALTIME] &&
719 !active_timers[QEMU_CLOCK_VIRTUAL] &&
720 !active_timers[QEMU_CLOCK_HOST])
721 return;
722
723 timeKillEvent(data->timerId);
724
725 data->timerId = timeSetEvent(1,
726 data->period,
727 host_alarm_handler,
728 (DWORD)t,
729 TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
730
731 if (!data->timerId) {
732 fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
733 GetLastError());
734
735 timeEndPeriod(data->period);
736 exit(1);
737 }
738}
739
740#endif /* _WIN32 */
741
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200742int init_timer_alarm(void)
743{
744 struct qemu_alarm_timer *t = NULL;
745 int i, err = -1;
746
747 for (i = 0; alarm_timers[i].name; i++) {
748 t = &alarm_timers[i];
749
750 err = t->start(t);
751 if (!err)
752 break;
753 }
754
755 if (err) {
756 err = -ENOENT;
757 goto fail;
758 }
759
760 /* first event is at time 0 */
761 t->pending = 1;
762 alarm_timer = t;
763
764 return 0;
765
766fail:
767 return err;
768}
769
770void quit_timers(void)
771{
772 struct qemu_alarm_timer *t = alarm_timer;
773 alarm_timer = NULL;
774 t->stop(t);
775}
776
777int qemu_calculate_timeout(void)
778{
David 'Digit' Turner6b512812010-10-15 15:05:04 +0200779 /* Deliver user events at 30 Hz */
780 return 1000/30;
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200781}