]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/turnstile.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / turnstile.c
index baa08bf2735f5a8fd07db391edda6748232de9a6..8d98e3989c8fa228c3a8a98def0f17ed7b89ac97 100644 (file)
@@ -3188,59 +3188,72 @@ turnstile_stats_update(
 static uint64_t
 kdp_turnstile_traverse_inheritor_chain(struct turnstile *ts, uint64_t *flags, uint8_t *hops)
 {
+       uint8_t unknown_hops;
+
        if (waitq_held(&ts->ts_waitq)) {
                *flags |= STACKSHOT_TURNSTILE_STATUS_LOCKED_WAITQ;
                return 0;
        }
 
        *hops = *hops + 1;
+       unknown_hops = *hops;
+
+       /*
+        * If a turnstile is inheriting our priority, recurse.  If we get back *exactly* UNKNOWN,
+        * continue on, since we may be able to give a more specific answer.  To
+        * give an accurate hops count, we reset *hops, saving the recursive value in
+        * unknown_hops to use if we can't give a better answer.
+        */
+       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_TURNSTILE) {
+               uint8_t pre_hops = *hops;
+               uint64_t ret = kdp_turnstile_traverse_inheritor_chain(ts->ts_inheritor, flags, hops);
+               /*
+                * Note that while flags is usually |=ed, we're checking with != here to
+                * make sure we only replace *exactly* UNKNOWN
+                */
+               if (ret != 0 || *flags != STACKSHOT_TURNSTILE_STATUS_UNKNOWN) {
+                       return ret;
+               }
+               /* restore original hops value, saving the new one if we fall through to unknown */
+               unknown_hops = *hops;
+               *hops = pre_hops;
+               *flags = 0;
+       }
+
+       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_THREAD) {
+               *flags |= STACKSHOT_TURNSTILE_STATUS_THREAD;
+               return (uint64_t) thread_tid(ts->ts_inheritor);
+       }
+
+       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_WORKQ) {
+               *flags |= STACKSHOT_TURNSTILE_STATUS_WORKQUEUE;
+               return VM_KERNEL_UNSLIDE_OR_PERM(ts->ts_inheritor);
+       }
 
        /*
         * If we found a send turnstile, try to get the task that the turnstile's
         * port is in the ipc space of
         */
        if (turnstile_is_send_turnstile(ts)) {
-               task_t dest_task = TASK_NULL;
                ipc_port_t port = (ipc_port_t)ts->ts_proprietor;
 
                if (port && ip_active(port)) {
                        if (ip_lock_held_kdp(port)) {
                                *flags |= STACKSHOT_TURNSTILE_STATUS_HELD_IPLOCK;
-
                                return 0;
-                       } else {
-                               if (port->ip_receiver_name != 0) {
-                                       if (port->ip_receiver) {
-                                               ipc_space_t space = (ipc_space_t) port->ip_receiver;
-
-                                               dest_task = space->is_task;
-                                       } else {
-                                               return 0;
-                                       }
-                               }
                        }
-               }
+                       if (port->ip_receiver_name != 0 && port->ip_receiver) {
+                               ipc_space_t space = (ipc_space_t) port->ip_receiver;
+                               task_t dest_task = space->is_task;
 
-               if (dest_task != TASK_NULL) {
-                       *flags |= STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK;
-                       return pid_from_task(dest_task);
+                               if (dest_task != TASK_NULL) {
+                                       *flags |= STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK;
+                                       return pid_from_task(dest_task);
+                               }
+                       }
                }
        }
 
-       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_TURNSTILE) {
-               return kdp_turnstile_traverse_inheritor_chain(ts->ts_inheritor, flags, hops);
-       }
-
-       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_THREAD) {
-               *flags |= STACKSHOT_TURNSTILE_STATUS_THREAD;
-               return (uint64_t) thread_tid(ts->ts_inheritor);
-       }
-
-       if (ts->ts_inheritor_flags & TURNSTILE_INHERITOR_WORKQ) {
-               *flags |= STACKSHOT_TURNSTILE_STATUS_WORKQUEUE;
-               return VM_KERNEL_UNSLIDE_OR_PERM(ts->ts_inheritor);
-       }
-
        if (turnstile_is_receive_turnstile(ts)) {
                ipc_port_t port = (ipc_port_t)ts->ts_proprietor;
                if (port && ip_active(port)) {
@@ -3260,6 +3273,7 @@ kdp_turnstile_traverse_inheritor_chain(struct turnstile *ts, uint64_t *flags, ui
                }
        }
 
+       *hops = unknown_hops;
        *flags |= STACKSHOT_TURNSTILE_STATUS_UNKNOWN;
        return 0;
 }