From d245d9e13fa39cab381193a24af50f540bb37e9f Mon Sep 17 00:00:00 2001
From: David Xu <davidxu@FreeBSD.org>
Date: Tue, 12 Apr 2005 03:00:28 +0000
Subject: [PATCH] Add debugger event reporting support, current only TD_CREATE
 and TD_DEATH events are reported.

---
 lib/libthr/Makefile             |  1 +
 lib/libthr/pthread.map          | 17 +++++++++++------
 lib/libthr/thread/Makefile.inc  |  1 +
 lib/libthr/thread/thr_create.c  | 21 ++++++++++++++++++---
 lib/libthr/thread/thr_exit.c    |  4 +++-
 lib/libthr/thread/thr_init.c    |  2 ++
 lib/libthr/thread/thr_list.c    |  2 +-
 lib/libthr/thread/thr_private.h | 29 +++++++++++++++++++++++++----
 lib/libthr/thread/thr_symbols.c |  5 +++--
 9 files changed, 65 insertions(+), 17 deletions(-)

diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
index 24ebe7c28114..0df6873fed53 100644
--- a/lib/libthr/Makefile
+++ b/lib/libthr/Makefile
@@ -16,6 +16,7 @@ CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
 CFLAGS+=-I${.CURDIR}/sys
 CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
 CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-I${.CURDIR}/../libthread_db
 CFLAGS+=-Winline
 
 # CFLAGS+=-DSYSTEM_SCOPE_ONLY
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index 12f0183b2ce1..be30e9663c65 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -344,21 +344,26 @@ global:
 	# Debugger needs these.
 	_libthr_debug;
 	_thread_active_threads;
+	_thread_bp_create;
+	_thread_bp_death;
+	_thread_event_mask;
 	_thread_keytable;
+	_thread_last_event;
 	_thread_list;
 	_thread_max_keys;
 	_thread_off_attr_flags;
 	_thread_off_dtv;
-	_thread_off_linkmap;
-	_thread_off_next;
-	_thread_off_tcb;
-	_thread_off_tid;
+	_thread_off_event_buf;
+	_thread_off_event_mask;
 	_thread_off_key_allocated;
 	_thread_off_key_destructor;
+	_thread_off_linkmap;
+	_thread_off_next;
+	_thread_off_report_events;
 	_thread_off_state;
-	_thread_off_thr_locklevel;
+	_thread_off_tcb;
+	_thread_off_tid;
 	_thread_off_tlsindex;
-	_thread_off_isdead;
 	_thread_size_key;
 	_thread_state_running;
 	_thread_state_zoombie;
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
index d756a32fea78..595d99457b22 100644
--- a/lib/libthr/thread/Makefile.inc
+++ b/lib/libthr/thread/Makefile.inc
@@ -15,6 +15,7 @@ SRCS+= \
 	thr_create.c \
 	thr_detach.c \
 	thr_equal.c \
+	thr_event.c \
 	thr_exit.c \
 	thr_fork.c \
 	thr_getprio.c \
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
index d5e9a620a386..af0697c848e6 100644
--- a/lib/libthr/thread/thr_create.c
+++ b/lib/libthr/thread/thr_create.c
@@ -56,7 +56,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
 	ucontext_t uc;
 	sigset_t sigmask, oldsigmask;
 	struct pthread *curthread, *new_thread;
-	int ret = 0;
+	int ret = 0, locked;
 
 	_thr_check_init();
 
@@ -92,9 +92,10 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
 	else if (_thr_scope_system < 0)
 		new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
 
+	new_thread->tid = TID_TERMINATED;
+
 	if (create_stack(&new_thread->attr) != 0) {
 		/* Insufficient memory to create a stack: */
-		new_thread->terminated = 1;
 		_thr_free(curthread, new_thread);
 		return (EAGAIN);
 	}
@@ -151,20 +152,31 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
 	 * it can not handle signal, so we should masks all signals here.
 	 */
 	SIGFILLSET(sigmask);
