---
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