]> git.proxmox.com Git - qemu.git/blobdiff - qemu-timer.c
virtio-net: properly check the vhost status during status set
[qemu.git] / qemu-timer.c
index 17915df22d719839d4e5ceca2ed1612abe4f5963..b2d95e2fec8ecf852dd6ebc0c329556da18244bb 100644 (file)
  * THE SOFTWARE.
  */
 
-#include "sysemu.h"
-#include "net.h"
-#include "monitor.h"
-#include "console.h"
+#include "sysemu/sysemu.h"
+#include "monitor/monitor.h"
+#include "ui/console.h"
 
 #include "hw/hw.h"
 
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <signal.h>
-#ifdef __FreeBSD__
-#include <sys/param.h>
+#include "qemu/timer.h"
+#ifdef CONFIG_POSIX
+#include <pthread.h>
 #endif
 
 #ifdef _WIN32
-#include <windows.h>
 #include <mmsystem.h>
 #endif
 
-#include "qemu-timer.h"
-
 /***********************************************************/
 /* timers */
 
 #define QEMU_CLOCK_HOST     2
 
 struct QEMUClock {
-    int type;
-    int enabled;
-
     QEMUTimer *active_timers;
 
     NotifierList reset_notifiers;
     int64_t last;
+
+    int type;
+    bool enabled;
 };
 
 struct QEMUTimer {
-    QEMUClock *clock;
     int64_t expire_time;       /* in nanoseconds */
-    int scale;
+    QEMUClock *clock;
     QEMUTimerCB *cb;
     void *opaque;
-    struct QEMUTimer *next;
+    QEMUTimer *next;
+    int scale;
 };
 
 struct qemu_alarm_timer {
@@ -78,13 +69,13 @@ struct qemu_alarm_timer {
     void (*stop)(struct qemu_alarm_timer *t);
     void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns);
 #if defined(__linux__)
-    int fd;
     timer_t timer;
+    int fd;
 #elif defined(_WIN32)
     HANDLE timer;
 #endif
-    char expired;
-    char pending;
+    bool expired;
+    bool pending;
 };
 
 static struct qemu_alarm_timer *alarm_timer;
@@ -94,35 +85,23 @@ static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time)
     return timer_head && (timer_head->expire_time <= current_time);
 }
 
