Commit c2764719914ff0c4d6c06adafea17629600f21ba

Authored by pbrook
1 parent 0b8a988c

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>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6735 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-defs.h
... ... @@ -203,7 +203,7 @@ typedef struct CPUWatchpoint {
203 203 jmp_buf jmp_env; \
204 204 int exception_index; \
205 205 \
206   - void *next_cpu; /* next CPU sharing TB cache */ \
  206 + CPUState *next_cpu; /* next CPU sharing TB cache */ \
207 207 int cpu_index; /* CPU index (informative) */ \
208 208 int running; /* Nonzero if cpu is currently running(usermode). */ \
209 209 /* user data */ \
... ...
... ... @@ -534,6 +534,9 @@ void cpu_exec_init(CPUState *env)
534 534 CPUState **penv;
535 535 int cpu_index;
536 536  
  537 +#if defined(CONFIG_USER_ONLY)
  538 + cpu_list_lock();
  539 +#endif
537 540 env->next_cpu = NULL;
538 541 penv = &first_cpu;
539 542 cpu_index = 0;
... ... @@ -545,6 +548,9 @@ void cpu_exec_init(CPUState *env)
545 548 TAILQ_INIT(&env->breakpoints);
546 549 TAILQ_INIT(&env->watchpoints);
547 550 *penv = env;
  551 +#if defined(CONFIG_USER_ONLY)
  552 + cpu_list_unlock();
  553 +#endif
548 554 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
549 555 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
550 556 cpu_common_save, cpu_common_load, env);
... ...
linux-user/main.c
... ... @@ -143,6 +143,7 @@ int64_t cpu_get_real_ticks(void)
143 143 We don't require a full sync, only that no cpus are executing guest code.
144 144 The alternative is to map target atomic ops onto host equivalents,
145 145 which requires quite a lot of per host/target work. */
  146 +static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
146 147 static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
147 148 static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
148 149 static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
... ... @@ -165,6 +166,7 @@ void fork_end(int child)
165 166 thread_env->next_cpu = NULL;
166 167 pending_cpus = 0;
167 168 pthread_mutex_init(&exclusive_lock, NULL);
  169 + pthread_mutex_init(&cpu_list_mutex, NULL);
168 170 pthread_cond_init(&exclusive_cond, NULL);
169 171 pthread_cond_init(&exclusive_resume, NULL);
170 172 pthread_mutex_init(&tb_lock, NULL);
... ... @@ -237,6 +239,16 @@ static inline void cpu_exec_end(CPUState *env)
237 239 exclusive_idle();
238 240 pthread_mutex_unlock(&exclusive_lock);
239 241 }
  242 +
  243 +void cpu_list_lock(void)
  244 +{
  245 + pthread_mutex_lock(&cpu_list_mutex);
  246 +}
  247 +
  248 +void cpu_list_unlock(void)
  249 +{
  250 + pthread_mutex_unlock(&cpu_list_mutex);
  251 +}
240 252 #else /* if !USE_NPTL */
241 253 /* These are no-ops because we are not threadsafe. */
242 254 static inline void cpu_exec_start(CPUState *env)
... ... @@ -265,6 +277,14 @@ void fork_end(int child)
265 277 gdbserver_fork(thread_env);
266 278 }
267 279 }
  280 +
  281 +void cpu_list_lock(void)
  282 +{
  283 +}
  284 +
  285 +void cpu_list_unlock(void)
  286 +{
  287 +}
