Patchwork [001/111] linux-user: Signals processing is not thread-safe.

login
register
mail settings
Submitter Bryce Lanham
Date Aug. 17, 2011, 8:46 p.m.
Message ID <1313614076-28878-2-git-send-email-blanham@gmail.com>
Download mbox | patch
Permalink /patch/110348/
State New
Headers show

Comments

Bryce Lanham - Aug. 17, 2011, 8:46 p.m.
From: Alexander Paramonov <widgetcartman@gmail.com>

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

Patch

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 627c8b3..ae87149 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 07ad07a..0ba11bd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -472,6 +472,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;
@@ -5231,21 +5232,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:
@@ -5253,9 +5267,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);