qemu-devel
[Top][All Lists]
Advanced

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

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


From: Alexander Paramonov
Subject: [Qemu-devel] QEMU patch for non-NPTL mode
Date: Fri, 18 Mar 2011 14:55:36 +0300
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Thunderbird/3.1.8

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.

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



reply via email to

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