From: Anthony Liguori <anthony@codemonkey.ws>
To: Anthony Liguori <aliguori@us.ibm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
qemu-devel@nongnu.org,
Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>,
Jan Kiszka <jan.kiszka@siemens.com>
Subject: Re: [Qemu-devel] [PATCH 1/2] main: add high resolution GSource based timer
Date: Mon, 22 Aug 2011 14:26:48 -0500 [thread overview]
Message-ID: <4E52AD78.2040408@codemonkey.ws> (raw)
In-Reply-To: <1314040874-9259-1-git-send-email-aliguori@us.ibm.com>
On 08/22/2011 02:21 PM, Anthony Liguori wrote:
> This was originally written by Paolo Bonzini.
>
> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
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<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
prev parent reply other threads:[~2011-08-22 19:26 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Anthony Liguori [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E52AD78.2040408@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=aliguori@us.ibm.com \
--cc=jan.kiszka@siemens.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).