-int qemu_alarm_pending(void)
-{
-    return alarm_timer->pending;
-}
-
-static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
-{
-    return !!t->rearm;
-}
-
 static int64_t qemu_next_alarm_deadline(void)
 {
-    int64_t delta;
+    int64_t delta = INT64_MAX;
     int64_t rtdelta;
 
-    if (!use_icount && vm_clock->active_timers) {
+    if (!use_icount && vm_clock->enabled && vm_clock->active_timers) {
         delta = vm_clock->active_timers->expire_time -
                      qemu_get_clock_ns(vm_clock);
-    } else {
-        delta = INT32_MAX;
     }
-    if (host_clock->active_timers) {
+    if (host_clock->enabled && host_clock->active_timers) {
         int64_t hdelta = host_clock->active_timers->expire_time -
                  qemu_get_clock_ns(host_clock);
         if (hdelta < delta) {
             delta = hdelta;
         }
     }
-    if (rt_clock->active_timers) {
+    if (rt_clock->enabled && rt_clock->active_timers) {
         rtdelta = (rt_clock->active_timers->expire_time -
                  qemu_get_clock_ns(rt_clock));
         if (rtdelta < delta) {
@@ -135,15 +114,10 @@ static int64_t qemu_next_alarm_deadline(void)
 
 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 {
-    int64_t nearest_delta_ns;
-    assert(alarm_has_dynticks(t));
-    if (!rt_clock->active_timers &&
-        !vm_clock->active_timers &&
-        !host_clock->active_timers) {
-        return;
+    int64_t nearest_delta_ns = qemu_next_alarm_deadline();
+    if (nearest_delta_ns < INT64_MAX) {
+        t->rearm(t, nearest_delta_ns);
     }
-    nearest_delta_ns = qemu_next_alarm_deadline();
-    t->rearm(t, nearest_delta_ns);
 }
 
 /* TODO: MIN_TIMER_REARM_NS should be optimized */
@@ -207,7 +181,7 @@ void configure_alarms(char const *opt)
     char *name;
     struct qemu_alarm_timer tmp;
 
-    if (!strcmp(opt, "?")) {
+    if (is_help_option(opt)) {
         show_available_alarms();
         exit(0);
     }
@@ -263,13 +237,13 @@ static QEMUClock *qemu_new_clock(int type)
 
     clock = g_malloc0(sizeof(QEMUClock));
     clock->type = type;
-    clock->enabled = 1;
+    clock->enabled = true;
     clock->last = INT64_MIN;
     notifier_list_init(&clock->reset_notifiers);
     return clock;
 }
 
-void qemu_clock_enable(QEMUClock *clock, int enabled)
+void qemu_clock_enable(QEMUClock *clock, bool enabled)
 {
     bool old = clock->enabled;
     clock->enabled = enabled;
@@ -382,38 +356,38 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
     qemu_mod_timer_ns(ts, expire_time * ts->scale);
 }
 
-int qemu_timer_pending(QEMUTimer *ts)
+bool qemu_timer_pending(QEMUTimer *ts)
 {
     QEMUTimer *t;
     for (t = ts->clock->active_timers; t != NULL; t = t->next) {
-        if (t == ts)
-            return 1;
+        if (t == ts) {
+            return true;
+        }
     }
-    return 0;
+    return false;
 }
 
-int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
+bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
 {
     return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
 }
 
 void qemu_run_timers(QEMUClock *clock)
 {
-    QEMUTimer **ptimer_head, *ts;
+    QEMUTimer *ts;
     int64_t current_time;
    
     if (!clock->enabled)
         return;
 
     current_time = qemu_get_clock_ns(clock);
-    ptimer_head = &clock->active_timers;
     for(;;) {
-        ts = *ptimer_head;
+        ts = clock->active_timers;
         if (!qemu_timer_expired_ns(ts, current_time)) {
             break;
         }
         /* remove timer from the list before calling the callback */
-        *ptimer_head = ts->next;
+        clock->active_timers = ts->next;
         ts->next = NULL;
 
         /* run the callback (the timer list can be modified) */
@@ -458,9 +432,11 @@ void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 
 void init_clocks(void)
 {
-    rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
-    vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
-    host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
+    if (!rt_clock) {
+        rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
+        vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
+        host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
+    }
 }
 
 uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
@@ -470,7 +446,7 @@ uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
 
 void qemu_run_all_timers(void)
 {
-    alarm_timer->pending = 0;
+    alarm_timer->pending = false;
 
     /* vm time timers */
     qemu_run_timers(vm_clock);
@@ -479,7 +455,7 @@ void qemu_run_all_timers(void)
 
     /* rearm timer, if not periodic */
     if (alarm_timer->expired) {
-        alarm_timer->expired = 0;
+        alarm_timer->expired = false;
         qemu_rearm_alarm_timer(alarm_timer);
     }
 }
@@ -494,17 +470,14 @@ static void host_alarm_handler(int host_signum)
     if (!t)
        return;
 
-    if (alarm_has_dynticks(t) ||
-        qemu_next_alarm_deadline () <= 0) {
-        t->expired = alarm_has_dynticks(t);
-        t->pending = 1;
-        qemu_notify_event();
-    }
+    t->expired = true;
+    t->pending = true;
+    qemu_notify_event();
 }
 
 #if defined(__linux__)
 
-#include "compatfd.h"
+#include "qemu/compatfd.h"
 
 static int dynticks_start_timer(struct qemu_alarm_timer *t)
 {
@@ -525,20 +498,16 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t)
     memset(&ev, 0, sizeof(ev));
     ev.sigev_value.sival_int = 0;
     ev.sigev_notify = SIGEV_SIGNAL;
-#ifdef SIGEV_THREAD_ID
+#ifdef CONFIG_SIGEV_THREAD_ID
     if (qemu_signalfd_available()) {
         ev.sigev_notify = SIGEV_THREAD_ID;
         ev._sigev_un._tid = qemu_get_thread_id();
     }
-#endif /* SIGEV_THREAD_ID */
+#endif /* CONFIG_SIGEV_THREAD_ID */
     ev.sigev_signo = SIGALRM;
 
     if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
         perror("timer_create");
-
-        /* disable dynticks */
-        fprintf(stderr, "Dynamic Ticks disabled\n");
-
         return -1;
     }
 
@@ -637,7 +606,7 @@ static void unix_stop_timer(struct qemu_alarm_timer *t)
 #ifdef _WIN32
 
 static MMRESULT mm_timer;
-static unsigned mm_period;
+static TIMECAPS mm_tc;
 
 static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
                                       DWORD_PTR dwUser, DWORD_PTR dw1,
@@ -647,72 +616,45 @@ static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
     if (!t) {
         return;
     }
-    if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) {
-        t->expired = alarm_has_dynticks(t);
-        t->pending = 1;
-        qemu_notify_event();
-    }
+    t->expired = true;
+    t->pending = true;
+    qemu_notify_event();
 }
 
 static int mm_start_timer(struct qemu_alarm_timer *t)
 {
-    TIMECAPS tc;
-    UINT flags;
-
-    memset(&tc, 0, sizeof(tc));
-    timeGetDevCaps(&tc, sizeof(tc));
-
-    mm_period = tc.wPeriodMin;
-    timeBeginPeriod(mm_period);
-
-    flags = TIME_CALLBACK_FUNCTION;
-    if (alarm_has_dynticks(t)) {
-        flags |= TIME_ONESHOT;
-    } else {
-        flags |= TIME_PERIODIC;
-    }
-
-    mm_timer = timeSetEvent(1,                  /* interval (ms) */
-                            mm_period,          /* resolution */
-                            mm_alarm_handler,   /* function */
-                            (DWORD_PTR)t,       /* parameter */
-                            flags);
-
-    if (!mm_timer) {
-        fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
-                GetLastError());
-        timeEndPeriod(mm_period);
-        return -1;
-    }
-
+    timeGetDevCaps(&mm_tc, sizeof(mm_tc));
     return 0;
 }
 
 static void mm_stop_timer(struct qemu_alarm_timer *t)
 {
-    timeKillEvent(mm_timer);
-    timeEndPeriod(mm_period);
+    if (mm_timer) {
+        timeKillEvent(mm_timer);
+    }
 }
 
 static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
 {
-    int nearest_delta_ms = (delta + 999999) / 1000000;
-    if (nearest_delta_ms < 1) {
-        nearest_delta_ms = 1;
+    int64_t nearest_delta_ms = delta / 1000000;
+    if (nearest_delta_ms < mm_tc.wPeriodMin) {
+        nearest_delta_ms = mm_tc.wPeriodMin;
+    } else if (nearest_delta_ms > mm_tc.wPeriodMax) {
+        nearest_delta_ms = mm_tc.wPeriodMax;
     }
 
-    timeKillEvent(mm_timer);
-    mm_timer = timeSetEvent(nearest_delta_ms,
-                            mm_period,
+    if (mm_timer) {
+        timeKillEvent(mm_timer);
+    }
+    mm_timer = timeSetEvent((UINT)nearest_delta_ms,
+                            mm_tc.wPeriodMin,
                             mm_alarm_handler,
                             (DWORD_PTR)t,
                             TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
 
     if (!mm_timer) {
-        fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
-                GetLastError());
-
-        timeEndPeriod(mm_period);
+        fprintf(stderr, "Failed to re-arm win32 alarm timer\n");
+        timeEndPeriod(mm_tc.wPeriodMin);
         exit(1);
     }
 }
@@ -731,7 +673,7 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
                           host_alarm_handler,
                           t,
                           1,
-                          alarm_has_dynticks(t) ? 3600000 : 1,
+                          3600000,
                           WT_EXECUTEINTIMERTHREAD);
 
     if (!success) {
@@ -757,16 +699,20 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t,
                               int64_t nearest_delta_ns)
 {
     HANDLE hTimer = t->timer;
-    int nearest_delta_ms;
+    int64_t nearest_delta_ms;
     BOOLEAN success;
 
-    nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
+    nearest_delta_ms = nearest_delta_ns / 1000000;
     if (nearest_delta_ms < 1) {
         nearest_delta_ms = 1;
     }
+    /* ULONG_MAX can be 32 bit */
+    if (nearest_delta_ms > ULONG_MAX) {
+        nearest_delta_ms = ULONG_MAX;
+    }
     success = ChangeTimerQueueTimer(NULL,
                                     hTimer,
-                                    nearest_delta_ms,
+                                    (unsigned long) nearest_delta_ms,
                                     3600000);
 
     if (!success) {
@@ -786,11 +732,28 @@ static void quit_timers(void)
     t->stop(t);
 }
 
+#ifdef CONFIG_POSIX
+static void reinit_timers(void)
+{
+    struct qemu_alarm_timer *t = alarm_timer;
+    t->stop(t);
+    if (t->start(t)) {
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+    qemu_rearm_alarm_timer(t);
+}
+#endif /* CONFIG_POSIX */
+
 int init_timer_alarm(void)
 {
     struct qemu_alarm_timer *t = NULL;
     int i, err = -1;
 
+    if (alarm_timer) {
+        return 0;
+    }
+
     for (i = 0; alarm_timers[i].name; i++) {
         t = &alarm_timers[i];
 
@@ -804,19 +767,14 @@ int init_timer_alarm(void)
         goto fail;
     }
 
-    /* first event is at time 0 */
     atexit(quit_timers);
-    t->pending = 1;
+#ifdef CONFIG_POSIX
+    pthread_atfork(NULL, NULL, reinit_timers);
+#endif
     alarm_timer = t;
-
     return 0;
 
 fail:
     return err;
 }
 
-int qemu_calculate_timeout(void)
-{
-    return 1000;
-}
-