diff --git a/cpu-defs.h b/cpu-defs.h index aa46fc3bce..b462a9fa0c 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 902031c48d..ab9399116c 100644 --- a/exec.c +++ b/exec.c @@ -534,6 +534,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; @@ -545,6 +548,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 6e2984c44b..2c1e4df6e5 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 41375677fe..94ae3338e8 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 4f3741e912..48640ec835 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 40eab4e624..226ee6ca6e 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 a160760f86..3e00507149 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 @@ -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 cab80cdfe6..f98655f803 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 754953cda0..e98a48d658 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 a6bbeb29be..90bceab68f 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 4f55a6e681..6a2aba4805 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 3fa0c3817b..eb32fb881d 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 bdc3cf974a..fba5a8fec2 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 c0215f8ae0..aea7108fce 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 1fb249b65a..8b847897ef 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