All of lore.kernel.org
 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 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.