diff mbox

[PATCHv11,13/31] aio / timers: aio_ctx_prepare sets timeout from AioContext timers

Message ID 1376598879-18976-14-git-send-email-alex@alex.org.uk
State New
Headers show

Commit Message

Alex Bligh Aug. 15, 2013, 8:34 p.m. UTC
Calculate the timeout in aio_ctx_prepare taking into account
the timers attached to the AioContext.

Alter aio_ctx_check similarly.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
---
 async.c |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

Comments

Wayne Xia Aug. 20, 2013, 3:08 a.m. UTC | #1
于 2013-8-16 4:34, Alex Bligh 写道:
> Calculate the timeout in aio_ctx_prepare taking into account
> the timers attached to the AioContext.
> 
> Alter aio_ctx_check similarly.
> 
> Signed-off-by: Alex Bligh <alex@alex.org.uk>
> ---
>   async.c |   13 +++++++++++--
>   1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/async.c b/async.c
> index 2b9ba9b..d8656cc 100644
> --- a/async.c
> +++ b/async.c
> @@ -150,13 +150,14 @@ aio_ctx_prepare(GSource *source, gint    *timeout)
>   {
>       AioContext *ctx = (AioContext *) source;
>       QEMUBH *bh;
> +    int deadline;
> 
>       for (bh = ctx->first_bh; bh; bh = bh->next) {
>           if (!bh->deleted && bh->scheduled) {
>               if (bh->idle) {
>                   /* idle bottom halves will be polled at least
>                    * every 10ms */
> -                *timeout = 10;
> +                *timeout = qemu_soonest_timeout(*timeout, 10);
    glib will not set *timeout to a meaningful value before calling
aio_ctx_prepare(), right? If so, "*timeout = 10" should be used.

>               } else {
>                   /* non-idle bottom halves will be executed
>                    * immediately */
> @@ -166,6 +167,14 @@ aio_ctx_prepare(GSource *source, gint    *timeout)
>           }
>       }
> 
> +    deadline = qemu_timeout_ns_to_ms(timerlistgroup_deadline_ns(&ctx->tlg));
> +    if (deadline == 0) {
> +        *timeout = 0;
> +        return true;
> +    } else {
> +        *timeout = qemu_soonest_timeout(*timeout, deadline);
> +    }
> +
>       return false;
>   }
> 
> @@ -180,7 +189,7 @@ aio_ctx_check(GSource *source)
>               return true;
>   	}
>       }
> -    return aio_pending(ctx);
> +    return aio_pending(ctx) || (timerlistgroup_deadline_ns(&ctx->tlg) == 0);
>   }
> 
>   static gboolean
>
Alex Bligh Aug. 20, 2013, 6:48 a.m. UTC | #2
>> 
>>      for (bh = ctx->first_bh; bh; bh = bh->next) {
>>          if (!bh->deleted && bh->scheduled) {
>>              if (bh->idle) {
>>                  /* idle bottom halves will be polled at least
>>                   * every 10ms */
>> -                *timeout = 10;
>> +                *timeout = qemu_soonest_timeout(*timeout, 10);
>    glib will not set *timeout to a meaningful value before calling
> aio_ctx_prepare(), right? If so, "*timeout = 10" should be used.


I don't think that's correct. Each _prepare routine is called
and has the abilitiy to alter the timeout but need not
set it at all. Indeed it should not set it as there may already
be a shorter timeout there.

Here's the code before I touched it:

aio_ctx_prepare(GSource *source, gint    *timeout)
{
    AioContext *ctx = (AioContext *) source;
    QEMUBH *bh;

    for (bh = ctx->first_bh; bh; bh = bh->next) {
        if (!bh->deleted && bh->scheduled) {
            if (bh->idle) {
                /* idle bottom halves will be polled at least
                 * every 10ms */
                *timeout = 10;
            } else {
                /* non-idle bottom halves will be executed
                 * immediately */
                *timeout = 0;
                return true;
            }
        }
    }

    return false;
}

You'll note that what this does is:
a) if there are no bottom halves, leaves *timeout as is
b) if there is a non-idle bottom half, set timeout to 0
c) else set timeout to 10 if there are only idle bottom
   halves.

