blob: ca5e6b12e1181b7bb1767ae9de8616f9f133a542 [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/***********************************************************/
David Turner6a9ef172010-09-09 22:54:36 +020045/* timers */
46
David Turner6a9ef172010-09-09 22:54:36 +020047struct QEMUClock {
48 int type;
49 int enabled;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +020050
51 QEMUTimer *warp_timer;
David Turner6a9ef172010-09-09 22:54:36 +020052};
53
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +010054QEMUTimer* qemu_clock_get_warp_timer(QEMUClock* clock) {
55 return clock ? clock->warp_timer : NULL;
56}
57
David Turner6a9ef172010-09-09 22:54:36 +020058struct QEMUTimer {
59 QEMUClock *clock;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +020060 int64_t expire_time; /* in nanoseconds */
61 int scale;
David Turner6a9ef172010-09-09 22:54:36 +020062 QEMUTimerCB *cb;
63 void *opaque;
64 struct QEMUTimer *next;
65};
66
David 'Digit' Turner317c9d52011-05-10 06:38:21 +020067static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
68{
69 return timer_head && (timer_head->expire_time <= current_time);
70}
71
David Turner6a9ef172010-09-09 22:54:36 +020072QEMUClock *rt_clock;
73QEMUClock *vm_clock;
74QEMUClock *host_clock;
75
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +010076QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
David Turner6a9ef172010-09-09 22:54:36 +020077
78static QEMUClock *qemu_new_clock(int type)
79{
80 QEMUClock *clock;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +010081 clock = g_malloc0(sizeof(QEMUClock));
David Turner6a9ef172010-09-09 22:54:36 +020082 clock->type = type;
83 clock->enabled = 1;
84 return clock;
85}
86
87void qemu_clock_enable(QEMUClock *clock, int enabled)
88{
89 clock->enabled = enabled;
90}
91
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +010092int qemu_clock_has_active_timer(QEMUClock* clock) {
93 return active_timers[clock->type] != NULL;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +020094}
95
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +010096int64_t qemu_clock_next_deadline(QEMUClock* clock) {
97 /* To avoid problems with overflow limit this to 2^32. */
98 int64_t delta = INT32_MAX;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +020099
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100100 if (active_timers[clock->type]) {
101 delta = active_timers[clock->type]->expire_time -
102 qemu_get_clock_ns(clock);
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200103 }
104
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100105 if (delta < 0)
106 delta = 0;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200107
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100108 return delta;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200109}
110
David 'Digit' Turner5973c772011-05-10 07:06:00 +0200111QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200112 QEMUTimerCB *cb, void *opaque)
David Turner6a9ef172010-09-09 22:54:36 +0200113{
114 QEMUTimer *ts;
115
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100116 ts = g_malloc0(sizeof(QEMUTimer));
David Turner6a9ef172010-09-09 22:54:36 +0200117 ts->clock = clock;
118 ts->cb = cb;
119 ts->opaque = opaque;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200120 ts->scale = scale;
David Turner6a9ef172010-09-09 22:54:36 +0200121 return ts;
122}
123
124void qemu_free_timer(QEMUTimer *ts)
125{
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100126 g_free(ts);
David Turner6a9ef172010-09-09 22:54:36 +0200127}
128
129/* stop a timer, but do not dealloc it */
130void qemu_del_timer(QEMUTimer *ts)
131{
132 QEMUTimer **pt, *t;
133
134 /* NOTE: this code must be signal safe because
135 qemu_timer_expired() can be called from a signal. */
136 pt = &active_timers[ts->clock->type];
137 for(;;) {
138 t = *pt;
139 if (!t)
140 break;
141 if (t == ts) {
142 *pt = t->next;
143 break;
144 }
145 pt = &t->next;
146 }
147}
148
149/* modify the current timer so that it will be fired when current_time
150 >= expire_time. The corresponding callback will be called. */
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200151static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
David Turner6a9ef172010-09-09 22:54:36 +0200152{
153 QEMUTimer **pt, *t;
154
155 qemu_del_timer(ts);
156
157 /* add the timer in the sorted list */
158 /* NOTE: this code must be signal safe because
159 qemu_timer_expired() can be called from a signal. */
160 pt = &active_timers[ts->clock->type];
161 for(;;) {
162 t = *pt;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200163 if (!qemu_timer_expired_ns(t, expire_time)) {
David Turner6a9ef172010-09-09 22:54:36 +0200164 break;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200165 }
David Turner6a9ef172010-09-09 22:54:36 +0200166 pt = &t->next;
167 }
168 ts->expire_time = expire_time;
169 ts->next = *pt;
170 *pt = ts;
171
172 /* Rearm if necessary */
173 if (pt == &active_timers[ts->clock->type]) {
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100174 qemu_adjust_clock(ts->clock);
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200175 }
176}
177
178/* modify the current timer so that it will be fired when current_time
179 >= expire_time. The corresponding callback will be called. */
180void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
181{
182 qemu_mod_timer_ns(ts, expire_time * ts->scale);
David Turner6a9ef172010-09-09 22:54:36 +0200183}
184
185int qemu_timer_pending(QEMUTimer *ts)
186{
187 QEMUTimer *t;
188 for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
189 if (t == ts)
190 return 1;
191 }
192 return 0;
193}
194
195int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
196{
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200197 return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
David Turner6a9ef172010-09-09 22:54:36 +0200198}
199
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100200void qemu_run_timers(QEMUClock *clock)
David Turner6a9ef172010-09-09 22:54:36 +0200201{
202 QEMUTimer **ptimer_head, *ts;
203 int64_t current_time;
David 'Digit' Turner6b512812010-10-15 15:05:04 +0200204
David Turner6a9ef172010-09-09 22:54:36 +0200205 if (!clock->enabled)
206 return;
207
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200208 current_time = qemu_get_clock_ns(clock);
David Turner6a9ef172010-09-09 22:54:36 +0200209 ptimer_head = &active_timers[clock->type];
210 for(;;) {
211 ts = *ptimer_head;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200212 if (!qemu_timer_expired_ns(ts, current_time)) {
David Turner6a9ef172010-09-09 22:54:36 +0200213 break;
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200214 }
David Turner6a9ef172010-09-09 22:54:36 +0200215 /* remove timer from the list before calling the callback */
216 *ptimer_head = ts->next;
217 ts->next = NULL;
218
219 /* run the callback (the timer list can be modified) */
220 ts->cb(ts->opaque);
221 }
222}
223
224int64_t qemu_get_clock(QEMUClock *clock)
225{
226 switch(clock->type) {
227 case QEMU_CLOCK_REALTIME:
228 return get_clock() / 1000000;
229 default:
230 case QEMU_CLOCK_VIRTUAL:
231 if (use_icount) {
232 return cpu_get_icount();
233 } else {
234 return cpu_get_clock();
235 }
236 case QEMU_CLOCK_HOST:
237 return get_clock_realtime();
238 }
239}
240
241int64_t qemu_get_clock_ns(QEMUClock *clock)
242{
243 switch(clock->type) {
244 case QEMU_CLOCK_REALTIME:
245 return get_clock();
246 default:
247 case QEMU_CLOCK_VIRTUAL:
248 if (use_icount) {
249 return cpu_get_icount();
250 } else {
251 return cpu_get_clock();
252 }
253 case QEMU_CLOCK_HOST:
254 return get_clock_realtime();
255 }
256}
257
258void init_clocks(void)
259{
David Turner6a9ef172010-09-09 22:54:36 +0200260 rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
261 vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
262 host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
263
264 rtc_clock = host_clock;
265}
266
267/* save a timer */
268void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
269{
270 uint64_t expire_time;
271
272 if (qemu_timer_pending(ts)) {
273 expire_time = ts->expire_time;
274 } else {
275 expire_time = -1;
276 }
277 qemu_put_be64(f, expire_time);
278}
279
280void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
281{
282 uint64_t expire_time;
283
284 expire_time = qemu_get_be64(f);
285 if (expire_time != -1) {
David 'Digit' Turner317c9d52011-05-10 06:38:21 +0200286 qemu_mod_timer_ns(ts, expire_time);
David Turner6a9ef172010-09-09 22:54:36 +0200287 } else {
288 qemu_del_timer(ts);
289 }
290}
291
292#if 0
293static const VMStateDescription vmstate_timers = {
294 .name = "timer",
295 .version_id = 2,
296 .minimum_version_id = 1,
297 .minimum_version_id_old = 1,
298 .fields = (VMStateField []) {
299 VMSTATE_INT64(cpu_ticks_offset, TimersState),
300 VMSTATE_INT64(dummy, TimersState),
301 VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
302 VMSTATE_END_OF_LIST()
303 }
304};
305#endif