qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based tim


From: Anthony Liguori
Subject: Re: [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer
Date: Mon, 22 Aug 2011 14:26:48 -0500
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110516 Lightning/1.0b2 Thunderbird/3.1.10

On 08/22/2011 02:21 PM, Anthony Liguori wrote:
This was originally written by Paolo Bonzini.

Signed-off-by: Anthony Liguori<address@hidden>

FYI, all of these glib integration patches are available at:

http://repo.or.cz/w/qemu/aliguori.git/shortlog/refs/heads/glib-main

But be forewarned, they may eat your lunch and steal your stapler.

Regards,

Anthony Liguori

---
  Makefile.objs |    1 +
  configure     |    4 +-
  ghrtimer.c    |  334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  ghrtimer.h    |   49 +++++++++
  4 files changed, 386 insertions(+), 2 deletions(-)
  create mode 100644 ghrtimer.c
  create mode 100644 ghrtimer.h

diff --git a/Makefile.objs b/Makefile.objs
index d1f3e5d..e4267ed 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -9,6 +9,7 @@ qobject-obj-y += qerror.o error.o
  oslib-obj-y = osdep.o
  oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
  oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
+oslib-obj-y += ghrtimer.o

  #######################################################################
  # coroutines
diff --git a/configure b/configure
index 8bbd694..6339c45 100755
--- a/configure
+++ b/configure
@@ -1843,8 +1843,8 @@ fi
  ##########################################
  # glib support probe
  if $pkg_config --modversion gthread-2.0>  /dev/null 2>&1 ; then
-    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
-    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
+    glib_cflags=`$pkg_config --cflags gthread-2.0 gobject-2.0 2>/dev/null`
+    glib_libs=`$pkg_config --libs gthread-2.0 gobject-2.0 2>/dev/null`
      LIBS="$glib_libs $LIBS"
      libs_qga="$glib_libs $libs_qga"
  else
diff --git a/ghrtimer.c b/ghrtimer.c
new file mode 100644
index 0000000..1e7e1c2
--- /dev/null
+++ b/ghrtimer.c
@@ -0,0 +1,334 @@
+/*
+ * timerfd GSource wrapper
+ *
+ * Copyright IBM, Corp. 2011
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *  Anthony Liguori<address@hidden>
+ *  Paolo Bonzini<address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "config-host.h"
+#include<stdlib.h>
+#include "ghrtimer.h"
+#include<glib-object.h>
+#include<fcntl.h>
+#include<unistd.h>
+
+#ifdef CONFIG_TIMERFD
+#include<sys/timerfd.h>
+#endif
+
+struct _GHRTimer {
+    GSource                source;
+    gint64                 deadline;
+    GPollFD                 poll;
+    char                   pending;
+};
+
+#define MIN_TIMER_REARM_NS     250000
+
+#if GLIB_MAJOR_VERSION == 2&&  GLIB_MINOR_VERSION<= 26
+static inline guint64 muldiv64(guint64 a, guint32 b, guint32 c)
+{
+    guint64 rl = (a&  0xffffffff) * (guint64)b;
+    guint64 rh = (a>>  32) * (guint64)b + (rl>>  32);
+    rl&= 0xffffffff;
+    return ((rh / c)<<  32) | ((((rh % c)<<  32) + rl) / c);
+}
+
+gint64
+g_get_monotonic_time_ns (void)
+{
+#if defined(__linux__) || (defined(__FreeBSD__)&&  __FreeBSD_version>= 500000) 
\
+            || defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
+            || defined(__OpenBSD__)
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC,&ts);
+    return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+
+#elif defined _WIN32
+    LARGE_INTEGER ti;
+    static LARGE_INTEGER freq;
+    if (freq.QuadPart == 0) {
+        QueryPerformanceFrequency(&freq);
+    }
+    QueryPerformanceCounter(&ti);
+    return muldiv64(ti.QuadPart, 1000000000, freq.QuadPart);
+
+#else
+#ifdef CONFIG_TIMERFD
+#error configuration problem, timerfd uses CLOCK_MONOTONIC
+#endif
+    GTimeVal tv;
+    g_get_current_time (&tv);
+    return ((guint64) tv.tv_sec) * 1000000000 + tv.tv_usec * 1000;
+#endif
+}
+
+gint64
+g_source_get_time_ns (GSource *source)
+{
+    return g_get_monotonic_time_ns ();
+}
+
+#else
+gint64
+g_get_monotonic_time_ns (void)
+{
+    return g_get_monotonic_time () * 1000;
+}
+
+gint64
+g_source_get_time_ns (GSource *source)
+{
+    return g_source_get_time (source) * 1000;
+}
+#endif
+
+gboolean
+g_hrtimer_pending (GHRTimer *timer)
+{
+    return timer->pending;
+}
+
+void
+g_hrtimer_rearm (GHRTimer *timer,
+                gint64    us)
+{
+    return g_hrtimer_rearm_ns (timer, us * 1000);
+}
+
+void
+g_hrtimer_rearm_ns (GHRTimer *timer,
+                   gint64    ns)
+{
+    gint64 time = g_get_monotonic_time_ns ();
+    timer->deadline = ns;
+    if (ns<  time) {
+       timer->pending = TRUE;
+       return;
+    }
+
+    timer->pending = FALSE;
+    if (ns == G_HRTIMER_QUIESCE) {
+       return;
+    }
+
+    if (ns - time<  MIN_TIMER_REARM_NS) {
+        timer->deadline = ns = time + MIN_TIMER_REARM_NS;
+    }
+#ifdef CONFIG_TIMERFD
+    if (timer->poll.fd != -1) {
+        struct itimerspec new = {
+            .it_interval = { 0, 0 },
+            .it_value = { ns / 1000000000, ns % 1000000000 }
+        };
+        timerfd_settime(timer->poll.fd, TFD_TIMER_ABSTIME,&new, NULL);
+    }
+#endif
+}
+
+static gboolean
+g_hrtimer_prepare (GSource *source,
+                   gint    *timeout)
+{
+    GHRTimer *timer = (GHRTimer *) source;
+
+    if (timer->deadline == G_HRTIMER_QUIESCE) {
+       g_assert (!timer->pending);
+       *timeout = -1;
+       return FALSE;
+    }
+
+    if (timer->poll.fd == -1) {
+        gint64 timeout_ns = timer->deadline - g_get_monotonic_time_ns ();
+       if (timeout_ns<  0) {
+           *timeout = 0;
+            timer->pending = TRUE;
+       } else {
+            *timeout = timeout_ns / 1000000;
+       }
+    } else {
+       *timeout = -1;
+#ifndef CONFIG_TIMERFD
+        abort ();
+#endif
+    }
+    return timer->pending;
+}
+
+static gboolean
+g_hrtimer_check (GSource *source)
+{
+    GHRTimer *timer = (GHRTimer *) source;
+
+    if (timer->deadline == G_HRTIMER_QUIESCE) {
+       g_assert (!timer->pending);
+       return FALSE;
+    }
+
+    if (timer->poll.fd == -1) {
+        timer->pending |= (timer->deadline<= g_source_get_time_ns (source));
+    } else {
+        long long overrun;
+        timer->pending |= (timer->poll.revents&  G_IO_IN) != 0;
+       if (timer->pending) {
+           if (read (timer->poll.fd, (char *)&overrun, sizeof (overrun))) {
+               /* do nothing */
+            }
+       }
+#ifndef CONFIG_TIMERFD
+        abort ();
+#endif
+    }
+
+    return timer->pending;
+}
+
+static gboolean
+g_hrtimer_dispatch (GSource *source,
+                    GSourceFunc  callback,
+                    gpointer     user_data)
+{
+    GHRTimer *timer = (GHRTimer *) source;
+
+    if (!callback) {
+        g_warning ("Timer source dispatched without callback\n"
+                   "You must call g_source_set_callback().");
+        return TRUE;
+    }
+
+    timer->pending = FALSE;
+    timer->deadline = G_HRTIMER_QUIESCE;
+    if (user_data == NULL)
+        user_data = timer;
+    callback (user_data);
+    return TRUE;
+}
+
+static void
+g_hrtimer_finalize (GSource *source)
+{
+    GHRTimer *timer = (GHRTimer *) source;
+
+    if (timer->poll.fd != -1) {
+        close (timer->poll.fd);
+#ifndef CONFIG_TIMERFD
+        abort ();
+#endif
+    }
+}
+
+static void
+g_hrtimer_closure_callback (gpointer data)
+{
+    GClosure *closure = data;
+    g_closure_invoke (closure, NULL, 0, NULL, NULL);
+}
+
+static GSourceFuncs hrtimer_source_funcs = {
+  g_hrtimer_prepare,
+  g_hrtimer_check,
+  g_hrtimer_dispatch,
+  g_hrtimer_finalize,
+  (GSourceFunc) g_hrtimer_closure_callback,
+  (gpointer) g_cclosure_marshal_VOID__VOID
+};
+
+GHRTimer *
+g_hrtimer_new (void)
+{
+    GHRTimer *timer;
+
+    timer = (GHRTimer *) g_source_new (&hrtimer_source_funcs,
+                                       sizeof (GHRTimer));
+
+#ifdef CONFIG_TIMERFD
+    timer->poll.fd = timerfd_create (CLOCK_MONOTONIC, 0);
+    if (timer->poll.fd != -1) {
+        fcntl(timer->poll.fd, F_SETFD, fcntl (timer->poll.fd, F_GETFD) | 
FD_CLOEXEC);
+        fcntl(timer->poll.fd, F_SETFL, fcntl (timer->poll.fd, F_GETFL) | 
O_NONBLOCK);
+        timer->poll.events = G_IO_IN;
+        g_source_add_poll (&timer->source,&timer->poll);
+    }
+#else
+    timer->poll.fd = -1;
+#endif
+    timer->deadline = G_HRTIMER_QUIESCE;
+    return timer;
+}
+guint
+g_hrtimer_add (GHRTimer     **timer,
+              GSourceFunc    func,
+              gpointer       user_data)
+{
+    return g_hrtimer_add_full (G_PRIORITY_DEFAULT, timer, func, user_data, 
NULL);
+}
+
+guint
+g_hrtimer_add_full (gint              priority,
+                   GHRTimer        **timer,
+                   GSourceFunc       func,
+                   gpointer          user_data,
+                   GDestroyNotify    notify)
+{
+    GHRTimer *hrtimer;
+    guint id;
+
+    hrtimer = g_hrtimer_new ();
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority (&hrtimer->source, priority);
+
+    g_source_set_callback (&hrtimer->source, (GSourceFunc) func,
+                           user_data, notify);
+    id = g_source_attach (&hrtimer->source, NULL);
+
+    *timer = hrtimer;
+    return id;
+}
+
+#ifdef MAIN
+#include<stdio.h>
+
+static int i = 3;
+static GMainLoop *loop;
+
+void
+rearm_timer (GHRTimer *timer)
+{
+    printf (".");
+    fflush (stdout);
+    g_hrtimer_rearm_ns (timer, g_get_monotonic_time_ns () + 1000000000);
+}
+
+void
+hrtimer_callback (gpointer user_data)
+{
+    GHRTimer *timer = user_data;
+
+    if (--i == 0) {
+        printf ("\n");
+        fflush (stdout);
+        g_main_loop_quit (loop);
+    } else {
+        rearm_timer (timer);
+    }
+}
+
+int main()
+{
+    GHRTimer *timer;
+    loop = g_main_loop_new (NULL, FALSE);
+    g_hrtimer_add (&timer, (GSourceFunc) hrtimer_callback, NULL);
+    rearm_timer (timer);
+    g_main_loop_run (loop);
+    g_source_unref ((GSource *) timer);
+}
+#endif
+
diff --git a/ghrtimer.h b/ghrtimer.h
new file mode 100644
index 0000000..2cf6961
--- /dev/null
+++ b/ghrtimer.h
@@ -0,0 +1,49 @@
+/*
+ * timerfd GSource wrapper
+ *
+ * Copyright IBM, Corp. 2011
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *  Anthony Liguori<address@hidden>
+ *  Paolo Bonzini<address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef G_HRTIMER_H
+#define G_HRTIMER_H 1
+
+#include<glib.h>
+
+#define G_HRTIMER_QUIESCE      ((gint64) 0x7FFFFFFFFFFFFFFF)
+
+typedef struct _GHRTimer GHRTimer;
+
+gint64 g_get_monotonic_time_ns (void);
+
+gint64 g_source_get_time_ns    (GSource *source);
+
+GHRTimer *g_hrtimer_new        (void);
+
+gboolean g_hrtimer_pending     (GHRTimer               *timer);
+
+void   g_hrtimer_rearm         (GHRTimer               *timer,
+                                gint64                  usec);
+
+void   g_hrtimer_rearm_ns      (GHRTimer               *timer,
+                                gint64                  nsec);
+
+guint g_hrtimer_add           (GHRTimer               **timer,
+                               GSourceFunc              callback,
+                               gpointer                 user_data);
+
+guint g_hrtimer_add_full       (int                     priority,
+                               GHRTimer               **timer,
+                               GSourceFunc              callback,
+                               gpointer                 user_data,
+                               GDestroyNotify           notify);
+
+#endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]