268 288 #endif
269 289  
270 290  
... ...
linux-user/qemu.h
... ... @@ -100,6 +100,9 @@ typedef struct TaskState {
100 100 uint32_t v86flags;
101 101 uint32_t v86mask;
102 102 #endif
  103 +#ifdef USE_NPTL
  104 + abi_ulong child_tidptr;
  105 +#endif
103 106 #ifdef TARGET_M68K
104 107 int sim_syscalls;
105 108 #endif
... ... @@ -225,6 +228,8 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
225 228 extern unsigned long last_brk;
226 229 void mmap_lock(void);
227 230 void mmap_unlock(void);
  231 +void cpu_list_lock(void);
  232 +void cpu_list_unlock(void);
228 233 #if defined(USE_NPTL)
229 234 void mmap_fork_start(void);
230 235 void mmap_fork_end(int child);
... ...
linux-user/signal.c
... ... @@ -2691,7 +2691,7 @@ static int setup_sigcontext(struct target_sigcontext *sc,
2691 2691 return err;
2692 2692 }
2693 2693  
2694   -static int restore_sigcontext(struct CPUState *regs,
  2694 +static int restore_sigcontext(CPUState *regs,
2695 2695 struct target_sigcontext *sc)
2696 2696 {
2697 2697 unsigned int err = 0;
... ...
linux-user/syscall.c
... ... @@ -156,7 +156,6 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
156 156 }
157 157  
158 158  
159   -#define __NR_sys_exit __NR_exit
160 159 #define __NR_sys_uname __NR_uname
161 160 #define __NR_sys_faccessat __NR_faccessat
162 161 #define __NR_sys_fchmodat __NR_fchmodat
... ... @@ -198,7 +197,6 @@ static int gettid(void) {
198 197 return -ENOSYS;
199 198 }
200 199 #endif
201   -_syscall1(int,sys_exit,int,status)
202 200 _syscall1(int,sys_uname,struct new_utsname *,buf)
203 201 #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
204 202 _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,
2936 2934 nptl_flags = flags;
2937 2935 flags &= ~CLONE_NPTL_FLAGS2;
2938 2936  
2939   - /* TODO: Implement CLONE_CHILD_CLEARTID. */
  2937 + if (nptl_flags & CLONE_CHILD_CLEARTID) {
  2938 + ts->child_tidptr = child_tidptr;
  2939 + }
  2940 +
2940 2941 if (nptl_flags & CLONE_SETTLS)
2941 2942 cpu_set_tls (new_env, newtls);
2942 2943  
... ... @@ -2961,6 +2962,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
2961 2962 sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
2962 2963  
2963 2964 ret = pthread_create(&info.thread, &attr, clone_func, &info);
  2965 + /* TODO: Free new CPU state if thread creation failed. */
2964 2966  
2965 2967 sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
2966 2968 pthread_attr_destroy(&attr);
... ... @@ -3011,7 +3013,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
3011 3013 ts = (TaskState *)env->opaque;
3012 3014 if (flags & CLONE_SETTLS)
3013 3015 cpu_set_tls (env, newtls);
3014   - /* TODO: Implement CLONE_CHILD_CLEARTID. */
  3016 + if (flags & CLONE_CHILD_CLEARTID)
  3017 + ts->child_tidptr = child_tidptr;
3015 3018 #endif
3016 3019 } else {
3017 3020 fork_end(0);
... ... @@ -3428,12 +3431,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
3428 3431  
3429 3432 switch(num) {
3430 3433 case TARGET_NR_exit:
  3434 +#ifdef USE_NPTL
  3435 + /* In old applications this may be used to implement _exit(2).
  3436 + However in threaded applictions it is used for thread termination,
  3437 + and _exit_group is used for application termination.
  3438 + Do thread termination if we have more then one thread. */
  3439 + /* FIXME: This probably breaks if a signal arrives. We should probably
  3440 + be disabling signals. */
  3441 + if (first_cpu->next_cpu) {
  3442 + CPUState **lastp;
  3443 + CPUState *p;
  3444 +
  3445 + cpu_list_lock();
  3446 + lastp = &first_cpu;
  3447 + p = first_cpu;
  3448 + while (p && p != (CPUState *)cpu_env) {
  3449 + lastp = &p->next_cpu;
  3450 + p = p->next_cpu;
  3451 + }
  3452 + /* If we didn't find the CPU for this thread then something is
  3453 + horribly wrong. */
  3454 + if (!p)
  3455 + abort();
  3456 + /* Remove the CPU from the list. */
  3457 + *lastp = p->next_cpu;
  3458 + cpu_list_unlock();
  3459 + TaskState *ts = ((CPUState *)cpu_env)->opaque;
  3460 + if (ts->child_tidptr) {
  3461 + put_user_u32(0, ts->child_tidptr);
  3462 + sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
  3463 + NULL, NULL, 0);
  3464 + }
  3465 + /* TODO: Free CPU state. */
  3466 + pthread_exit(NULL);
  3467 + }
  3468 +#endif
3431 3469 #ifdef HAVE_GPROF
3432 3470 _mcleanup();
3433 3471 #endif
3434 3472 gdb_exit(cpu_env, arg1);
3435   - /* XXX: should free thread stack and CPU env */
3436   - sys_exit(arg1);
  3473 + _exit(arg1);
3437 3474 ret = 0; /* avoid warning */
3438 3475 break;
3439 3476 case TARGET_NR_read:
... ...
target-alpha/cpu.h
... ... @@ -25,6 +25,8 @@
25 25  
26 26 #define TARGET_LONG_BITS 64
27 27  
  28 +#define CPUState struct CPUAlphaState
  29 +
28 30 #include "cpu-defs.h"
29 31  
30 32 #include <setjmp.h>
... ... @@ -291,7 +293,6 @@ struct CPUAlphaState {
291 293 pal_handler_t *pal_handler;
292 294 };
293 295  
294   -#define CPUState CPUAlphaState
295 296 #define cpu_init cpu_alpha_init
296 297 #define cpu_exec cpu_alpha_exec
297 298 #define cpu_gen_code cpu_alpha_gen_code
... ...
target-arm/cpu.h
... ... @@ -24,6 +24,8 @@
24 24  
25 25 #define ELF_MACHINE EM_ARM
26 26  
  27 +#define CPUState struct CPUARMState
  28 +
27 29 #include "cpu-defs.h"
28 30  
29 31 #include "softfloat.h"
... ... @@ -398,7 +400,6 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
398 400 #define TARGET_PAGE_BITS 10
399 401 #endif
400 402  
401   -#define CPUState CPUARMState
402 403 #define cpu_init cpu_arm_init
403 404 #define cpu_exec cpu_arm_exec
404 405 #define cpu_gen_code cpu_arm_gen_code
... ...
target-cris/cpu.h
... ... @@ -23,6 +23,8 @@
23 23  
24 24 #define TARGET_LONG_BITS 32
25 25  
  26 +#define CPUState struct CPUCRISState
  27 +
26 28 #include "cpu-defs.h"
27 29  
28 30 #define TARGET_HAS_ICE 1
... ... @@ -199,7 +201,6 @@ enum {
199 201 #define TARGET_PAGE_BITS 13
200 202 #define MMAP_SHIFT TARGET_PAGE_BITS
201 203  
202   -#define CPUState CPUCRISState
203 204 #define cpu_init cpu_cris_init
204 205 #define cpu_exec cpu_cris_exec
205 206 #define cpu_gen_code cpu_cris_gen_code
... ...
target-i386/cpu.h
... ... @@ -42,6 +42,8 @@
42 42 #define ELF_MACHINE EM_386
43 43 #endif
44 44  
  45 +#define CPUState struct CPUX86State
  46 +
45 47 #include "cpu-defs.h"
46 48  
47 49 #include "softfloat.h"
... ... @@ -828,7 +830,6 @@ static inline int cpu_get_time_fast(void)
828 830  
829 831 #define TARGET_PAGE_BITS 12
830 832  
831   -#define CPUState CPUX86State
832 833 #define cpu_init cpu_x86_init
833 834 #define cpu_exec cpu_x86_exec
834 835 #define cpu_gen_code cpu_x86_gen_code
... ...
target-m68k/cpu.h
... ... @@ -23,6 +23,8 @@
23 23  
24 24 #define TARGET_LONG_BITS 32
25 25  
  26 +#define CPUState struct CPUM68KState
  27 +
26 28 #include "cpu-defs.h"
27 29  
28 30 #include "softfloat.h"
... ... @@ -207,7 +209,6 @@ void register_m68k_insns (CPUM68KState *env);
207 209 #define TARGET_PAGE_BITS 10
208 210 #endif
209 211  
210   -#define CPUState CPUM68KState
211 212 #define cpu_init cpu_m68k_init
212 213 #define cpu_exec cpu_m68k_exec
213 214 #define cpu_gen_code cpu_m68k_gen_code
... ...
target-mips/cpu.h
... ... @@ -5,6 +5,8 @@
5 5  
6 6 #define ELF_MACHINE EM_MIPS
7 7  
  8 +#define CPUState struct CPUMIPSState
  9 +
8 10 #include "config.h"
9 11 #include "mips-defs.h"
10 12 #include "cpu-defs.h"
... ... @@ -473,7 +475,6 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
473 475 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
474 476 int unused, int size);
475 477  
476   -#define CPUState CPUMIPSState
477 478 #define cpu_init cpu_mips_init
478 479 #define cpu_exec cpu_mips_exec
479 480 #define cpu_gen_code cpu_mips_gen_code
... ...
target-ppc/cpu.h
... ... @@ -54,6 +54,8 @@
54 54  
55 55 #endif /* defined (TARGET_PPC64) */
56 56  
  57 +#define CPUState struct CPUPPCState
  58 +
57 59 #include "cpu-defs.h"
58 60  
59 61 #define REGX "%016" PRIx64
... ... @@ -786,7 +788,6 @@ static always_inline uint64_t ppc_dump_gpr (CPUPPCState *env, int gprn)
786 788 int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp);
787 789 int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
788 790  
789   -#define CPUState CPUPPCState
790 791 #define cpu_init cpu_ppc_init
791 792 #define cpu_exec cpu_ppc_exec
792 793 #define cpu_gen_code cpu_ppc_gen_code
... ...
target-sh4/cpu.h
... ... @@ -37,6 +37,8 @@
37 37 #define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R)
38 38 #define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R)
39 39  
  40 +#define CPUState struct CPUSH4State
  41 +
40 42 #include "cpu-defs.h"
41 43  
42 44 #include "softfloat.h"
... ... @@ -169,7 +171,6 @@ void cpu_load_tlb(CPUSH4State * env);
169 171  
170 172 #include "softfloat.h"
171 173  
172   -#define CPUState CPUSH4State
173 174 #define cpu_init cpu_sh4_init
174 175 #define cpu_exec cpu_sh4_exec
175 176 #define cpu_gen_code cpu_sh4_gen_code
... ...
target-sparc/cpu.h
... ... @@ -15,6 +15,8 @@
15 15  
16 16 #define TARGET_PHYS_ADDR_BITS 64
17 17  
  18 +#define CPUState struct CPUSPARCState
  19 +
18 20 #include "cpu-defs.h"
19 21  
20 22 #include "softfloat.h"
... ... @@ -436,7 +438,6 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
436 438 int is_asi, int size);
437 439 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
438 440  
439   -#define CPUState CPUSPARCState
440 441 #define cpu_init cpu_sparc_init
441 442 #define cpu_exec cpu_sparc_exec
442 443 #define cpu_gen_code cpu_sparc_gen_code
... ...