diff options
author | jhb <jhb@FreeBSD.org> | 2015-12-29 23:25:26 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2015-12-29 23:25:26 +0000 |
commit | fb5720f7be0d2eab3253696e244c058a229b5473 (patch) | |
tree | 38cac37b4cace20e5e9e11b5763940c44fe6be7f /sys/kern/kern_thr.c | |
parent | 79ec12eeb6f427ceaaaa94ca98073316d8c24e47 (diff) | |
download | FreeBSD-src-fb5720f7be0d2eab3253696e244c058a229b5473.zip FreeBSD-src-fb5720f7be0d2eab3253696e244c058a229b5473.tar.gz |
Add ptrace(2) reporting for LWP events.
Add two new LWPINFO flags: PL_FLAG_BORN and PL_FLAG_EXITED for reporting
thread creation and destruction. Newly created threads will stop to report
PL_FLAG_BORN before returning to userland and exiting threads will stop to
report PL_FLAG_EXIT before exiting completely. Both of these events are
only enabled and reported if PT_LWP_EVENTS is enabled on a process.
Diffstat (limited to 'sys/kern/kern_thr.c')
-rw-r--r-- | sys/kern/kern_thr.c | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 9e878d8..1b226dd 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -253,6 +253,8 @@ thread_create(struct thread *td, struct rtprio *rtp, thread_unlock(td); if (P_SHOULDSTOP(p)) newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; + if (p->p_flag2 & P2_LWP_EVENTS) + newtd->td_dbgflags |= TDB_BORN; /* * Copy the existing thread VM policy into the new thread. @@ -322,29 +324,54 @@ kern_thr_exit(struct thread *td) p = td->td_proc; - rw_wlock(&tidhash_lock); + /* + * If all of the threads in a process call this routine to + * exit (e.g. all threads call pthread_exit()), exactly one + * thread should return to the caller to terminate the process + * instead of the thread. + * + * Checking p_numthreads alone is not sufficient since threads + * might be committed to terminating while the PROC_LOCK is + * dropped in either ptracestop() or while removing this thread + * from the tidhash. Instead, the p_pendingexits field holds + * the count of threads in either of those states and a thread + * is considered the "last" thread if all of the other threads + * in a process are already terminating. + */ PROC_LOCK(p); - - if (p->p_numthreads != 1) { - racct_sub(p, RACCT_NTHR, 1); - LIST_REMOVE(td, td_hash); - rw_wunlock(&tidhash_lock); - tdsigcleanup(td); - umtx_thread_exit(td); - PROC_SLOCK(p); - thread_stopped(p); - thread_exit(); - /* NOTREACHED */ + if (p->p_numthreads == p->p_pendingexits + 1) { + /* + * Ignore attempts to shut down last thread in the + * proc. This will actually call _exit(2) in the + * usermode trampoline when it returns. + */ + PROC_UNLOCK(p); + return (0); } + p->p_pendingexits++; + td->td_dbgflags |= TDB_EXIT; + if (p->p_flag & P_TRACED && p->p_flag2 & P2_LWP_EVENTS) + ptracestop(td, SIGTRAP); + PROC_UNLOCK(p); + tidhash_remove(td); + PROC_LOCK(p); + p->p_pendingexits--; + /* - * Ignore attempts to shut down last thread in the proc. This - * will actually call _exit(2) in the usermode trampoline when - * it returns. + * The check above should prevent all other threads from this + * process from exiting while the PROC_LOCK is dropped, so + * there must be at least one other thread other than the + * current thread. */ - PROC_UNLOCK(p); - rw_wunlock(&tidhash_lock); - return (0); + KASSERT(p->p_numthreads > 1, ("too few threads")); + racct_sub(p, RACCT_NTHR, 1); + tdsigcleanup(td); + umtx_thread_exit(td); + PROC_SLOCK(p); + thread_stopped(p); + thread_exit(); + /* NOTREACHED */ } int |