summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/linux/linux_emul.c39
-rw-r--r--sys/compat/linux/linux_emul.h5
-rw-r--r--sys/compat/linux/linux_misc.c31
-rw-r--r--sys/kern/kern_exit.c3
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. */
OpenPOWER on IntegriCloud