Arguably (c) is a bug if timeout was shorter than 10
on entry but the whole of idle bhs are a bit of a bodge.
This is fixed by my series.

If you are asking WHERE it gets set to -1, I don't claim
to be a glib expert but I believe it's the line
  gint source_timeout = -1
around line 2816 in glib/gmain.c
Wayne Xia Aug. 20, 2013, 7:19 a.m. UTC | #3
于 2013-8-20 14:48, Alex Bligh 写道:
>>>
>>>       for (bh = ctx->first_bh; bh; bh = bh->next) {
>>>           if (!bh->deleted && bh->scheduled) {
>>>               if (bh->idle) {
>>>                   /* idle bottom halves will be polled at least
>>>                    * every 10ms */
>>> -                *timeout = 10;
>>> +                *timeout = qemu_soonest_timeout(*timeout, 10);
>>     glib will not set *timeout to a meaningful value before calling
>> aio_ctx_prepare(), right? If so, "*timeout = 10" should be used.
>
>
> I don't think that's correct. Each _prepare routine is called
> and has the abilitiy to alter the timeout but need not
> set it at all. Indeed it should not set it as there may already
> be a shorter timeout there.
>
> Here's the code before I touched it:
>
> aio_ctx_prepare(GSource *source, gint    *timeout)
> {
>      AioContext *ctx = (AioContext *) source;
>      QEMUBH *bh;
>
>      for (bh = ctx->first_bh; bh; bh = bh->next) {
>          if (!bh->deleted && bh->scheduled) {
>              if (bh->idle) {
>                  /* idle bottom halves will be polled at least
>                   * every 10ms */
>                  *timeout = 10;
>              } else {
>                  /* non-idle bottom halves will be executed
>                   * immediately */
>                  *timeout = 0;
>                  return true;
>              }
>          }
>      }
>
>      return false;
> }
>
> You'll note that what this does is:
> a) if there are no bottom halves, leaves *timeout as is
> b) if there is a non-idle bottom half, set timeout to 0
> c) else set timeout to 10 if there are only idle bottom
>     halves.
>
> Arguably (c) is a bug if timeout was shorter than 10
> on entry but the whole of idle bhs are a bit of a bodge.
> This is fixed by my series.
>
> If you are asking WHERE it gets set to -1, I don't claim
> to be a glib expert but I believe it's the line
>    gint source_timeout = -1
> around line 2816 in glib/gmain.c
>
   Thanks for the explanation. It seems *timeout is always set
to -1 before calling GSource's prepare(), so
"*timeout = qemu_soonest_timeout(*timeout, 10);"
will always get *timeout = 10, so this call can be saved.
Alex Bligh Aug. 20, 2013, 9:29 a.m. UTC | #4
On 20 Aug 2013, at 08:19, Wenchao Xia wrote:

>  Thanks for the explanation. It seems *timeout is always set
> to -1 before calling GSource's prepare(), so
> "*timeout = qemu_soonest_timeout(*timeout, 10);"
> will always get *timeout = 10, so this call can be saved.

I believe that's incorrect too. glib *currently* calls
the API that way, but there's nothing to say a future
or past glub couldn't call each g_source with the same
timeout pointer, with each g_source adjusting the timeout
downwards. Or (for instance) call it with 0 for a
non-blocking prepare. Therefore the implemented way
is safer (only reducing the timeout).
Wayne Xia Aug. 20, 2013, 11:19 a.m. UTC | #5
于 2013-8-20 17:29, Alex Bligh 写道:
>
> On 20 Aug 2013, at 08:19, Wenchao Xia wrote:
>
>>   Thanks for the explanation. It seems *timeout is always set
>> to -1 before calling GSource's prepare(), so
>> "*timeout = qemu_soonest_timeout(*timeout, 10);"
>> will always get *timeout = 10, so this call can be saved.
>
> I believe that's incorrect too. glib *currently* calls
> the API that way, but there's nothing to say a future
> or past glub couldn't call each g_source with the same
> timeout pointer, with each g_source adjusting the timeout
> downwards. Or (for instance) call it with 0 for a
   So it is an undefined value, should avoid use it?
