summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-defs.h2
-rw-r--r--exec.c6
-rw-r--r--linux-user/main.c20
-rw-r--r--linux-user/qemu.h5
-rw-r--r--linux-user/signal.c2
-rw-r--r--linux-user/syscall.c49
-rw-r--r--target-alpha/cpu.h3
-rw-r--r--target-arm/cpu.h3
-rw-r--r--target-cris/cpu.h3
-rw-r--r--target-i386/cpu.h3
-rw-r--r--target-m68k/cpu.h3
-rw-r--r--target-mips/cpu.h3
-rw-r--r--target-ppc/cpu.h3
-rw-r--r--target-sh4/cpu.h3
-rw-r--r--target-sparc/cpu.h3
15 files changed, 94 insertions, 17 deletions
diff --git a/cpu-defs.h b/cpu-defs.h
index aa46fc3bc..b462a9fa0 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 902031c48..ab9399116 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 6e2984c44..2c1e4df6e 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 41375677f..94ae3338e 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 4f3741e91..48640ec83 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 40eab4e62..226ee6ca6 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 a160760f8..3e0050714 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 cab80cdfe..f98655f80 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 754953cda..e98a48d65 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 a6bbeb29b..90bceab68 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 4f55a6e68..6a2aba480 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 3fa0c3817..eb32fb881 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 bdc3cf974..fba5a8fec 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 c0215f8ae..aea7108fc 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 1fb249b65..8b847897e 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