qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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

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