For example, other gsource have minimum timeout of 5, and
aio_ctx_prepare() is called with 0, then returned timeout
is 0, but it is supposed to work with timeout 5 as the glib
doc described:
https://developer.gnome.org/glib/2.32/glib-The-Main-Event-Loop.html#GSourceFuncs

That is my opinion, but I haven't read other project's
code about prepare() usage, so can't be sure. Guess maintainer
can give a conclusion.


> non-blocking prepare. Therefore the implemented way
> is safer (only reducing the timeout).
>
Alex Bligh Aug. 20, 2013, 1:35 p.m. UTC | #6
On 20 Aug 2013, at 12:19, Wenchao Xia wrote:
> So it is an undefined value, should avoid use it?


It's not an undefined value. It's the value that the poll should
wait for subject to modification by the prepare call.
Stefan Hajnoczi Aug. 21, 2013, 9:01 a.m. UTC | #7
On Thu, Aug 15, 2013 at 09:34:21PM +0100, Alex Bligh wrote:
> @@ -150,13 +150,14 @@ aio_ctx_prepare(GSource *source, gint    *timeout)
>  {
>      AioContext *ctx = (AioContext *) source;
>      QEMUBH *bh;
> +    int deadline;
>  
>      for (bh = ctx->first_bh; bh; bh = bh->next) {
>          if (!bh->deleted && bh->scheduled) {
>              if (bh->idle) {
>                  /* idle bottom halves will be polled at least
>                   * every 10ms */
> -                *timeout = 10;
> +                *timeout = qemu_soonest_timeout(*timeout, 10);
>              } else {
>                  /* non-idle bottom halves will be executed
>                   * immediately */

I agree with Wenchao:

The docs explicitly say that .prepare() can set timeout to the maximum
timeout value that is required.  It then explains that the "actual
timeout used" is the minimum of all timeout values - it's not our job to
calculate the minimum, glib will do that after calling all .prepare()
functions.

I would drop this hunk.

Stefan
Alex Bligh Aug. 21, 2013, 10:07 a.m. UTC | #8
Stefan,

--On 21 August 2013 11:01:42 +0200 Stefan Hajnoczi <stefanha@gmail.com> 
wrote:

> I agree with Wenchao:
>
> The docs explicitly say that .prepare() can set timeout to the maximum
> timeout value that is required.  It then explains that the "actual
> timeout used" is the minimum of all timeout values - it's not our job to
> calculate the minimum, glib will do that after calling all .prepare()
> functions.
>
> I would drop this hunk.

OK I will put that into v13.

Anything else for v13 or are you ready to merge? I will rebase (again)
on block-next obviously.
diff mbox

Patch

diff --git a/async.c b/async.c
index 2b9ba9b..d8656cc 100644
--- a/async.c
+++ b/async.c
@@ -150,13 +150,14 @@  aio_ctx_prepare(GSource *source, gint    *timeout)
 {
     AioContext *ctx = (AioContext *) source;
     QEMUBH *bh;
+    int deadline;
 
     for (bh = ctx->first_bh; bh; bh = bh->next) {
         if (!bh->deleted && bh->scheduled) {
             if (bh->idle) {
                 /* idle bottom halves will be polled at least
                  * every 10ms */
-                *timeout = 10;
+                *timeout = qemu_soonest_timeout(*timeout, 10);
             } else {
                 /* non-idle bottom halves will be executed
                  * immediately */
@@ -166,6 +167,14 @@  aio_ctx_prepare(GSource *source, gint    *timeout)
         }
     }
 
+    deadline = qemu_timeout_ns_to_ms(timerlistgroup_deadline_ns(&ctx->tlg));
+    if (deadline == 0) {
+        *timeout = 0;
+        return true;
+    } else {
+        *timeout = qemu_soonest_timeout(*timeout, deadline);
+    }
+
     return false;
 }
 
@@ -180,7 +189,7 @@  aio_ctx_check(GSource *source)
             return true;
 	}
     }
-    return aio_pending(ctx);
+    return aio_pending(ctx) || (timerlistgroup_deadline_ns(&ctx->tlg) == 0);
 }
 
 static gboolean