Patchwork QEMU patch for non-NPTL mode

login
register
mail settings
Submitter Laurent Vivier
Date March 22, 2011, 12:16 p.m.
Message ID <1300796162.3930.11.camel@Quad>
Download mbox | patch
Permalink /patch/87905/
State New
Headers show

Comments

Laurent Vivier - March 22, 2011, 12:16 p.m.
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
>

Patch

From bda825012e189a6dfcae0f0bd761ebe0e20b93f4 Mon Sep 17 00:00:00 2001
From: Alexander Paramonov <widgetcartman@gmail.com>
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 <widgetcartman@gmail.com>
Signed-off-by: Laurent Vivier <Laurent@Vivier.EU>
---
 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