]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - qemu-timer.c
Merge remote-tracking branch 'borntraeger/tags/s390-next-20130924' into staging
[lisovros/qemu_apohw.git] / qemu-timer.c
1 /*
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 "sysemu/sysemu.h"
26 #include "monitor/monitor.h"
27 #include "ui/console.h"
28
29 #include "hw/hw.h"
30
31 #include "qemu/timer.h"
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 /* timers */
46
47 typedef struct QEMUClock {
48     QLIST_HEAD(, QEMUTimerList) timerlists;
49
50     NotifierList reset_notifiers;
51     int64_t last;
52
53     QEMUClockType type;
54     bool enabled;
55 } QEMUClock;
56
57 QEMUTimerListGroup main_loop_tlg;
58 QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
59
60 /* A QEMUTimerList is a list of timers attached to a clock. More
61  * than one QEMUTimerList can be attached to each clock, for instance
62  * used by different AioContexts / threads. Each clock also has
63  * a list of the QEMUTimerLists associated with it, in order that
64  * reenabling the clock can call all the notifiers.
65  */
66
67 struct QEMUTimerList {
68     QEMUClock *clock;
69     QemuMutex active_timers_lock;
70     QEMUTimer *active_timers;
71     QLIST_ENTRY(QEMUTimerList) list;
72     QEMUTimerListNotifyCB *notify_cb;
73     void *notify_opaque;
74 };
75
76 /**
77  * qemu_clock_ptr:
78  * @type: type of clock
79  *
80  * Translate a clock type into a pointer to QEMUClock object.
81  *
82  * Returns: a pointer to the QEMUClock object
83  */
84 static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
85 {
86     return &qemu_clocks[type];
87 }
88
89 static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
90 {
91     return timer_head && (timer_head->expire_time <= current_time);
92 }
93
94 QEMUTimerList *timerlist_new(QEMUClockType type,
95                              QEMUTimerListNotifyCB *cb,
96                              void *opaque)
97 {
98     QEMUTimerList *timer_list;
99     QEMUClock *clock = qemu_clock_ptr(type);
100
101     timer_list = g_malloc0(sizeof(QEMUTimerList));
102     timer_list->clock = clock;
103     timer_list->notify_cb = cb;
104     timer_list->notify_opaque = opaque;
105     qemu_mutex_init(&timer_list->active_timers_lock);
106     QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
107     return timer_list;
108 }
109
110 void timerlist_free(QEMUTimerList *timer_list)
111 {
112     assert(!timerlist_has_timers(timer_list));
113     if (timer_list->clock) {
114         QLIST_REMOVE(timer_list, list);
115     }
116     qemu_mutex_destroy(&timer_list->active_timers_lock);
117     g_free(timer_list);
118 }
119
120 static void qemu_clock_init(QEMUClockType type)
121 {
122     QEMUClock *clock = qemu_clock_ptr(type);
123
124     clock->type = type;
125     clock->enabled = true;
126     clock->last = INT64_MIN;
127     QLIST_INIT(&clock->timerlists);
128     notifier_list_init(&clock->reset_notifiers);
129     main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL);
130 }
131
132 bool qemu_clock_use_for_deadline(QEMUClockType type)
133 {
134     return !(use_icount && (type == QEMU_CLOCK_VIRTUAL));
135 }
136
137 void qemu_clock_notify(QEMUClockType type)
138 {
139     QEMUTimerList *timer_list;
140     QEMUClock *clock = qemu_clock_ptr(type);
141     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
142         timerlist_notify(timer_list);
143     }
144 }
145
146 void qemu_clock_enable(QEMUClockType type, bool enabled)
147 {
148     QEMUClock *clock = qemu_clock_ptr(type);
149     bool old = clock->enabled;
150     clock->enabled = enabled;
151     if (enabled && !old) {
152         qemu_clock_notify(type);
153     }
154 }
155
156 bool timerlist_has_timers(QEMUTimerList *timer_list)
157 {
158     return !!timer_list->active_timers;
159 }
160
161 bool qemu_clock_has_timers(QEMUClockType type)
162 {
163     return timerlist_has_timers(
164         main_loop_tlg.tl[type]);
165 }
166
167 bool timerlist_expired(QEMUTimerList *timer_list)
168 {
169     int64_t expire_time;
170
171     qemu_mutex_lock(&timer_list->active_timers_lock);
172     if (!timer_list->active_timers) {
173         qemu_mutex_unlock(&timer_list->active_timers_lock);
174         return false;
175     }
176     expire_time = timer_list->active_timers->expire_time;
177     qemu_mutex_unlock(&timer_list->active_timers_lock);
178
179     return expire_time < qemu_clock_get_ns(timer_list->clock->type);
180 }
181
182 bool qemu_clock_expired(QEMUClockType type)
183 {
184     return timerlist_expired(
185         main_loop_tlg.tl[type]);
186 }
187
188 /*
189  * As above, but return -1 for no deadline, and do not cap to 2^32
190  * as we know the result is always positive.
191  */
192
193 int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
194 {
195     int64_t delta;
196     int64_t expire_time;
197
198     if (!timer_list->clock->enabled) {
199         return -1;
200     }
201
202     /* The active timers list may be modified before the caller uses our return
203      * value but ->notify_cb() is called when the deadline changes.  Therefore
204      * the caller should notice the change and there is no race condition.
205      */
206     qemu_mutex_lock(&timer_list->active_timers_lock);
207     if (!timer_list->active_timers) {
208         qemu_mutex_unlock(&timer_list->active_timers_lock);
209         return -1;
210     }
211     expire_time = timer_list->active_timers->expire_time;
212     qemu_mutex_unlock(&timer_list->active_timers_lock);
213
214     delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
215
216     if (delta <= 0) {
217         return 0;
218     }
219
220     return delta;
221 }
222
223 /* Calculate the soonest deadline across all timerlists attached
224  * to the clock. This is used for the icount timeout so we
225  * ignore whether or not the clock should be used in deadline
226  * calculations.
227  */
228 int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
229 {
230     int64_t deadline = -1;
231     QEMUTimerList *timer_list;
232     QEMUClock *clock = qemu_clock_ptr(type);
233     QLIST_FOREACH(timer_list, &clock->timerlists, list) {
234         deadline = qemu_soonest_timeout(deadline,
235                                         timerlist_deadline_ns(timer_list));
236     }
237     return deadline;
238 }
239
240 QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
241 {
242     return timer_list->clock->type;
243 }
244
245 QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
246 {
247     return main_loop_tlg.tl[type];
248 }
249
250 void timerlist_notify(QEMUTimerList *timer_list)
251 {
252     if (timer_list->notify_cb) {
253         timer_list->notify_cb(timer_list->notify_opaque);
254     } else {
255         qemu_notify_event();
256     }
257 }
258
259 /* Transition function to convert a nanosecond timeout to ms
260  * This is used where a system does not support ppoll
261  */
262 int qemu_timeout_ns_to_ms(int64_t ns)
263 {
264     int64_t ms;
265     if (ns < 0) {
266         return -1;
267     }
268
269     if (!ns) {
270         return 0;
271     }
272
273     /* Always round up, because it's better to wait too long than to wait too
274      * little and effectively busy-wait
275      */
276     ms = (ns + SCALE_MS - 1) / SCALE_MS;
277
278     /* To avoid overflow problems, limit this to 2^31, i.e. approx 25 days */
279     if (ms > (int64_t) INT32_MAX) {
280         ms = INT32_MAX;
281     }
282
283     return (int) ms;
284 }
285
286
287 /* qemu implementation of g_poll which uses a nanosecond timeout but is
288  * otherwise identical to g_poll
289  */
290 int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
291 {
292 #ifdef CONFIG_PPOLL
293     if (timeout < 0) {
294         return ppoll((struct pollfd *)fds, nfds, NULL, NULL);
295     } else {
296         struct timespec ts;
297         ts.tv_sec = timeout / 1000000000LL;
298         ts.tv_nsec = timeout % 1000000000LL;
299         return ppoll((struct pollfd *)fds, nfds, &ts, NULL);
300     }
301 #else
302     return g_poll(fds, nfds, qemu_timeout_ns_to_ms(timeout));
303 #endif
304 }
305
306
307 void timer_init(QEMUTimer *ts,
308                 QEMUTimerList *timer_list, int scale,
309                 QEMUTimerCB *cb, void *opaque)
310 {
311     ts->timer_list = timer_list;
312     ts->cb = cb;
313     ts->opaque = opaque;
314     ts->scale = scale;
315     ts->expire_time = -1;
316 }
317
318 void timer_free(QEMUTimer *ts)
319 {
320     g_free(ts);
321 }
322
323 static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
324 {
325     QEMUTimer **pt, *t;
326
327     ts->expire_time = -1;
328     pt = &timer_list->active_timers;
329     for(;;) {
330         t = *pt;
331         if (!t)
332             break;
333         if (t == ts) {
334             *pt = t->next;
335             break;
336         }
337         pt = &t->next;
338     }
339 }
340
341 /* stop a timer, but do not dealloc it */
342 void timer_del(QEMUTimer *ts)
343 {
344     QEMUTimerList *timer_list = ts->timer_list;
345
346     qemu_mutex_lock(&timer_list->active_timers_lock);
347     timer_del_locked(timer_list, ts);
348     qemu_mutex_unlock(&timer_list->active_timers_lock);
349 }
350
351 /* modify the current timer so that it will be fired when current_time
352    >= expire_time. The corresponding callback will be called. */
353 void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
354 {
355     QEMUTimerList *timer_list = ts->timer_list;
356     QEMUTimer **pt, *t;
357
358     qemu_mutex_lock(&timer_list->active_timers_lock);
359     timer_del_locked(timer_list, ts);
360
361     /* add the timer in the sorted list */
362     pt = &timer_list->active_timers;
363     for(;;) {
364         t = *pt;
365         if (!timer_expired_ns(t, expire_time)) {
366             break;
367         }
368         pt = &t->next;
369     }
370     ts->expire_time = MAX(expire_time, 0);
371     ts->next = *pt;
372     *pt = ts;
373     qemu_mutex_unlock(&timer_list->active_timers_lock);
374
375     /* Rearm if necessary  */
376     if (pt == &timer_list->active_timers) {
377         /* Interrupt execution to force deadline recalculation.  */
378         qemu_clock_warp(timer_list->clock->type);
379         timerlist_notify(timer_list);
380     }
381 }
382
383 void timer_mod(QEMUTimer *ts, int64_t expire_time)
384 {
385     timer_mod_ns(ts, expire_time * ts->scale);
386 }
387
388 bool timer_pending(QEMUTimer *ts)
389 {
390     return ts->expire_time >= 0;
391 }
392
393 bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
394 {
395     return timer_expired_ns(timer_head, current_time * timer_head->scale);
396 }
397
398 bool timerlist_run_timers(QEMUTimerList *timer_list)
399 {
400     QEMUTimer *ts;
401     int64_t current_time;
402     bool progress = false;
403     QEMUTimerCB *cb;
404     void *opaque;
405
406     if (!timer_list->clock->enabled) {
407         return progress;
408     }
409
410     current_time = qemu_clock_get_ns(timer_list->clock->type);
411     for(;;) {
412         qemu_mutex_lock(&timer_list->active_timers_lock);
413         ts = timer_list->active_timers;
414         if (!timer_expired_ns(ts, current_time)) {
415             qemu_mutex_unlock(&timer_list->active_timers_lock);
416             break;
417         }
418
419         /* remove timer from the list before calling the callback */
420         timer_list->active_timers = ts->next;
421         ts->next = NULL;
422         ts->expire_time = -1;
423         cb = ts->cb;
424         opaque = ts->opaque;
425         qemu_mutex_unlock(&timer_list->active_timers_lock);
426
427         /* run the callback (the timer list can be modified) */
428         cb(opaque);
429         progress = true;
430     }
431     return progress;
432 }
433
434 bool qemu_clock_run_timers(QEMUClockType type)
435 {
436     return timerlist_run_timers(main_loop_tlg.tl[type]);
437 }
438
439 void timerlistgroup_init(QEMUTimerListGroup *tlg,
440                          QEMUTimerListNotifyCB *cb, void *opaque)
441 {
442     QEMUClockType type;
443     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
444         tlg->tl[type] = timerlist_new(type, cb, opaque);
445     }
446 }
447
448 void timerlistgroup_deinit(QEMUTimerListGroup *tlg)
449 {
450     QEMUClockType type;
451     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
452         timerlist_free(tlg->tl[type]);
453     }
454 }
455
456 bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg)
457 {
458     QEMUClockType type;
459     bool progress = false;
460     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
461         progress |= timerlist_run_timers(tlg->tl[type]);
462     }
463     return progress;
464 }
465
466 int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
467 {
468     int64_t deadline = -1;
469     QEMUClockType type;
470     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
471         if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
472             deadline = qemu_soonest_timeout(deadline,
473                                             timerlist_deadline_ns(
474                                                 tlg->tl[type]));
475         }
476     }
477     return deadline;
478 }
479
480 int64_t qemu_clock_get_ns(QEMUClockType type)
481 {
482     int64_t now, last;
483     QEMUClock *clock = qemu_clock_ptr(type);
484
485     switch (type) {
486     case QEMU_CLOCK_REALTIME:
487         return get_clock();
488     default:
489     case QEMU_CLOCK_VIRTUAL:
490         if (use_icount) {
491             return cpu_get_icount();
492         } else {
493             return cpu_get_clock();
494         }
495     case QEMU_CLOCK_HOST:
496         now = get_clock_realtime();
497         last = clock->last;
498         clock->last = now;
499         if (now < last) {
500             notifier_list_notify(&clock->reset_notifiers, &now);
501         }
502         return now;
503     }
504 }
505
506 void qemu_clock_register_reset_notifier(QEMUClockType type,
507                                         Notifier *notifier)
508 {
509     QEMUClock *clock = qemu_clock_ptr(type);
510     notifier_list_add(&clock->reset_notifiers, notifier);
511 }
512
513 void qemu_clock_unregister_reset_notifier(QEMUClockType type,
514                                           Notifier *notifier)
515 {
516     notifier_remove(notifier);
517 }
518
519 void init_clocks(void)
520 {
521     QEMUClockType type;
522     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
523         qemu_clock_init(type);
524     }
525
526 #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
527     prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
528 #endif
529 }
530
531 uint64_t timer_expire_time_ns(QEMUTimer *ts)
532 {
533     return timer_pending(ts) ? ts->expire_time : -1;
534 }
535
536 bool qemu_clock_run_all_timers(void)
537 {
538     bool progress = false;
539     QEMUClockType type;
540
541     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
542         progress |= qemu_clock_run_timers(type);
543     }
544
545     return progress;
546 }