qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit
@ 2007-11-23 22:50 andrzej zaborowski
  2007-11-23 23:43 ` Paul Brook
  0 siblings, 1 reply; 5+ messages in thread
From: andrzej zaborowski @ 2007-11-23 22:50 UTC (permalink / raw)
  To: Qemu mailing list

Hi,
  There is a chance that when using "unix" or "dynticks" clock, the
signal arrives when no cpu is executing. The probability is high when
using dynticks and a timer is scheduled to expire very soon so that a
signal is delivered very soon after a previous signal. When that
happens cpu_single_env is zero and the signal handler does nothing.
This is not much problem with "unix" clocks or when not using
-nographic or when the guest OS uses interrupts, because a another
cpu_loop_exit will happen in not too long. If none of these conditions
is true the cpu loop starts spinning without a chance to exit and
process events. I used the following patch to prevent this but there's
probably a better way:

diff --git a/cpu-all.h b/cpu-all.h
index f4db592..c095e9c 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -706,6 +706,7 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
     __attribute__ ((__noreturn__));
 extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
+extern int env_pending_request;
 extern int code_copy_enabled;

 #define CPU_INTERRUPT_EXIT   0x01 /* wants exit from main loop */
diff --git a/cpu-exec.c b/cpu-exec.c
index 1c7356a..af75731 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -258,6 +258,11 @@ int cpu_exec(CPUState *env1)

     cpu_single_env = env1;

+    if (env_pending_request) {
+        cpu_interrupt(env1, env_pending_request);
+        env_pending_request = 0;
+    }
+
     /* first we save global registers */
 #define SAVE_HOST_REGS 1
 #include "hostregs_helper.h"
diff --git a/exec.c b/exec.c
index 6384df2..a649d8f 100644
--- a/exec.c
+++ b/exec.c
@@ -96,6 +96,7 @@ CPUState *first_cpu;
 /* current CPU in the current thread. It is only valid inside
    cpu_exec() */
 CPUState *cpu_single_env;
+int env_pending_request;

 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
@@ -1194,6 +1195,12 @@ void cpu_interrupt(CPUState *env, int mask)
     TranslationBlock *tb;
     static int interrupt_lock;

+    /* cause an interrupt in the first cpu that tries to start running */
+    if (!env) {
+        env_pending_request |= mask;
+        return;
+    }
+
     env->interrupt_request |= mask;
     /* if the cpu is currently executing code, we must unlink it and
        all the potentially executing TB */
diff --git a/vl.c b/vl.c
index 864a044..ec2aa84 100644
--- a/vl.c
+++ b/vl.c
@@ -1184,15 +1184,14 @@ static void host_alarm_handler(int host_signum)
         SetEvent(data->host_alarm);
 #endif
         CPUState *env = cpu_single_env;
-        if (env) {
-            /* stop the currently executing cpu because a timer occured */
-            cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+
+        /* stop the currently executing cpu because a timer occured */
+        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
 #ifdef USE_KQEMU
-            if (env->kqemu_enabled) {
-                kqemu_cpu_interrupt(env);
-            }
-#endif
+        if (env && env->kqemu_enabled) {
+            kqemu_cpu_interrupt(env);
         }
+#endif
     }
 }

Regards

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit
  2007-11-23 22:50 [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit andrzej zaborowski
@ 2007-11-23 23:43 ` Paul Brook
  2007-11-24 23:13   ` andrzej zaborowski
  0 siblings, 1 reply; 5+ messages in thread
From: Paul Brook @ 2007-11-23 23:43 UTC (permalink / raw)
  To: qemu-devel

>   There is a chance that when using "unix" or "dynticks" clock, the
> signal arrives when no cpu is executing.

I've seen similar stalls, but not managed to track down the source. Your 
analysis seems correct.

> +    /* cause an interrupt in the first cpu that tries to start running */
> +    if (!env) {
> +        env_pending_request | mask

IIUC We should assert that mask == CPU_INTERRUPT_EXIT. If we try to raise an 
actual interrupt without an active CPU then something else is wrong. In fact 
this probably means env_pending_request can be a simple boolean (indicating 
we want to break out of cpu_exec), rather than munging it into 
env->interrupt_request.

it took me a while to figure out exactly which race condition we're avoiding 
here. How adding a comment like:

/* There is a window for signals to arrive between main_loop checking for 
events and setting cpu_single_env here.  Check if this occurred and we need 
to exit back to the IO loop. */

> +    if (env_pending_request) {
> +        cpu_interrupt(env1, env_pending_request);
> +        env_pending_request = 0;
> +    }
> +

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit
  2007-11-23 23:43 ` Paul Brook