+	SIGDELSET(sigmask, SIGTRAP);
 	__sys_sigprocmask(SIG_SETMASK, &sigmask, &oldsigmask);
 	new_thread->sigmask = oldsigmask;
 	/* Add the new thread. */
 	_thr_link(curthread, new_thread);
 	/* Return thread pointer eariler so that new thread can use it. */
 	(*thread) = new_thread;
+	if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) {
+		THR_THREAD_LOCK(curthread, new_thread);
+		locked = 1;
+	} else
+		locked = 0;
 	/* Schedule the new thread. */
 	ret = thr_create(&uc, &new_thread->tid, 0);
 	__sys_sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
 	if (ret != 0) {
+		if (locked)
+			THR_THREAD_UNLOCK(curthread, new_thread);
 		_thr_unlink(curthread, new_thread);
 		free_thread(curthread, new_thread);
 		(*thread) = 0;
 		ret = EAGAIN;
+	} else if (locked) {
+		_thr_report_creation(curthread, new_thread);
+		THR_THREAD_UNLOCK(curthread, new_thread);
 	}
 	return (ret);
 }
@@ -173,7 +185,7 @@ static void
 free_thread(struct pthread *curthread, struct pthread *thread)
 {
 	free_stack(curthread, &thread->attr);
-	curthread->terminated = 1;
+	curthread->tid = TID_TERMINATED;
 	_thr_free(curthread, thread);
 }
 
@@ -215,6 +227,9 @@ thread_start(struct pthread *curthread)
 	if (curthread->flags & THR_FLAGS_NEED_SUSPEND)
 		_thr_suspend_check(curthread);
 
+	THR_LOCK(curthread);
+	THR_UNLOCK(curthread);
+
 	/* Run the current thread's start routine with argument: */
 	pthread_exit(curthread->start_routine(curthread->arg));
 
diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
index 554646b7de81..4f4eff6c5158 100644
--- a/lib/libthr/thread/thr_exit.c
+++ b/lib/libthr/thread/thr_exit.c
@@ -130,7 +130,9 @@ _pthread_exit(void *status)
 	THREAD_LIST_UNLOCK(curthread);
 	if (curthread->joiner)
 		_thr_umtx_wake(&curthread->state, INT_MAX);
-	thr_exit(&curthread->terminated);
+	if (SHOULD_REPORT_EVENT(curthread, TD_DEATH))
+		_thr_report_death(curthread);
+	thr_exit(&curthread->tid);
 	PANIC("thr_exit() returned");
 	/* Never reach! */
 }
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index a0f4e5c48641..7636fecf45fc 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -309,6 +309,7 @@ _libpthread_init(struct pthread *curthread)
 		_thr_initial = curthread;
 		SIGDELSET(oldset, SIGCANCEL);
 		__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+		_thr_report_creation(curthread, curthread);
 	}
 }
 
@@ -384,6 +385,7 @@ init_private(void)
 	_thr_umtx_init(&_rwlock_static_lock);
 	_thr_umtx_init(&_keytable_lock);
 	_thr_umtx_init(&_thr_atfork_lock);
