diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/linux/linux_emul.c | 39 | ||||
-rw-r--r-- | sys/compat/linux/linux_emul.h | 5 | ||||
-rw-r--r-- | sys/compat/linux/linux_misc.c | 31 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 3 |
4 files changed, 55 insertions, 23 deletions
diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c index dc81553..eb10ca6 100644 --- a/sys/compat/linux/linux_emul.c +++ b/sys/compat/linux/linux_emul.c @@ -155,7 +155,7 @@ void linux_proc_exit(void *arg __unused, struct proc *p) { struct linux_emuldata *em; - int error; + int error, shared_flags, shared_xstat; struct thread *td = FIRST_THREAD_IN_PROC(p); int *child_clear_tid; struct proc *q, *nq; @@ -187,6 +187,8 @@ linux_proc_exit(void *arg __unused, struct proc *p) } EMUL_SHARED_WLOCK(&emul_shared_lock); + shared_flags = em->shared->flags; + shared_xstat = em->shared->xstat; LIST_REMOVE(em, threads); em->shared->refs--; @@ -196,6 +198,12 @@ linux_proc_exit(void *arg __unused, struct proc *p) } else EMUL_SHARED_WUNLOCK(&emul_shared_lock); + if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) { + PROC_LOCK(p); + p->p_xstat = shared_xstat; + PROC_UNLOCK(p); + } + if (child_clear_tid != NULL) { struct linux_sys_futex_args cup; int null = 0; @@ -257,6 +265,9 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) if (__predict_false(imgp->sysent == &elf_linux_sysvec && p->p_sysent != &elf_linux_sysvec)) linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); + if (__predict_false(p->p_sysent == &elf_linux_sysvec)) + /* Kill threads regardless of imgp->sysent value */ + linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL); if (__predict_false(imgp->sysent != &elf_linux_sysvec && p->p_sysent == &elf_linux_sysvec)) { struct linux_emuldata *em; @@ -334,3 +345,29 @@ linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args EMUL_UNLOCK(&emul_lock); return 0; } + +void +linux_kill_threads(struct thread *td, int sig) +{ + struct linux_emuldata *em, *td_em, *tmp_em; + struct proc *sp; + + td_em = em_find(td->td_proc, EMUL_DONTLOCK); + + KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n")); + + EMUL_SHARED_RLOCK(&emul_shared_lock); + LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) { + if (em->pid == td_em->pid) + continue; + + sp = pfind(em->pid); + if ((sp->p_flag & P_WEXIT) == 0) + psignal(sp, sig); + PROC_UNLOCK(sp); +#ifdef DEBUG + printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid); +#endif + } + EMUL_SHARED_RUNLOCK(&emul_shared_lock); +} diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h index 8ce27d7..43034ff 100644 --- a/sys/compat/linux/linux_emul.h +++ b/sys/compat/linux/linux_emul.h @@ -31,8 +31,12 @@ #ifndef _LINUX_EMUL_H_ #define _LINUX_EMUL_H_ +#define EMUL_SHARED_HASXSTAT 0x01 + struct linux_emuldata_shared { int refs; + int flags; + int xstat; pid_t group_pid; LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */ @@ -76,6 +80,7 @@ int linux_proc_init(struct thread *, pid_t, int); void linux_proc_exit(void *, struct proc *); void linux_schedtail(void *, struct proc *); void linux_proc_exec(void *, struct proc *, struct image_params *); +void linux_kill_threads(struct thread *, int); extern struct sx emul_shared_lock; extern struct mtx emul_lock; diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index d2cf6b6..c50bf1c 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1695,34 +1695,23 @@ linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) int linux_exit_group(struct thread *td, struct linux_exit_group_args *args) { - struct linux_emuldata *em, *td_em, *tmp_em; - struct proc *sp; + struct linux_emuldata *em; #ifdef DEBUG if (ldebug(exit_group)) printf(ARGS(exit_group, "%i"), args->error_code); #endif - if (linux_use26(td)) { - td_em = em_find(td->td_proc, EMUL_DONTLOCK); - - KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n")); - - EMUL_SHARED_RLOCK(&emul_shared_lock); - LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) { - if (em->pid == td_em->pid) - continue; - - sp = pfind(em->pid); - psignal(sp, SIGKILL); - PROC_UNLOCK(sp); -#ifdef DEBUG - printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid); -#endif - } - - EMUL_SHARED_RUNLOCK(&emul_shared_lock); + em = em_find(td->td_proc, EMUL_DONTLOCK); + if (em->shared->refs > 1) { + EMUL_SHARED_WLOCK(&emul_shared_lock); + em->shared->flags |= EMUL_SHARED_HASXSTAT; + em->shared->xstat = W_EXITCODE(args->error_code, 0); + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + if (linux_use26(td)) + linux_kill_threads(td, SIGKILL); } + /* * XXX: we should send a signal to the parent if * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 31389e1..e95ac8f 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -200,6 +200,7 @@ exit1(struct thread *td, int rv) while (p->p_lock > 0) msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0); + p->p_xstat = rv; /* Let event handler change exit status */ PROC_UNLOCK(p); /* Drain the limit callout while we don't have the proc locked */ callout_drain(&p->p_limco); @@ -242,6 +243,7 @@ exit1(struct thread *td, int rv) * P_PPWAIT is set; we will wakeup the parent below. */ PROC_LOCK(p); + rv = p->p_xstat; /* Event handler could change exit status */ stopprofclock(p); p->p_flag &= ~(P_TRACED | P_PPWAIT); @@ -424,7 +426,6 @@ exit1(struct thread *td, int rv) /* Save exit status. */ PROC_LOCK(p); - p->p_xstat = rv; p->p_xthread = td; /* Tell the prison that we are gone. */ |