From 2fb2cd0c70d9b66b9b4ad85f382d8b6e62542a0c Mon Sep 17 00:00:00 2001
From: Paul Brook <paul@nowt.org>
Date: Sat, 7 Mar 2009 15:25:00 +0000
Subject: [PATCH] The _exit syscall is used for both thread termination in NPTL applications ,

Revision: 6735
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6735
Author:   pbrook
Date:     2009-03-07 15:24:59 +0000 (Sat, 07 Mar 2009)
Log Message:
-----------
The _exit syscall is used for both thread termination in NPTL applications,
and process termination in legacy applications.  Try to guess which we want
based on the presence of multiple threads.

Also implement locking when modifying the CPU list.

Signed-off-by: Paul Brook <paul@codesourcery.com>

Modified Paths:
--------------
    trunk/cpu-defs.h
    trunk/exec.c
    trunk/linux-user/main.c
    trunk/linux-user/qemu.h
    trunk/linux-user/signal.c
    trunk/linux-user/syscall.c
    trunk/target-alpha/cpu.h
    trunk/target-arm/cpu.h
    trunk/target-cris/cpu.h
    trunk/target-i386/cpu.h
    trunk/target-m68k/cpu.h
    trunk/target-mips/cpu.h
    trunk/target-ppc/cpu.h
    trunk/target-sh4/cpu.h
    trunk/target-sparc/cpu.h

Modified: trunk/cpu-defs.h
===================================================================
---
 cpu-defs.h           |    2 +-
 exec.c               |    6 ++++++
 linux-user/main.c    |   20 ++++++++++++++++++++
 linux-user/qemu.h    |    5 +++++
 linux-user/signal.c  |    2 +-
 linux-user/syscall.c |   49 +++++++++++++++++++++++++++++++++++++++++++------
 target-alpha/cpu.h   |    3 ++-
 target-arm/cpu.h     |    3 ++-
 target-cris/cpu.h    |    3 ++-
 target-i386/cpu.h    |    3 ++-
 target-m68k/cpu.h    |    3 ++-
 target-mips/cpu.h    |    3 ++-
 target-ppc/cpu.h     |    3 ++-
 target-sh4/cpu.h     |    3 ++-
 target-sparc/cpu.h   |    3 ++-
 15 files changed, 94 insertions(+), 17 deletions(-)

diff --git a/cpu-defs.h b/cpu-defs.h
index aa46fc3..b462a9f 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -203,7 +203,7 @@ typedef struct CPUWatchpoint {
     jmp_buf jmp_env;                                                    \
     int exception_index;                                                \
                                                                         \
-    void *next_cpu; /* next CPU sharing TB cache */                     \
+    CPUState *next_cpu; /* next CPU sharing TB cache */                 \
     int cpu_index; /* CPU index (informative) */                        \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
     /* user data */                                                     \
diff --git a/exec.c b/exec.c
index 61a5532..1e54a9c 100644
--- a/exec.c
+++ b/exec.c
@@ -535,6 +535,9 @@ void cpu_exec_init(CPUState *env)
     CPUState **penv;
     int cpu_index;
 
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_lock();
+#endif
     env->next_cpu = NULL;
     penv = &first_cpu;
     cpu_index = 0;
@@ -546,6 +549,9 @@ void cpu_exec_init(CPUState *env)
     TAILQ_INIT(&env->breakpoints);
     TAILQ_INIT(&env->watchpoints);
     *penv = env;
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_unlock();
+#endif
 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
     register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
                     cpu_common_save, cpu_common_load, env);
diff --git a/linux-user/main.c b/linux-user/main.c
index 6e2984c..2c1e4df 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -143,6 +143,7 @@ int64_t cpu_get_real_ticks(void)
    We don't require a full sync, only that no cpus are executing guest code.
    The alternative is to map target atomic ops onto host equivalents,
    which requires quite a lot of per host/target work.  */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
 static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
@@ -165,6 +166,7 @@ void fork_end(int child)
         thread_env->next_cpu = NULL;
         pending_cpus = 0;
         pthread_mutex_init(&exclusive_lock, NULL);
+        pthread_mutex_init(&cpu_list_mutex, NULL);
         pthread_cond_init(&exclusive_cond, NULL);
         pthread_cond_init(&exclusive_resume, NULL);
         pthread_mutex_init(&tb_lock, NULL);
@@ -237,6 +239,16 @@ static inline void cpu_exec_end(CPUState *env)
     exclusive_idle();
     pthread_mutex_unlock(&exclusive_lock);
 }
