qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] QEMU patch for non-NPTL mode


From: Laurent Vivier
Subject: Re: [Qemu-devel] QEMU patch for non-NPTL mode
Date: Tue, 22 Mar 2011 13:16:02 +0100

Le vendredi 18 mars 2011 à 14:55 +0300, Alexander Paramonov a écrit :
> Hello! We use QEMU to run ARM-compiled soft on PC Linux OS. Our soft is 
> linked with uClibc library in non-NPTL mode. So there are some problems 
> in running multi-threaded applications under QEMU:
> 1. Both uClibc and gLibc use 32 and 33 signals and conflict.
> 2. Signals processing was not thread-safe.
> Here's a patch which makes our soft working fine. Perhaps, you would 
> find something useful and apply it in yout further QEMU versions.
> 
> Alexander, Terminal Technologies, Russia.

Hi,

I've tested the signals processing part with m68k-linux-user and it
works fine (debian etch-m68k doesn't have NPTL support).

But your patch doesn't apply cleanly (a carriage return on line 119,
some blanks on lines start) and it doesn't follow coding style
(tabulation and brace). Moreover, I think it should be split into two
patches.

You can find attached the patches I applied to my development tree.

Regards,
Laurent

> diff -ruN qemu_orig/linux-user/qemu.h qemu_patched/linux-user/qemu.h
> --- qemu_orig/linux-user/qemu.h    2011-02-16 17:44:05.000000000 +0300
> +++ qemu_patched/linux-user/qemu.h    2011-03-17 19:16:13.000000000 +0300
> @@ -80,6 +80,7 @@
>   struct sigqueue {
>       struct sigqueue *next;
>       target_siginfo_t info;
> +    pid_t pid;
>   };
> 
>   struct emulated_sigtable {
> diff -ruN qemu_orig/linux-user/signal.c qemu_patched/linux-user/signal.c
> --- qemu_orig/linux-user/signal.c    2011-02-16 17:44:05.000000000 +0300
> +++ qemu_patched/linux-user/signal.c    2011-03-18 14:29:57.991141322 +0300
> @@ -314,6 +314,8 @@
>       for(i = 1; i < _NSIG; i++) {
>           if (host_to_target_signal_table[i] == 0)
>               host_to_target_signal_table[i] = i;
> +        if (i >= SIGRTMIN && i <= SIGRTMAX)
> +            host_to_target_signal_table[i] = __SIGRTMIN + (i - SIGRTMIN);
>       }
>       for(i = 1; i < _NSIG; i++) {
>           j = host_to_target_signal_table[i];
> @@ -473,6 +475,7 @@
>           *pq = q;
>           q->info = *info;
>           q->next = NULL;
> +        q->pid = getpid();
>           k->pending = 1;
>           /* signal that a new signal is pending */
>           ts->signal_pending = 1;
> @@ -4896,21 +4899,34 @@
>       target_sigset_t target_old_set;
>       struct emulated_sigtable *k;
>       struct target_sigaction *sa;
> -    struct sigqueue *q;
> -    TaskState *ts = cpu_env->opaque;
> +    struct sigqueue *q, *q_prev;
> +    TaskState *ts = thread_env->opaque;
> 
>       if (!ts->signal_pending)
>           return;
> 
> -    /* FIXME: This is not threadsafe.  */
>       k = ts->sigtab;
> +    int signal_pending = 0;
>       for(sig = 1; sig <= TARGET_NSIG; sig++) {
>           if (k->pending)
> -            goto handle_signal;
> +        {
> +            q = k->first;
> +            q_prev = NULL;
> +            while (q)
> +            {
> +                if (q->pid == getpid())
> +                    goto handle_signal;
> +                else
> +                    signal_pending = 1;
> +                q_prev = q;
> +                q = q->next;
> +            }
> +        }
>           k++;
>       }
> +
>       /* if no signal is pending, just return */
> -    ts->signal_pending = 0;
> +    ts->signal_pending = signal_pending;
>       return;
> 
>    handle_signal:
> @@ -4918,10 +4934,19 @@
>       fprintf(stderr, "qemu: process signal %d\n", sig);
>   #endif
>       /* dequeue signal */
> -    q = k->first;
> -    k->first = q->next;
> -    if (!k->first)
> -        k->pending = 0;
> +    if (q_prev == k->first)
> +    {
> +        q = k->first;
> +        k->first = q->next;
> +        if (!k->first)
> +        {
> +            k->pending = 0;
> +        }
> +    }
> +    else if (q_prev)
> +        q_prev->next = q->next;
> +    else
> +        k->pending = 0;
> 
>       sig = gdb_handlesig (cpu_env, sig);
>       if (!sig) {
> diff -ruN qemu_orig/linux-user/syscall.c qemu_patched/linux-user/syscall.c
> --- qemu_orig/linux-user/syscall.c    2011-02-16 17:44:05.000000000 +0300
> +++ qemu_patched/linux-user/syscall.c    2011-03-18 14:32:47.107641348 +0300
> @@ -88,6 +88,7 @@
>   #endif
>   #include <linux/fb.h>
>   #include <linux/vt.h>
> +#include <bits/signum.h>
>   #include "linux_loop.h"
>   #include "cpu-uname.h"
> 
> @@ -3827,6 +3828,12 @@
>   #ifdef __ia64__
>           ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, 
> new_env);
>   #else
> +    unsigned int clone_sig = flags & CSIGNAL;
> +    if (clone_sig >= __SIGRTMIN && clone_sig <= __SIGRTMIN+2)
> +    {
> +        flags &= ~CSIGNAL;
> +        flags |= SIGRTMIN + (clone_sig - __SIGRTMIN);
> +    }
>       ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
>   #endif
>   #endif
> 

-- 
--------------------- address@hidden ----------------------
"Tout ce qui est impossible reste à accomplir"    Jules Verne
"Things are only impossible until they're not" Jean-Luc Picard
>From 83021138682bba5d1d37e1fc5d33367e8865700b Mon Sep 17 00:00:00 2001
From: Alexander Paramonov <address@hidden>
Date: Mon, 21 Mar 2011 16:41:09 +0100
Subject: [PATCH 1/2] linux-user: Signals processing is not thread-safe.

Signed-off-by: Alexander Paramonov <address@hidden>
Signed-off-by: Laurent Vivier <address@hidden>
---
 linux-user/qemu.h   |    1 +
 linux-user/signal.c |   39 +++++++++++++++++++++++++++++++--------
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 250814d..5c64d1d 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -87,6 +87,7 @@ struct vm86_saved_state {
 struct sigqueue {
     struct sigqueue *next;
     target_siginfo_t info;
+    pid_t pid;
 };
 
 struct emulated_sigtable {
diff --git a/linux-user/signal.c b/linux-user/signal.c
index ce033e9..93d2c44 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -473,6 +473,7 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t 
*info)
         *pq = q;
         q->info = *info;
         q->next = NULL;
+        q->pid = getpid();
         k->pending = 1;
         /* signal that a new signal is pending */
         ts->signal_pending = 1;
@@ -4896,21 +4897,34 @@ void process_pending_signals(CPUState *cpu_env)
     target_sigset_t target_old_set;
     struct emulated_sigtable *k;
     struct target_sigaction *sa;
-    struct sigqueue *q;
-    TaskState *ts = cpu_env->opaque;
+    struct sigqueue *q, *q_prev;
+    TaskState *ts = thread_env->opaque;
 
     if (!ts->signal_pending)
         return;
 
-    /* FIXME: This is not threadsafe.  */
     k = ts->sigtab;
+    int signal_pending = 0;
     for(sig = 1; sig <= TARGET_NSIG; sig++) {
         if (k->pending)
-            goto handle_signal;
+        {
+            q = k->first;
+            q_prev = NULL;
+            while (q)
+            {
+                if (q->pid == getpid())
+                    goto handle_signal;
+                else
+                    signal_pending = 1;
+                q_prev = q;
+                q = q->next;
+            }
+        }
         k++;
     }
+
     /* if no signal is pending, just return */
-    ts->signal_pending = 0;
+    ts->signal_pending = signal_pending;
     return;
 
  handle_signal:
@@ -4918,9 +4932,18 @@ void process_pending_signals(CPUState *cpu_env)
     fprintf(stderr, "qemu: process signal %d\n", sig);
 #endif
     /* dequeue signal */
-    q = k->first;
-    k->first = q->next;
-    if (!k->first)
+    if (q_prev == k->first)
+    {
+        q = k->first;
+        k->first = q->next;
+        if (!k->first)
+        {
+            k->pending = 0;
+        }
+    }
+    else if (q_prev)
+        q_prev->next = q->next;
+    else
         k->pending = 0;
 
     sig = gdb_handlesig (cpu_env, sig);
-- 
1.7.1

>From bda825012e189a6dfcae0f0bd761ebe0e20b93f4 Mon Sep 17 00:00:00 2001
From: Alexander Paramonov <address@hidden>
Date: Mon, 21 Mar 2011 16:49:23 +0100
Subject: [PATCH 2/2] linux-user: Both uClibc and gLibc use 32 and 33 signals 
and conflict.

Signed-off-by: Alexander Paramonov <address@hidden>
Signed-off-by: Laurent Vivier <address@hidden>
---
 linux-user/signal.c  |    2 ++
 linux-user/syscall.c |    7 +++++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 93d2c44..4adf74a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -314,6 +314,8 @@ void signal_init(void)
     for(i = 1; i < _NSIG; i++) {
         if (host_to_target_signal_table[i] == 0)
             host_to_target_signal_table[i] = i;
+        if (i >= SIGRTMIN && i <= SIGRTMAX)
+            host_to_target_signal_table[i] = __SIGRTMIN + (i - SIGRTMIN);
     }
     for(i = 1; i < _NSIG; i++) {
         j = host_to_target_signal_table[i];
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 23d7a63..8f218bd 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -91,6 +91,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #endif
 #include <linux/fb.h>
 #include <linux/vt.h>
+#include <bits/signum.h>
 #include "linux_loop.h"
 #include "cpu-uname.h"
 
@@ -3845,6 +3846,12 @@ static int do_fork(CPUState *env, unsigned int flags, 
abi_ulong newsp,
 #ifdef __ia64__
         ret = __clone2(clone_func, new_stack, NEW_STACK_SIZE, flags, new_env);
 #else
+        unsigned int clone_sig = flags & CSIGNAL;
+        if (clone_sig >= __SIGRTMIN && clone_sig <= __SIGRTMIN+2)
+        {
+            flags &= ~CSIGNAL;
+            flags |= SIGRTMIN + (clone_sig - __SIGRTMIN);
+        }
        ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
 #endif
 #endif
-- 
1.7.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]