From: Apple Date: Wed, 29 Mar 2017 19:58:47 +0000 (+0000) Subject: libpthread-218.51.1.tar.gz X-Git-Tag: macos-10124^0 X-Git-Url: https://git.saurik.com/apple/libpthread.git/commitdiff_plain/010efe49ed19075418796acfb56075924aa43936?hp=1feaeaac93c7205dd7f4a739b5b97561d8343429 libpthread-218.51.1.tar.gz --- diff --git a/kern/kern_init.c b/kern/kern_init.c index ca10fd0..b45d277 100644 --- a/kern/kern_init.c +++ b/kern/kern_init.c @@ -45,6 +45,9 @@ const struct pthread_functions_s pthread_internal_functions = { .psynch_rw_wrlock = _psynch_rw_wrlock, .psynch_rw_yieldwrlock = _psynch_rw_yieldwrlock, + .pthread_find_owner = _pthread_find_owner, + .pthread_get_thread_kwq = _pthread_get_thread_kwq, + .workq_reqthreads = _workq_reqthreads, .thread_qos_from_pthread_priority = _thread_qos_from_pthread_priority, .pthread_priority_canonicalize2 = _pthread_priority_canonicalize, diff --git a/kern/kern_internal.h b/kern/kern_internal.h index cdaa6ed..3f3da0a 100644 --- a/kern/kern_internal.h +++ b/kern/kern_internal.h @@ -33,6 +33,7 @@ #include #include #include +#include #endif #include "kern/synch_internal.h" @@ -310,6 +311,9 @@ int _psynch_rw_unlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t u int _psynch_rw_wrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval); int _psynch_rw_yieldwrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval); +void _pthread_find_owner(thread_t thread, struct stackshot_thread_waitinfo *waitinfo); +void * _pthread_get_thread_kwq(thread_t thread); + extern lck_grp_attr_t *pthread_lck_grp_attr; extern lck_grp_t *pthread_lck_grp; extern lck_attr_t *pthread_lck_attr; diff --git a/kern/kern_support.c b/kern/kern_support.c index ece5c6f..f63a781 100644 --- a/kern/kern_support.c +++ b/kern/kern_support.c @@ -1866,8 +1866,12 @@ _workq_open(struct proc *p, __unused int32_t *retval) TAILQ_INIT(&wq->wq_thrunlist); TAILQ_INIT(&wq->wq_thidlelist); - wq->wq_atimer_delayed_call = thread_call_allocate((thread_call_func_t)workqueue_add_timer, (thread_call_param_t)wq); - wq->wq_atimer_immediate_call = thread_call_allocate((thread_call_func_t)workqueue_add_timer, (thread_call_param_t)wq); + wq->wq_atimer_delayed_call = + thread_call_allocate_with_priority((thread_call_func_t)workqueue_add_timer, + (thread_call_param_t)wq, THREAD_CALL_PRIORITY_KERNEL); + wq->wq_atimer_immediate_call = + thread_call_allocate_with_priority((thread_call_func_t)workqueue_add_timer, + (thread_call_param_t)wq, THREAD_CALL_PRIORITY_KERNEL); lck_spin_init(&wq->wq_lock, pthread_lck_grp, pthread_lck_attr); @@ -2520,6 +2524,7 @@ parkit(struct workqueue *wq, struct threadlist *tl, thread_t thread) us_to_wait = wq_reduce_pool_window_usecs / 100; } + thread_set_pending_block_hint(thread, kThreadWaitParkedWorkQueue); assert_wait_timeout_with_leeway((caddr_t)tl, (THREAD_INTERRUPTIBLE), TIMEOUT_URGENCY_SYS_BACKGROUND|TIMEOUT_URGENCY_LEEWAY, us_to_wait, wq_reduce_pool_window_usecs/10, NSEC_PER_USEC); @@ -3018,6 +3023,7 @@ wq_unpark_continue(void* __unused ptr, wait_result_t wait_result) workqueue_lock_spin(wq); if ( !(tl->th_flags & TH_LIST_RUNNING)) { + thread_set_pending_block_hint(th, kThreadWaitParkedWorkQueue); assert_wait((caddr_t)tl, (THREAD_INTERRUPTIBLE)); workqueue_unlock(wq); diff --git a/kern/kern_synch.c b/kern/kern_synch.c index 4e76749..dab8327 100644 --- a/kern/kern_synch.c +++ b/kern/kern_synch.c @@ -68,6 +68,7 @@ #include #include #include +#include //#include #include #include @@ -271,7 +272,7 @@ static int ksyn_findobj(user_addr_t uaddr, uint64_t *objectp, uint64_t *offsetp) static int _wait_result_to_errno(wait_result_t result); -static int ksyn_wait(ksyn_wait_queue_t, int, uint32_t, int, uint64_t, thread_continue_t); +static int ksyn_wait(ksyn_wait_queue_t, int, uint32_t, int, uint64_t, thread_continue_t, block_hint_t); static kern_return_t ksyn_signal(ksyn_wait_queue_t, int, ksyn_waitq_element_t, uint32_t); static void ksyn_freeallkwe(ksyn_queue_t kq); @@ -745,7 +746,7 @@ _psynch_mutexwait(__unused proc_t p, ksyn_mtx_update_owner_qos_override(kwq, tid, FALSE); kwq->kw_owner = tid; - error = ksyn_wait(kwq, KSYN_QUEUE_WRITER, mgen, ins_flags, 0, psynch_mtxcontinue); + error = ksyn_wait(kwq, KSYN_QUEUE_WRITER, mgen, ins_flags, 0, psynch_mtxcontinue, kThreadWaitPThreadMutex); // ksyn_wait drops wait queue lock out: ksyn_wqrelease(kwq, 1, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_MTX)); @@ -1170,7 +1171,7 @@ _psynch_cvwait(__unused proc_t p, clock_absolutetime_interval_to_deadline(abstime, &abstime); } - error = ksyn_wait(ckwq, KSYN_QUEUE_WRITER, cgen, SEQFIT, abstime, psynch_cvcontinue); + error = ksyn_wait(ckwq, KSYN_QUEUE_WRITER, cgen, SEQFIT, abstime, psynch_cvcontinue, kThreadWaitPThreadCondVar); // ksyn_wait drops wait queue lock } @@ -1320,7 +1321,9 @@ __psynch_rw_lock(int type, _ksyn_handle_prepost(kwq, prepost_type, lockseq, retval)) { ksyn_wqunlock(kwq); } else { - error = ksyn_wait(kwq, kqi, lgenval, SEQFIT, 0, THREAD_CONTINUE_NULL); + block_hint_t block_hint = type == PTH_RW_TYPE_READ ? + kThreadWaitPThreadRWLockRead : kThreadWaitPThreadRWLockWrite; + error = ksyn_wait(kwq, kqi, lgenval, SEQFIT, 0, THREAD_CONTINUE_NULL, block_hint); // ksyn_wait drops wait queue lock if (error == 0) { uthread_t uth = current_uthread(); @@ -1817,7 +1820,8 @@ ksyn_wait(ksyn_wait_queue_t kwq, uint32_t lockseq, int fit, uint64_t abstime, - thread_continue_t continuation) + thread_continue_t continuation, + block_hint_t block_hint) { int res; @@ -1838,6 +1842,7 @@ ksyn_wait(ksyn_wait_queue_t kwq, return res; } + thread_set_pending_block_hint(th, block_hint); assert_wait_deadline_with_leeway(&kwe->kwe_psynchretval, THREAD_ABORTSAFE, TIMEOUT_URGENCY_USER_NORMAL, abstime, 0); ksyn_wqunlock(kwq); @@ -2599,3 +2604,52 @@ psynch_zoneinit(void) kwq_zone = (zone_t)pthread_kern->zinit(sizeof(struct ksyn_wait_queue), 8192 * sizeof(struct ksyn_wait_queue), 4096, "ksyn_wait_queue"); kwe_zone = (zone_t)pthread_kern->zinit(sizeof(struct ksyn_waitq_element), 8192 * sizeof(struct ksyn_waitq_element), 4096, "ksyn_waitq_element"); } + +void * +_pthread_get_thread_kwq(thread_t thread) +{ + assert(thread); + struct uthread * uthread = pthread_kern->get_bsdthread_info(thread); + assert(uthread); + ksyn_waitq_element_t kwe = pthread_kern->uthread_get_uukwe(uthread); + assert(kwe); + ksyn_wait_queue_t kwq = kwe->kwe_kwqqueue; + return kwq; +} + +/* This function is used by stackshot to determine why a thread is blocked, and report + * who owns the object that the thread is blocked on. It should *only* be called if the + * `block_hint' field in the relevant thread's struct is populated with something related + * to pthread sync objects. + */ +void +_pthread_find_owner(thread_t thread, struct stackshot_thread_waitinfo * waitinfo) +{ + ksyn_wait_queue_t kwq = _pthread_get_thread_kwq(thread); + switch (waitinfo->wait_type) { + case kThreadWaitPThreadMutex: + assert((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_MTX); + waitinfo->owner = kwq->kw_owner; + waitinfo->context = kwq->kw_addr; + break; + /* Owner of rwlock not stored in kernel space due to races. Punt + * and hope that the userspace address is helpful enough. */ + case kThreadWaitPThreadRWLockRead: + case kThreadWaitPThreadRWLockWrite: + assert((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_RWLOCK); + waitinfo->owner = 0; + waitinfo->context = kwq->kw_addr; + break; + /* Condvars don't have owners, so just give the userspace address. */ + case kThreadWaitPThreadCondVar: + assert((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_CVAR); + waitinfo->owner = 0; + waitinfo->context = kwq->kw_addr; + break; + case kThreadWaitNone: + default: + waitinfo->owner = 0; + waitinfo->context = 0; + break; + } +} diff --git a/pthread/sched.h b/pthread/sched.h index df1fc51..91efb4e 100644 --- a/pthread/sched.h +++ b/pthread/sched.h @@ -24,8 +24,8 @@ #ifndef _SCHED_H_ #define _SCHED_H_ -#include #include +#include __BEGIN_DECLS /* diff --git a/src/pthread_atfork.c b/src/pthread_atfork.c index b799f3f..ec174df 100644 --- a/src/pthread_atfork.c +++ b/src/pthread_atfork.c @@ -93,13 +93,13 @@ pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) // Called before the fork(2) system call is made in the parent process. // Iterate pthread_atfork prepare handlers. +// Called first in libSystem_atfork_prepare(). void -_pthread_fork_prepare(void) +_pthread_atfork_prepare_handlers(void) { pthread_globals_t globals = _pthread_globals(); _PTHREAD_LOCK(globals->pthread_atfork_lock); - size_t idx; for (idx = globals->atfork_count; idx > 0; --idx) { struct pthread_atfork_entry *e = &globals->atfork[idx-1]; @@ -107,6 +107,14 @@ _pthread_fork_prepare(void) e->prepare(); } } +} + +// Take pthread-internal locks. +// Called last in libSystem_atfork_prepare(). +void +_pthread_fork_prepare(void) +{ + pthread_globals_t globals = _pthread_globals(); _PTHREAD_LOCK(globals->psaved_self_global_lock); globals->psaved_self = pthread_self(); @@ -114,7 +122,8 @@ _pthread_fork_prepare(void) } // Called after the fork(2) system call returns to the parent process. -// Iterate pthread_atfork parent handlers. +// Release pthread-internal locks +// Called first in libSystem_atfork_parent(). void _pthread_fork_parent(void) { @@ -122,6 +131,14 @@ _pthread_fork_parent(void) _PTHREAD_UNLOCK(globals->psaved_self->lock); _PTHREAD_UNLOCK(globals->psaved_self_global_lock); +} + +// Iterate pthread_atfork parent handlers. +// Called last in libSystem_atfork_parent(). +void +_pthread_atfork_parent_handlers(void) +{ + pthread_globals_t globals = _pthread_globals(); size_t idx; for (idx = 0; idx < globals->atfork_count; ++idx) { @@ -136,6 +153,7 @@ _pthread_fork_parent(void) // Called after the fork(2) system call returns to the new child process. // Clean up data structures of other threads which no longer exist in the child. // Make the current thread the main thread. +// Called first in libSystem_atfork_child() (after _dyld_fork_child) void _pthread_fork_child(void) { @@ -147,8 +165,9 @@ _pthread_fork_child(void) } // Iterate pthread_atfork child handlers. +// Called last in libSystem_atfork_child(). void -_pthread_fork_child_postinit(void) +_pthread_atfork_child_handlers(void) { pthread_globals_t globals = _pthread_globals(); size_t idx; @@ -160,3 +179,10 @@ _pthread_fork_child_postinit(void) } _PTHREAD_LOCK_INIT(globals->pthread_atfork_lock); } + +// Preserve legacy symbol in case somebody depends on it +void +_pthread_fork_child_postinit(void) +{ + _pthread_atfork_child_handlers(); +} diff --git a/tools/wqtrace.lua b/tools/wqtrace.lua index e60383b..61f0c60 100755 --- a/tools/wqtrace.lua +++ b/tools/wqtrace.lua @@ -3,7 +3,7 @@ trace_codename = function(codename, callback) local debugid = trace.debugid(codename) if debugid ~= 0 then - trace.single(debugid,callback) + trace.single(debugid,callback) else printf("WARNING: Cannot locate debugid for '%s'\n", codename) end @@ -15,15 +15,15 @@ get_prefix = function(buf) if initial_timestamp == 0 then initial_timestamp = buf.timestamp end - local secs = (buf.timestamp - initial_timestamp) / 1000000000 + local secs = trace.convert_timestamp_to_nanoseconds(buf.timestamp - initial_timestamp) / 1000000000 local prefix - if trace.debugid_is_start(buf.debugid) then - prefix = "→" - elseif trace.debugid_is_end(buf.debugid) then - prefix = "←" - else - prefix = "↔" + if trace.debugid_is_start(buf.debugid) then + prefix = "→" + elseif trace.debugid_is_end(buf.debugid) then + prefix = "←" + else + prefix = "↔" end local proc @@ -196,12 +196,29 @@ trace_codename("wq_run_nextitem", function(buf) end end) +trace.enable_thread_cputime() +runitem_time_map = {} +runitem_cputime_map = {} trace_codename("wq_runitem", function(buf) local prefix = get_prefix(buf) if trace.debugid_is_start(buf.debugid) then + runitem_time_map[buf.threadid] = buf.timestamp; + runitem_cputime_map[buf.threadid] = trace.cputime_for_thread(buf.threadid); + printf("%s\tSTART running item\n", prefix) + elseif runitem_time_map[buf.threadid] then + local time = buf.timestamp - runitem_time_map[buf.threadid] + local cputime = trace.cputime_for_thread(buf.threadid) - runitem_cputime_map[buf.threadid] + + local time_ms = trace.convert_timestamp_to_nanoseconds(time) / 1000000 + local cputime_ms = trace.convert_timestamp_to_nanoseconds(cputime) / 1000000 + + printf("%s\tDONE running item: time = %6.6f ms, cputime = %6.6f ms\n", prefix, time_ms, cputime_ms) + + runitem_time_map[buf.threadid] = 0 + runitem_cputime_map[buf.threadid] = 0 else - printf("%s\tDONE running item; thread returned to kernel\n", prefix) + printf("%s\tDONE running item\n", prefix) end end)