summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_thr.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-12-29 23:25:26 +0000
committerjhb <jhb@FreeBSD.org>2015-12-29 23:25:26 +0000
commitfb5720f7be0d2eab3253696e244c058a229b5473 (patch)
tree38cac37b4cace20e5e9e11b5763940c44fe6be7f /sys/kern/kern_thr.c
parent79ec12eeb6f427ceaaaa94ca98073316d8c24e47 (diff)
downloadFreeBSD-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.c63
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
OpenPOWER on IntegriCloud