diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 49 |
1 files changed, 43 insertions, 6 deletions
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: |