From dd1f63493adbbb06fa16ed15f8fc16584f55ee81 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
Date: Fri, 30 Sep 2016 22:31:01 +0100
Subject: [PATCH] linux-user/syscall: extend lock around cpu-list
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

There is a potential race if several threads exit at once. To serialise
the exits extend the lock above the initial checking of the CPU list.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20160930213106.20186-11-alex.bennee@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 linux-user/syscall.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 0815f30965..fa559be47f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7476,13 +7476,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             break;
         }
 
+        cpu_list_lock();
+
         if (CPU_NEXT(first_cpu)) {
             TaskState *ts;
 
-            cpu_list_lock();
             /* Remove the CPU from the list.  */
             QTAILQ_REMOVE(&cpus, cpu, node);
+
             cpu_list_unlock();
+
             ts = cpu->opaque;
             if (ts->child_tidptr) {
                 put_user_u32(0, ts->child_tidptr);
@@ -7495,6 +7498,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             rcu_unregister_thread();
             pthread_exit(NULL);
         }
+
+        cpu_list_unlock();
 #ifdef TARGET_GPROF
         _mcleanup();
 #endif
-- 
2.30.2