@ 2007-11-24 23:13   ` andrzej zaborowski
  2007-12-02 16:42     ` Thiemo Seufer
  0 siblings, 1 reply; 5+ messages in thread
From: andrzej zaborowski @ 2007-11-24 23:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paul Brook

On 24/11/2007, Paul Brook <paul@codesourcery.com> wrote:
> > There is a chance that when using "unix" or "dynticks" clock, the
> > signal arrives when no cpu is executing.

How about this version, this one touches vl.c only:

--- a/vl.c
+++ b/vl.c
@@ -236,6 +236,10 @@ const char *prom_envs[MAX_PROM_ENVS];
 struct bt_piconet_s *local_piconet;
 struct modem_ops_s modem_ops;

+static CPUState *cur_cpu;
+static CPUState *next_cpu;
+static int event_pending;
+
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)

 /***********************************************************/
@@ -1183,16 +1187,16 @@ static void host_alarm_handler(int host_signum)
         struct qemu_alarm_win32 *data = ((struct
qemu_alarm_timer*)dwUser)->priv;
         SetEvent(data->host_alarm);
 #endif
-        CPUState *env = cpu_single_env;
-        if (env) {
-            /* stop the currently executing cpu because a timer occured */
-            cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+        CPUState *env = next_cpu;
+
+        /* stop the currently executing cpu because a timer occured */
+        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
 #ifdef USE_KQEMU
-            if (env->kqemu_enabled) {
-                kqemu_cpu_interrupt(env);
-            }
-#endif
+        if (env->kqemu_enabled) {
+            kqemu_cpu_interrupt(env);
         }
+#endif
+        event_pending = 1;
     }
 }

@@ -7168,8 +7172,6 @@ void main_loop_wait(int timeout)

 }

