blob: cbb119dc5b1c3f52fd97ff5dd3f84d751420993b [file] [log] [blame]
David Turner6a9ef172010-09-09 22:54:36 +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
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010025#include "sysemu/sysemu.h"
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010026#include "net/net.h"
David 'Digit' Turner6af67652013-12-14 23:49:32 +010027#include "monitor/monitor.h"
David 'Digit' Turner1c31e3e2013-12-14 20:07:17 +010028#include "ui/console.h"
David Turner6a9ef172010-09-09 22:54:36 +020029
30#include "hw/hw.h"
31
32#include <unistd.h>
33#include <fcntl.h>
34#include <time.h>
35#include <errno.h>
36#include <sys/time.h>
37#include <signal.h>
38#ifdef __FreeBSD__
39#include <sys/param.h>
40#endif
41
David 'Digit' Turner7a78db72013-12-14 11:46:01 +010042#include "qemu/timer.h"
David Turner6a9ef172010-09-09 22:54:36 +020043
David Turner6a9ef172010-09-09 22:54:36 +020044/***********************************************************/
45/* guest cycle counter */
46
47typedef struct TimersState {
48 int64_t cpu_ticks_prev;
49 int64_t cpu_ticks_offset;
50 int64_t cpu_clock_offset;
51 int32_t cpu_ticks_enabled;
52 int64_t dummy;
53} TimersState;
54
55static void timer_save(QEMUFile *f, void *opaque)
56{
57 TimersState *s = opaque;
58
59 if (s->cpu_ticks_enabled) {
60 hw_error("cannot save state if virtual timers are running");
61 }
62 qemu_put_be64(f, s->cpu_ticks_prev);
63 qemu_put_be64(f, s->cpu_ticks_offset);
64 qemu_put_be64(f, s->cpu_clock_offset);
65 }
66
67static int timer_load(QEMUFile *f, void *opaque, int version_id)
68{
69 TimersState *s = opaque;
70
71 if (version_id != 1 && version_id != 2)
72 return -EINVAL;
73 if (s->cpu_ticks_enabled) {
74 return -EINVAL;
75 }
76 s->cpu_ticks_prev = qemu_get_sbe64(f);
77 s->cpu_ticks_offset = qemu_get_sbe64(f);
78 if (version_id == 2) {
79 s->cpu_clock_offset = qemu_get_sbe64(f);
80 }
81 return 0;
82}
83
84
85TimersState timers_state;
86
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +010087void qemu_timer_register_savevm(void) {
88 register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state);
89}
90
David Turner6a9ef172010-09-09 22:54:36 +020091/* return the host CPU cycle counter and handle stop/restart */
92int64_t cpu_get_ticks(void)
93{
94 if (use_icount) {
95 return cpu_get_icount();
96 }
97 if (!timers_state.cpu_ticks_enabled) {
98 return timers_state.cpu_ticks_offset;
99 } else {
100 int64_t ticks;
101 ticks = cpu_get_real_ticks();
102 if (timers_state.cpu_ticks_prev > ticks) {
103 /* Note: non increasing ticks may happen if the host uses
104 software suspend */
105 timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
106 }
107 timers_state.cpu_ticks_prev = ticks;
108 return ticks + timers_state.cpu_ticks_offset;
109 }
110}
111
112/* return the host CPU monotonic timer and handle stop/restart */
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100113int64_t cpu_get_clock(void)
David Turner6a9ef172010-09-09 22:54:36 +0200114{
115 int64_t ti;
116 if (!timers_state.cpu_ticks_enabled) {
117 return timers_state.cpu_clock_offset;
118 } else {
119 ti = get_clock();
120 return ti + timers_state.cpu_clock_offset;
121 }
122}
123
David Turner6a9ef172010-09-09 22:54:36 +0200124/* enable cpu_get_ticks() */
125void cpu_enable_ticks(void)
126{
127 if (!timers_state.cpu_ticks_enabled) {
128 timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
129 timers_state.cpu_clock_offset -= get_clock();
130 timers_state.cpu_ticks_enabled = 1;
131 }
132}
133
134/* disable cpu_get_ticks() : the clock is stopped. You must not call
135 cpu_get_ticks() after that. */
136void cpu_disable_ticks(void)
137{
138 if (timers_state.cpu_ticks_enabled) {
139 timers_state.cpu_ticks_offset = cpu_get_ticks();
140 timers_state.cpu_clock_offset = cpu_get_clock();
141 timers_state.cpu_ticks_enabled = 0;
142 }
143}
144
145/***********************************************************/
146/* timers */
147
David Turner6a9ef172010-09-09 22:54:36 +0200148struct QEMUClock {
149 int type;
150 int enabled;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200151
152 QEMUTimer *warp_timer;
David Turner6a9ef172010-09-09 22:54:36 +0200153};
154
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100155QEMUTimer* qemu_clock_get_warp_timer(QEMUClock* clock) {
156 return clock ? clock->warp_timer : NULL;
157}
158
David Turner6a9ef172010-09-09 22:54:36 +0200159struct QEMUTimer {
160 QEMUClock *clock;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200161 int64_t expire_time; /* in nanoseconds */
162 int scale;
David Turner6a9ef172010-09-09 22:54:36 +0200163 QEMUTimerCB *cb;
164 void *opaque;
165 struct QEMUTimer *next;
166};
167
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200168static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
169{
170 return timer_head && (timer_head->expire_time <= current_time);
171}
172
David Turner6a9ef172010-09-09 22:54:36 +0200173QEMUClock *rt_clock;
174QEMUClock *vm_clock;
175QEMUClock *host_clock;
176
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100177QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
David Turner6a9ef172010-09-09 22:54:36 +0200178
179static QEMUClock *qemu_new_clock(int type)
180{
181 QEMUClock *clock;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100182 clock = g_malloc0(sizeof(QEMUClock));
David Turner6a9ef172010-09-09 22:54:36 +0200183 clock->type = type;
184 clock->enabled = 1;
185 return clock;
186}
187
188void qemu_clock_enable(QEMUClock *clock, int enabled)
189{
190 clock->enabled = enabled;
191}
192
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100193int qemu_clock_has_active_timer(QEMUClock* clock) {
194 return active_timers[clock->type] != NULL;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200195}
196
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100197int64_t qemu_clock_next_deadline(QEMUClock* clock) {
198 /* To avoid problems with overflow limit this to 2^32. */
199 int64_t delta = INT32_MAX;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200200
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100201 if (active_timers[clock->type]) {
202 delta = active_timers[clock->type]->expire_time -
203 qemu_get_clock_ns(clock);
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200204 }
205
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100206 if (delta < 0)
207 delta = 0;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200208
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100209 return delta;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200210}
211
David 'Digit' Turner5973c772011-05-10 07:06:00 +0200212QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200213 QEMUTimerCB *cb, void *opaque)
David Turner6a9ef172010-09-09 22:54:36 +0200214{
215 QEMUTimer *ts;
216
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100217 ts = g_malloc0(sizeof(QEMUTimer));
David Turner6a9ef172010-09-09 22:54:36 +0200218 ts->clock = clock;
219 ts->cb = cb;
220 ts->opaque = opaque;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200221 ts->scale = scale;
David Turner6a9ef172010-09-09 22:54:36 +0200222 return ts;
223}
224
225void qemu_free_timer(QEMUTimer *ts)
226{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100227 g_free(ts);
David Turner6a9ef172010-09-09 22:54:36 +0200228}
229
230/* stop a timer, but do not dealloc it */
231void qemu_del_timer(QEMUTimer *ts)
232{
233 QEMUTimer **pt, *t;
234
235 /* NOTE: this code must be signal safe because
236 qemu_timer_expired() can be called from a signal. */
237 pt = &active_timers[ts->clock->type];
238 for(;;) {
239 t = *pt;
240 if (!t)
241 break;
242 if (t == ts) {
243 *pt = t->next;
244 break;
245 }
246 pt = &t->next;
247 }
248}
249
250/* modify the current timer so that it will be fired when current_time
251 >= expire_time. The corresponding callback will be called. */
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200252static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
David Turner6a9ef172010-09-09 22:54:36 +0200253{
254 QEMUTimer **pt, *t;
255
256 qemu_del_timer(ts);
257
258 /* add the timer in the sorted list */
259 /* NOTE: this code must be signal safe because
260 qemu_timer_expired() can be called from a signal. */
261 pt = &active_timers[ts->clock->type];
262 for(;;) {
263 t = *pt;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200264 if (!qemu_timer_expired_ns(t, expire_time)) {
David Turner6a9ef172010-09-09 22:54:36 +0200265 break;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200266 }
David Turner6a9ef172010-09-09 22:54:36 +0200267 pt = &t->next;
268 }
269 ts->expire_time = expire_time;
270 ts->next = *pt;
271 *pt = ts;
272
273 /* Rearm if necessary */
274 if (pt == &active_timers[ts->clock->type]) {
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100275 qemu_adjust_clock(ts->clock);
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200276 }
277}
278
279/* modify the current timer so that it will be fired when current_time
280 >= expire_time. The corresponding callback will be called. */
281void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
282{
283 qemu_mod_timer_ns(ts, expire_time * ts->scale);
David Turner6a9ef172010-09-09 22:54:36 +0200284}
285
286int qemu_timer_pending(QEMUTimer *ts)
287{
288 QEMUTimer *t;
289 for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
290 if (t == ts)
291 return 1;
292 }
293 return 0;
294}
295
296int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
297{
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200298 return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
David Turner6a9ef172010-09-09 22:54:36 +0200299}
300
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100301void qemu_run_timers(QEMUClock *clock)
David Turner6a9ef172010-09-09 22:54:36 +0200302{
303 QEMUTimer **ptimer_head, *ts;
304 int64_t current_time;
David 'Digit' Turner6b512812010-10-15 15:05:04 +0200305
David Turner6a9ef172010-09-09 22:54:36 +0200306 if (!clock->enabled)
307 return;
308
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200309 current_time = qemu_get_clock_ns(clock);
David Turner6a9ef172010-09-09 22:54:36 +0200310 ptimer_head = &active_timers[clock->type];
311 for(;;) {
312 ts = *ptimer_head;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200313 if (!qemu_timer_expired_ns(ts, current_time)) {
David Turner6a9ef172010-09-09 22:54:36 +0200314 break;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200315 }
David Turner6a9ef172010-09-09 22:54:36 +0200316 /* remove timer from the list before calling the callback */
317 *ptimer_head = ts->next;
318 ts->next = NULL;
319
320 /* run the callback (the timer list can be modified) */
321 ts->cb(ts->opaque);
322 }
323}
324
325int64_t qemu_get_clock(QEMUClock *clock)
326{
327 switch(clock->type) {
328 case QEMU_CLOCK_REALTIME:
329 return get_clock() / 1000000;
330 default:
331 case QEMU_CLOCK_VIRTUAL:
332 if (use_icount) {
333 return cpu_get_icount();
334 } else {
335 return cpu_get_clock();
336 }
337 case QEMU_CLOCK_HOST:
338 return get_clock_realtime();
339 }
340}
341
342int64_t qemu_get_clock_ns(QEMUClock *clock)
343{
344 switch(clock->type) {
345 case QEMU_CLOCK_REALTIME:
346 return get_clock();
347 default:
348 case QEMU_CLOCK_VIRTUAL:
349 if (use_icount) {
350 return cpu_get_icount();
351 } else {
352 return cpu_get_clock();
353 }
354 case QEMU_CLOCK_HOST:
355 return get_clock_realtime();
356 }
357}
358
359void init_clocks(void)
360{
David Turner6a9ef172010-09-09 22:54:36 +0200361 rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
362 vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
363 host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
364
365 rtc_clock = host_clock;
366}
367
368/* save a timer */
369void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
370{
371 uint64_t expire_time;
372
373 if (qemu_timer_pending(ts)) {
374 expire_time = ts->expire_time;
375 } else {
376 expire_time = -1;
377 }
378 qemu_put_be64(f, expire_time);
379}
380
381void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
382{
383 uint64_t expire_time;
384
385 expire_time = qemu_get_be64(f);
386 if (expire_time != -1) {
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200387 qemu_mod_timer_ns(ts, expire_time);
David Turner6a9ef172010-09-09 22:54:36 +0200388 } else {
389 qemu_del_timer(ts);
390 }
391}
392
393#if 0
394static const VMStateDescription vmstate_timers = {
395 .name = "timer",
396 .version_id = 2,
397 .minimum_version_id = 1,
398 .minimum_version_id_old = 1,
399 .fields = (VMStateField []) {
400 VMSTATE_INT64(cpu_ticks_offset, TimersState),
401 VMSTATE_INT64(dummy, TimersState),
402 VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
403 VMSTATE_END_OF_LIST()
404 }
405};
406#endif