+
+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;
+ }
+}