Patchwork QEMU patch for non-NPTL mode

login
register
mail settings
Submitter Alexander Paramonov
Date March 18, 2011, 11:55 a.m.
Message ID <4D834838.7040507@gmail.com>
Download mbox | patch
Permalink /patch/87518/
State New
Headers show

Comments

Alexander Paramonov - March 18, 2011, 11:55 a.m.
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.

  #endif

Patch

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