+
+void cpu_list_lock(void)
+{
+    pthread_mutex_lock(&cpu_list_mutex);
+}
+
+void cpu_list_unlock(void)
+{
+    pthread_mutex_unlock(&cpu_list_mutex);
+}
 #else /* if !USE_NPTL */
 /* These are no-ops because we are not threadsafe.  */
 static inline void cpu_exec_start(CPUState *env)
@@ -265,6 +277,14 @@ void fork_end(int child)
         gdbserver_fork(thread_env);
     }
 }
+
+void cpu_list_lock(void)
+{
+}
+
+void cpu_list_unlock(void)
+{
+}
 #endif
 
 
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 4137567..94ae333 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -100,6 +100,9 @@ typedef struct TaskState {
     uint32_t v86flags;
     uint32_t v86mask;
 #endif
+#ifdef USE_NPTL
+    abi_ulong child_tidptr;
+#endif
 #ifdef TARGET_M68K
     int sim_syscalls;
 #endif
@@ -225,6 +228,8 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
 void mmap_lock(void);
 void mmap_unlock(void);
+void cpu_list_lock(void);
+void cpu_list_unlock(void);
 #if defined(USE_NPTL)
 void mmap_fork_start(void);
 void mmap_fork_end(int child);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 4f3741e..48640ec 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2691,7 +2691,7 @@ static int setup_sigcontext(struct target_sigcontext *sc,
     return err;
 }
 
-static int restore_sigcontext(struct CPUState *regs,
+static int restore_sigcontext(CPUState *regs,
 			      struct target_sigcontext *sc)
 {
     unsigned int err = 0;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 40eab4e..226ee6c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -156,7 +156,6 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
 }
 
 
-#define __NR_sys_exit __NR_exit
 #define __NR_sys_uname __NR_uname
 #define __NR_sys_faccessat __NR_faccessat
 #define __NR_sys_fchmodat __NR_fchmodat
@@ -198,7 +197,6 @@ static int gettid(void) {
     return -ENOSYS;
 }
 #endif
-_syscall1(int,sys_exit,int,status)
 _syscall1(int,sys_uname,struct new_utsname *,buf)
 #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
 _syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
@@ -2936,7 +2934,10 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         nptl_flags = flags;
         flags &= ~CLONE_NPTL_FLAGS2;
 
-        /* TODO: Implement CLONE_CHILD_CLEARTID.  */
+        if (nptl_flags & CLONE_CHILD_CLEARTID) {
+            ts->child_tidptr = child_tidptr;
+        }
+
         if (nptl_flags & CLONE_SETTLS)
             cpu_set_tls (new_env, newtls);
 
@@ -2961,6 +2962,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
 
         ret = pthread_create(&info.thread, &attr, clone_func, &info);
+        /* TODO: Free new CPU state if thread creation failed.  */
 
         sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
         pthread_attr_destroy(&attr);
@@ -3011,7 +3013,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
             ts = (TaskState *)env->opaque;
             if (flags & CLONE_SETTLS)
                 cpu_set_tls (env, newtls);
-            /* TODO: Implement CLONE_CHILD_CLEARTID.  */
+            if (flags & CLONE_CHILD_CLEARTID)
+                ts->child_tidptr = child_tidptr;
 #endif
         } else {
             fork_end(0);
@@ -3428,12 +3431,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_NR_exit:
+#ifdef USE_NPTL
+      /* In old applications this may be used to implement _exit(2).
+         However in threaded applictions it is used for thread termination,
+         and _exit_group is used for application termination.
+         Do thread termination if we have more then one thread.  */
+      /* FIXME: This probably breaks if a signal arrives.  We should probably
+         be disabling signals.  */
+      if (first_cpu->next_cpu) {
+          CPUState **lastp;
+          CPUState *p;
+
+          cpu_list_lock();
+          lastp = &first_cpu;
+          p = first_cpu;
+          while (p && p != (CPUState *)cpu_env) {
+              lastp = &p->next_cpu;
+              p = p->next_cpu;
+          }
+          /* If we didn't find the CPU for this thread then something is
+             horribly wrong.  */
+          if (!p)
+              abort();
+          /* Remove the CPU from the list.  */
+          *lastp = p->next_cpu;
+          cpu_list_unlock();
+          TaskState *ts = ((CPUState *)cpu_env)->opaque;
+          if (ts->child_tidptr) {
+              put_user_u32(0, ts->child_tidptr);
+              sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+                        NULL, NULL, 0);
+          }
+          /* TODO: Free CPU state.  */
+          pthread_exit(NULL);
+      }
+#endif
 #ifdef HAVE_GPROF
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        sys_exit(arg1);
+        _exit(arg1);
         ret = 0; /* avoid warning */
         break;
     case TARGET_NR_read:
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index a160760..3e00507 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -25,6 +25,8 @@
 
 #define TARGET_LONG_BITS 64
 
+#define CPUState struct CPUAlphaState
+
 #include "cpu-defs.h"
 
 #include <setjmp.h>
@@ -291,7 +293,6 @@ struct CPUAlphaState {
     pal_handler_t *pal_handler;
 };
 
-#define CPUState CPUAlphaState
 #define cpu_init cpu_alpha_init
 #define cpu_exec cpu_alpha_exec
 #define cpu_gen_code cpu_alpha_gen_code
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index cab80cd..f98655f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -24,6 +24,8 @@
 
 #define ELF_MACHINE	EM_ARM
 
+#define CPUState struct CPUARMState
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -398,7 +400,6 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define TARGET_PAGE_BITS 10
 #endif
 
-#define CPUState CPUARMState
 #define cpu_init cpu_arm_init
 #define cpu_exec cpu_arm_exec
 #define cpu_gen_code cpu_arm_gen_code
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 754953c..e98a48d 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -23,6 +23,8 @@
 
 #define TARGET_LONG_BITS 32
 
+#define CPUState struct CPUCRISState
+
 #include "cpu-defs.h"
 
 #define TARGET_HAS_ICE 1
@@ -199,7 +201,6 @@ enum {
 #define TARGET_PAGE_BITS 13
 #define MMAP_SHIFT TARGET_PAGE_BITS
 
-#define CPUState CPUCRISState
 #define cpu_init cpu_cris_init
 #define cpu_exec cpu_cris_exec
 #define cpu_gen_code cpu_cris_gen_code
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a6bbeb2..90bceab 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -42,6 +42,8 @@
 #define ELF_MACHINE	EM_386
 #endif
 
+#define CPUState struct CPUX86State
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -828,7 +830,6 @@ static inline int cpu_get_time_fast(void)
 
 #define TARGET_PAGE_BITS 12
 
-#define CPUState CPUX86State
 #define cpu_init cpu_x86_init
 #define cpu_exec cpu_x86_exec
 #define cpu_gen_code cpu_x86_gen_code
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 4f55a6e..6a2aba4 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -23,6 +23,8 @@
 
 #define TARGET_LONG_BITS 32
 
+#define CPUState struct CPUM68KState
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -207,7 +209,6 @@ void register_m68k_insns (CPUM68KState *env);
 #define TARGET_PAGE_BITS 10
 #endif
 
-#define CPUState CPUM68KState
 #define cpu_init cpu_m68k_init
 #define cpu_exec cpu_m68k_exec
 #define cpu_gen_code cpu_m68k_gen_code
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 3fa0c38..eb32fb8 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -5,6 +5,8 @@
 
 #define ELF_MACHINE	EM_MIPS
 
+#define CPUState struct CPUMIPSState
+
 #include "config.h"
 #include "mips-defs.h"
 #include "cpu-defs.h"
@@ -473,7 +475,6 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                           int unused, int size);
 
-#define CPUState CPUMIPSState
 #define cpu_init cpu_mips_init
 #define cpu_exec cpu_mips_exec
 #define cpu_gen_code cpu_mips_gen_code
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index bdc3cf9..fba5a8f 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -54,6 +54,8 @@
 
 #endif /* defined (TARGET_PPC64) */
 
+#define CPUState struct CPUPPCState
+
 #include "cpu-defs.h"
 
 #define REGX "%016" PRIx64
@@ -786,7 +788,6 @@ static always_inline uint64_t ppc_dump_gpr (CPUPPCState *env, int gprn)
 int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp);
 int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
 
-#define CPUState CPUPPCState
 #define cpu_init cpu_ppc_init
 #define cpu_exec cpu_ppc_exec
 #define cpu_gen_code cpu_ppc_gen_code
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index c0215f8..aea7108 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -37,6 +37,8 @@
 #define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R)
 #define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R)
 
+#define CPUState struct CPUSH4State
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -169,7 +171,6 @@ void cpu_load_tlb(CPUSH4State * env);
 
 #include "softfloat.h"
 
-#define CPUState CPUSH4State
 #define cpu_init cpu_sh4_init
 #define cpu_exec cpu_sh4_exec
 #define cpu_gen_code cpu_sh4_gen_code
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 1fb249b..8b84789 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -15,6 +15,8 @@
 
 #define TARGET_PHYS_ADDR_BITS 64
 
+#define CPUState struct CPUSPARCState
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -436,7 +438,6 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                           int is_asi, int size);
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
-#define CPUState CPUSPARCState
 #define cpu_init cpu_sparc_init
 #define cpu_exec cpu_sparc_exec
 #define cpu_gen_code cpu_sparc_gen_code
-- 
1.6.3.2