+	_thr_umtx_init(&_thr_event_lock);
 	_thr_spinlock_init();
 	_thr_list_init();
 
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index 06d14e8a5c87..a0d5aaa1427d 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -99,7 +99,7 @@ _thr_gc(struct pthread *curthread)
 	/* Check the threads waiting for GC. */
 	for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) {
 		td_next = TAILQ_NEXT(td, gcle);
-		if (td->terminated == 0) {
+		if (td->tid != TID_TERMINATED) {
 			/* make sure we are not still in userland */
 			continue;
 		}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 405340fc31c6..3c4f9edd29a3 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -56,6 +56,7 @@
 
 #include "pthread_md.h"
 #include "thr_umtx.h"
+#include "thread_db.h"
 
 /*
  * Evaluate the storage class specifier.
@@ -345,11 +346,9 @@ struct pthread {
 	 */
 	umtx_t			lock;
 
-	/* Thread is terminated in kernel, written by kernel. */
-	long			terminated;
-
 	/* Kernel thread id. */
 	long			tid;
+#define	TID_TERMINATED		1
 
 	/* Internal condition variable cycle number. */
 	umtx_t			cycle;
@@ -491,6 +490,15 @@ struct pthread {
 
 	/* Cleanup handlers Link List */
 	struct pthread_cleanup	*cleanup;
+
+	/* Enable event reporting */
+	int			report_events;
+
+	/* Event mask */
+	int			event_mask;
+
+	/* Event */
+	td_event_msg_t		event_buf;
 };
 
 #define THR_UMTX_TRYLOCK(thrd, lck)			\
@@ -573,6 +581,10 @@ do {								\
 
 #define	THR_IN_SYNCQ(thrd)	(((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
 
+#define SHOULD_REPORT_EVENT(curthr, e)			\
+	(curthr->report_events && 			\
+	 (((curthr)->event_mask | _thread_event_mask ) & e) != 0)
+
 extern int __isthreaded;
 
 /*
@@ -581,9 +593,12 @@ extern int __isthreaded;
 
 SCLASS void		*_usrstack	SCLASS_PRESET(NULL);
 SCLASS struct pthread	*_thr_initial	SCLASS_PRESET(NULL);
+SCLASS int		_thr_scope_system	SCLASS_PRESET(0);
+
 /* For debugger */
 SCLASS int		_libthr_debug		SCLASS_PRESET(0);
-SCLASS int		_thr_scope_system	SCLASS_PRESET(0);
+SCLASS int		_thread_event_mask	SCLASS_PRESET(0);
+SCLASS struct pthread	*_thread_last_event;
 
 /* List of all threads: */
 SCLASS TAILQ_HEAD(, pthread)	_thread_list
@@ -643,6 +658,7 @@ SCLASS umtx_t		_cond_static_lock;
 SCLASS umtx_t		_rwlock_static_lock;
 SCLASS umtx_t		_keytable_lock;
 SCLASS umtx_t		_thr_list_lock;
+SCLASS umtx_t		_thr_event_lock;
 
 /* Undefine the storage class and preset specifiers: */
 #undef  SCLASS
@@ -720,6 +736,11 @@ void	_thr_link(struct pthread *curthread, struct pthread *thread);
 void	_thr_unlink(struct pthread *curthread, struct pthread *thread);
 void	_thr_suspend_check(struct pthread *curthread);
 void	_thr_assert_lock_level() __dead2;
+void	_thr_report_creation(struct pthread *curthread,
+			   struct pthread *newthread);
+void	_thr_report_death(struct pthread *curthread);
+void	_thread_bp_create(void);
+void	_thread_bp_death(void);
 
 /* #include <sys/aio.h> */
 #ifdef _SYS_AIO_H_
diff --git a/lib/libthr/thread/thr_symbols.c b/lib/libthr/thread/thr_symbols.c
index 313cad76187e..c35f2c717fe8 100644
--- a/lib/libthr/thread/thr_symbols.c
+++ b/lib/libthr/thread/thr_symbols.c
@@ -45,10 +45,11 @@ int _thread_off_tcb = offsetof(struct pthread, tcb);
 int _thread_off_tid = offsetof(struct pthread, tid);
 int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
 int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
-int _thread_off_thr_locklevel = offsetof(struct pthread, locklevel);
 int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
 int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
-int _thread_off_isdead = offsetof(struct pthread, terminated);
+int _thread_off_report_events = offsetof(struct pthread, report_events);
+int _thread_off_event_mask = offsetof(struct pthread, event_mask);
+int _thread_off_event_buf = offsetof(struct pthread, event_buf);
 int _thread_size_key = sizeof(struct pthread_key);
 int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
 int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);