All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer
@ 2011-08-22 19:21 Anthony Liguori
  2011-08-22 19:21 ` [Qemu-devel] [PATCH 2/2] [RFC] time: refactor QEMU timer to use GHRTimer Anthony Liguori
  2011-08-22 19:26 ` [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer Anthony Liguori
  0 siblings, 2 replies; 13+ messages in thread
From: Anthony Liguori @ 2011-08-22 19:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Anthony Liguori, Jan Kiszka

This was originally written by Paolo Bonzini.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 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   <aliguori@us.ibm.com>
+ *  Paolo Bonzini     <pbonzini@redhat.com>
+ *
+ * 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   <aliguori@us.ibm.com>
+ *  Paolo Bonzini     <pbonzini@redhat.com>
+ *
+ * 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
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2011-08-23 12:44 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-22 19:21 [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer Anthony Liguori
2011-08-22 19:21 ` [Qemu-devel] [PATCH 2/2] [RFC] time: refactor QEMU timer to use GHRTimer Anthony Liguori
2011-08-22 20:28   ` Jan Kiszka
2011-08-22 20:36     ` Anthony Liguori
2011-08-22 20:49       ` Jan Kiszka
2011-08-22 21:55         ` Anthony Liguori
2011-08-22 23:48           ` Jan Kiszka
2011-08-23  8:12     ` Paolo Bonzini
2011-08-23  9:07       ` Edgar E. Iglesias
2011-08-23  7:43   ` Paolo Bonzini
2011-08-23 12:33     ` Anthony Liguori
2011-08-23 12:44       ` Paolo Bonzini
2011-08-22 19:26 ` [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer Anthony Liguori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.