-static CPUState *cur_cpu;
-
 static int main_loop(void)
 {
     int ret, timeout;
@@ -7179,15 +7181,13 @@ static int main_loop(void)
     CPUState *env;

     cur_cpu = first_cpu;
+    next_cpu = cur_cpu->next_cpu ?: first_cpu;
     for(;;) {
         if (vm_running) {

-            env = cur_cpu;
             for(;;) {
                 /* get next cpu */
-                env = env->next_cpu;
-                if (!env)
-                    env = first_cpu;
+                env = next_cpu;
 #ifdef CONFIG_PROFILER
                 ti = profile_getclock();
 #endif
@@ -7195,6 +7195,12 @@ static int main_loop(void)
 #ifdef CONFIG_PROFILER
                 qemu_time += profile_getclock() - ti;
 #endif
+                next_cpu = env->next_cpu ?: first_cpu;
+                if (event_pending) {
+                    ret = EXCP_INTERRUPT;
+                    event_pending = 0;
+                    break;
+                }
                 if (ret == EXCP_HLT) {
                     /* Give the next CPU a chance to run.  */
                     cur_cpu = env;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit
  2007-11-24 23:13   ` andrzej zaborowski
@ 2007-12-02 16:42     ` Thiemo Seufer
  2007-12-03  3:06       ` andrzej zaborowski
  0 siblings, 1 reply; 5+ messages in thread
From: Thiemo Seufer @ 2007-12-02 16:42 UTC (permalink / raw)
  To: andrzej zaborowski; +Cc: Paul Brook, qemu-devel

andrzej zaborowski wrote:
> On 24/11/2007, Paul Brook <paul@codesourcery.com> wrote:
> > > There is a chance that when using "unix" or "dynticks" clock, the
> > > signal arrives when no cpu is executing.
> 
> How about this version, this one touches vl.c only:

Any reason why this isn't in CVS?


Thiemo

> --- a/vl.c
> +++ b/vl.c
> @@ -236,6 +236,10 @@ const char *prom_envs[MAX_PROM_ENVS];
>  struct bt_piconet_s *local_piconet;
>  struct modem_ops_s modem_ops;
> 
> +static CPUState *cur_cpu;
> +static CPUState *next_cpu;
> +static int event_pending;
> +
>  #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
> 
>  /***********************************************************/
> @@ -1183,16 +1187,16 @@ static void host_alarm_handler(int host_signum)
>          struct qemu_alarm_win32 *data = ((struct
> qemu_alarm_timer*)dwUser)->priv;
>          SetEvent(data->host_alarm);
>  #endif
> -        CPUState *env = cpu_single_env;
> -        if (env) {
> -            /* stop the currently executing cpu because a timer occured */
> -            cpu_interrupt(env, CPU_INTERRUPT_EXIT);
> +        CPUState *env = next_cpu;
> +
> +        /* stop the currently executing cpu because a timer occured */
> +        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
>  #ifdef USE_KQEMU
> -            if (env->kqemu_enabled) {
> -                kqemu_cpu_interrupt(env);
> -            }
> -#endif
> +        if (env->kqemu_enabled) {
> +            kqemu_cpu_interrupt(env);
>          }
> +#endif
> +        event_pending = 1;
>      }
>  }
> 
> @@ -7168,8 +7172,6 @@ void main_loop_wait(int timeout)
> 
>  }
> 
> -static CPUState *cur_cpu;
> -
>  static int main_loop(void)
>  {
>      int ret, timeout;
> @@ -7179,15 +7181,13 @@ static int main_loop(void)
>      CPUState *env;
> 
>      cur_cpu = first_cpu;
> +    next_cpu = cur_cpu->next_cpu ?: first_cpu;
>      for(;;) {
>          if (vm_running) {
> 
> -            env = cur_cpu;
>              for(;;) {
>                  /* get next cpu */
> -                env = env->next_cpu;
> -                if (!env)
> -                    env = first_cpu;
> +                env = next_cpu;
>  #ifdef CONFIG_PROFILER
>                  ti = profile_getclock();
>  #endif
> @@ -7195,6 +7195,12 @@ static int main_loop(void)
>  #ifdef CONFIG_PROFILER
>                  qemu_time += profile_getclock() - ti;
>  #endif
> +                next_cpu = env->next_cpu ?: first_cpu;
> +                if (event_pending) {
> +                    ret = EXCP_INTERRUPT;
> +                    event_pending = 0;
> +                    break;
> +                }
>                  if (ret == EXCP_HLT) {
>                      /* Give the next CPU a chance to run.  */
>                      cur_cpu = env;
> 
> 
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit
  2007-12-02 16:42     ` Thiemo Seufer
@ 2007-12-03  3:06       ` andrzej zaborowski
  0 siblings, 0 replies; 5+ messages in thread
From: andrzej zaborowski @ 2007-12-03  3:06 UTC (permalink / raw)
  To: Thiemo Seufer; +Cc: qemu-devel

On 02/12/2007, Thiemo Seufer <ths@networkno.de> wrote:
> andrzej zaborowski wrote:
> > On 24/11/2007, Paul Brook <paul@codesourcery.com> wrote:
> > > > There is a chance that when using "unix" or "dynticks" clock, the
> > > > signal arrives when no cpu is executing.
> >
> > How about this version, this one touches vl.c only:
>
> Any reason why this isn't in CVS?

I wanted to make sure there were no objections :)
Now committed this in the form it was in the last message.
Regards

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-12-03  3:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-23 22:50 [Qemu-devel] [RFC] Ensure SIGALRM causes a cpu_loop_exit andrzej zaborowski
2007-11-23 23:43 ` Paul Brook
2007-11-24 23:13   ` andrzej zaborowski
2007-12-02 16:42     ` Thiemo Seufer
2007-12-03  3:06       ` andrzej zaborowski

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