From 3e93cc3ae35baf2f2398b3bee5ce38393eb7a595 Mon Sep 17 00:00:00 2001 From: David Xu Date: Sun, 8 Aug 2004 22:37:53 +0000 Subject: [PATCH] 1.Use new way to check if a thread is in critical region, defer suspending if it is true. 2.Add thread_db api td_thr_tls_get_addr to get tls address, the real code is commented out util tls patch is committed. Reviewed by: deischen --- lib/libthread_db/Makefile | 8 +- lib/libthread_db/libpthread_db.c | 141 ++++++++++++++++++++++++------- lib/libthread_db/thread_db.c | 8 ++ lib/libthread_db/thread_db.h | 1 + lib/libthread_db/thread_db_int.h | 2 + 5 files changed, 127 insertions(+), 33 deletions(-) diff --git a/lib/libthread_db/Makefile b/lib/libthread_db/Makefile index c94636b9e3d..bf8e338e335 100644 --- a/lib/libthread_db/Makefile +++ b/lib/libthread_db/Makefile @@ -11,7 +11,13 @@ SRCS+= libthr_db.c INCS= thread_db.h WARNS?= 1 -CFLAGS+=-I. -I${.CURDIR} +CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../libexec/rtld-elf +CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH} +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +CFLAGS+=-DTLS_DTV_AT_TCB +.else +CFLAGS+=-DTLS_DTV_AT_TP +.endif SRCS+= libpthread.h CLEANFILES+= libpthread.h diff --git a/lib/libthread_db/libpthread_db.c b/lib/libthread_db/libpthread_db.c index c5ef5ce1632..239b846dd9e 100644 --- a/lib/libthread_db/libpthread_db.c +++ b/lib/libthread_db/libpthread_db.c @@ -27,6 +27,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -38,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "rtld.h" + #include "libpthread.h" #include "libpthread_db.h" @@ -413,8 +416,7 @@ pt_dbsuspend(const td_thrhandle_t *th, int suspend) psaddr_t tcb_addr, tmbx_addr, ptr; lwpid_t lwp; uint32_t dflags; - int attrflags; - int ret; + int attrflags, locklevel, ret; TDBG_FUNC(); @@ -445,40 +447,57 @@ pt_dbsuspend(const td_thrhandle_t *th, int suspend) ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); if (ret != 0) return (P2T(ret)); - /* - * Don't stop lwp assigned to a M:N thread, it belongs - * to UTS, UTS shouldn't be stopped. - */ - if (lwp != 0 && (attrflags & PTHREAD_SCOPE_SYSTEM)) { - /* dont' suspend signal thread */ + + if (lwp != 0) { + /* don't suspend signal thread */ if (attrflags & THR_SIGNAL_THREAD) - return 0; - ptr = ta->map[th->th_tid].thr + - offsetof(struct pthread, kse); - /* Too many indirect level :-( */ - /* read struct kse * */ - ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); - if (ret != 0) - return (P2T(ret)); - ptr = ptr + offsetof(struct kse, k_kcb); - /* read k_kcb * */ - ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); - if (ret != 0) - return (P2T(ret)); - /* read kcb.kcb_kmbx.km_curthread */ - ptr = ptr + offsetof(struct kcb, kcb_kmbx.km_curthread); - ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); - if (ret != 0) - return (P2T(ret)); - if (ptr != 0) { /* not in critical */ - if (suspend) - ret = ps_lstop(ta->ph, lwp); - else - ret = ps_lcontinue(ta->ph, lwp); + return (0); + if (attrflags & PTHREAD_SCOPE_SYSTEM) { + /* + * don't suspend system scope thread if it is holding + * some low level locks + */ + ptr = ta->map[th->th_tid].thr + + offsetof(struct pthread, kse); + ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); if (ret != 0) return (P2T(ret)); + ret = ps_pread(ta->ph, ptr + offsetof(struct kse, + k_locklevel), &locklevel, sizeof(int)); + if (ret != 0) + return (P2T(ret)); + if (locklevel <= 0) { + ptr = ta->map[th->th_tid].thr + + offsetof(struct pthread, locklevel); + ret = ps_pread(ta->ph, ptr, &locklevel, + sizeof(int)); + if (ret != 0) + return (P2T(ret)); + } + if (suspend) { + if (locklevel <= 0) + ret = ps_lstop(ta->ph, lwp); + } else { + ret = ps_lcontinue(ta->ph, lwp); + } + if (ret != 0) + return (P2T(ret)); + /* FALLTHROUGH */ + } else { + struct ptrace_lwpinfo pl; + + if (ptrace(PT_LWPINFO, lwp, (caddr_t) &pl, sizeof(pl))) + return (TD_ERR); + if (suspend) { + if (!(pl.pl_flags & PL_FLAG_BOUND)) + ret = ps_lstop(ta->ph, lwp); + } else { + ret = ps_lcontinue(ta->ph, lwp); + } + if (ret != 0) + return (P2T(ret)); + /* FALLTHROUGH */ } - /* FALLTHROUGH */ } /* read tm_dflags */ ret = ps_pread(ta->ph, @@ -899,6 +918,63 @@ pt_validate(const td_thrhandle_t *th) return (TD_OK); } +td_err_e +pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, + void **address) +{ +#if 0 + Obj_Entry *obj_entry; + const td_thragent_t *ta = th->th_ta; + psaddr_t tcb_addr, *dtv_addr, tcb_tp; + int tls_index, ret; + + /* linkmap is a member of Obj_Entry */ + obj_entry = (Obj_Entry *) + (((char *)_linkmap) - offsetof(Obj_Entry, linkmap)); + + /* get tlsindex of the object file */ + ret = ps_pread(ta->ph, + ((char *)obj_entry) + offsetof(Obj_Entry, tlsindex), + &tls_index, sizeof(tls_index)); + if (ret != 0) + return (P2T(ret)); + + /* get thread tcb */ + ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + + offsetof(struct pthread, tcb), + &tcb_addr, sizeof(tcb_addr)); + if (ret != 0) + return (P2T(ret)); + +#ifdef TLS_DTV_AT_TCB + /* get dtv array address */ + ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb, tcb_dtv), + &dtv_addr, sizeof(dtv_addr)); + if (ret != 0) + return (P2T(ret)); +#else + #ifdef TLS_DTV_AT_TP + ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb, tcb_tp), + &tcb_tp, sizeof(tcb_tp)); + if (ret != 0) + return (P2T(ret)); + ret = ps_pread(ta->ph, tcb_tp + offsetof(struct tp, tp_dtv), + &dtv_addr, sizeof(dtv_addr)); + #else + #error "Either TLS_DTV_AT_TP or TLS_DTV_AT_TCB must be defined." + #endif +#endif + /* now get the object's tls block base address */ + ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, + sizeof(*address)); + if (ret != 0) + return (P2T(ret)); + + *address += offset; +#endif + return (TD_OK); +} + struct ta_ops libpthread_db_ops = { .to_init = pt_init, .to_ta_clear_event = pt_ta_clear_event, @@ -923,6 +999,7 @@ struct ta_ops libpthread_db_ops = { .to_thr_setfpregs = pt_thr_setfpregs, .to_thr_setgregs = pt_thr_setgregs, .to_thr_validate = pt_thr_validate, + .to_thr_tls_get_addr = pt_thr_tls_get_addr, /* FreeBSD specific extensions. */ .to_thr_sstep = pt_thr_sstep, diff --git a/lib/libthread_db/thread_db.c b/lib/libthread_db/thread_db.c index e92d4ff3c13..b1b1bccc9f6 100644 --- a/lib/libthread_db/thread_db.c +++ b/lib/libthread_db/thread_db.c @@ -226,6 +226,14 @@ td_thr_validate(const td_thrhandle_t *th) return (ta->ta_ops->to_thr_validate(th)); } +td_err_e +td_thr_tls_get_addr(const td_thrhandle_t *th, void *linkmap, size_t offset, + void **address) +{ + const td_thragent_t *ta = th->th_ta; + return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); +} + /* FreeBSD specific extensions. */ td_err_e diff --git a/lib/libthread_db/thread_db.h b/lib/libthread_db/thread_db.h index eaad92178aa..8827dd698d7 100644 --- a/lib/libthread_db/thread_db.h +++ b/lib/libthread_db/thread_db.h @@ -231,6 +231,7 @@ td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *); td_err_e td_thr_setfpregs(const td_thrhandle_t *, const prfpregset_t *); td_err_e td_thr_setgregs(const td_thrhandle_t *, const prgregset_t); td_err_e td_thr_validate(const td_thrhandle_t *); +td_err_e td_thr_tls_get_addr(const td_thrhandle_t *, void *, size_t, void **); /* FreeBSD specific extensions. */ td_err_e td_thr_sstep(const td_thrhandle_t *, int); diff --git a/lib/libthread_db/thread_db_int.h b/lib/libthread_db/thread_db_int.h index 1b562518d21..7dc152cb344 100644 --- a/lib/libthread_db/thread_db_int.h +++ b/lib/libthread_db/thread_db_int.h @@ -74,6 +74,8 @@ struct ta_ops { const prfpregset_t *); td_err_e (*to_thr_setgregs)(const td_thrhandle_t *, const prgregset_t); td_err_e (*to_thr_validate)(const td_thrhandle_t *); + td_err_e (*to_thr_tls_get_addr)(const td_thrhandle_t *, + void *, size_t, void **); /* FreeBSD specific extensions. */ td_err_e (*to_thr_sstep)(const td_thrhandle_t *, int);