>From 83021138682bba5d1d37e1fc5d33367e8865700b Mon Sep 17 00:00:00 2001 From: Alexander Paramonov 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 Signed-off-by: Laurent Vivier --- 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