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 */ #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);