]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/thread_act.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / thread_act.c
index 4faa1e9b569014dfef9b01786c340fe27e9638ea..679c11621df2425fdbbb344fbbc3aabd3c592911 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
@@ -74,6 +74,7 @@
 #include <kern/processor.h>
 #include <kern/timer.h>
 #include <kern/affinity.h>
+#include <kern/host.h>
 
 #include <stdatomic.h>
 
@@ -91,7 +92,7 @@ static void thread_set_apc_ast_locked(thread_t thread);
  */
 void
 thread_start(
-       thread_t                        thread)
+       thread_t                        thread)
 {
        clear_wait(thread, THREAD_AWAKENED);
        thread->started = TRUE;
@@ -105,7 +106,7 @@ thread_start(
  *
  * Always called with the thread mutex locked.
  *
- * Task and task_threads mutexes also held 
+ * Task and task_threads mutexes also held
  * (so nobody can set the thread running before
  * this point)
  *
@@ -114,7 +115,7 @@ thread_start(
  */
 void
 thread_start_in_assert_wait(
-       thread_t                        thread,
+       thread_t                        thread,
        event_t             event,
        wait_interrupt_t    interruptible)
 {
@@ -134,12 +135,12 @@ thread_start_in_assert_wait(
 
        /* assert wait interruptibly forever */
        wait_result = waitq_assert_wait64_locked(waitq, CAST_EVENT64_T(event),
-                                        interruptible,
-                                        TIMEOUT_URGENCY_SYS_NORMAL,
-                                        TIMEOUT_WAIT_FOREVER,
-                                        TIMEOUT_NO_LEEWAY,
-                                        thread);
-       assert (wait_result == THREAD_WAITING);
+           interruptible,
+           TIMEOUT_URGENCY_SYS_NORMAL,
+           TIMEOUT_WAIT_FOREVER,
+           TIMEOUT_NO_LEEWAY,
+           thread);
+       assert(wait_result == THREAD_WAITING);
 
        /* mark thread started while we still hold the waitq lock */
        thread_lock(thread);
@@ -156,9 +157,11 @@ thread_start_in_assert_wait(
  */
 kern_return_t
 thread_terminate_internal(
-       thread_t                        thread)
+       thread_t                        thread,
+       thread_terminate_options_t      options)
 {
-       kern_return_t           result = KERN_SUCCESS;
+       kern_return_t           result = KERN_SUCCESS;
+       boolean_t               test_pin_bit = false;
 
        thread_mtx_lock(thread);
 
@@ -167,24 +170,35 @@ thread_terminate_internal(
 
                act_abort(thread);
 
-               if (thread->started)
+               if (thread->started) {
                        clear_wait(thread, THREAD_INTERRUPTED);
-               else {
+               else {
                        thread_start(thread);
                }
-       }
-       else
+               /* This bit can be reliably tested only if the thread is still active */
+               test_pin_bit = (options == TH_TERMINATE_OPTION_UNPIN) ? true : false;
+       } else {
                result = KERN_TERMINATED;
+       }
 
-       if (thread->affinity_set != NULL)
+       if (thread->affinity_set != NULL) {
                thread_affinity_terminate(thread);
+       }
+
+       /*
+        * <rdar://problem/53562036> thread_terminate shouldn't be allowed on pthread
+        * Until thread_terminate is disallowed for pthreads, always unpin the pinned port
+        * when the thread is being terminated.
+        */
+       ipc_thread_port_unpin(thread->ith_self, test_pin_bit);
 
        thread_mtx_unlock(thread);
 
-       if (thread != current_thread() && result == KERN_SUCCESS)
+       if (thread != current_thread() && result == KERN_SUCCESS) {
                thread_wait(thread, FALSE);
+       }
 
-       return (result);
+       return result;
 }
 
 /*
@@ -192,16 +206,18 @@ thread_terminate_internal(
  */
 kern_return_t
 thread_terminate(
-       thread_t                thread)
+       thread_t                thread)
 {
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        /* Kernel threads can't be terminated without their own cooperation */
-       if (thread->task == kernel_task && thread != current_thread())
-               return (KERN_FAILURE);
+       if (thread->task == kernel_task && thread != current_thread()) {
+               return KERN_FAILURE;
+       }
 
-       kern_return_t result = thread_terminate_internal(thread);
+       kern_return_t result = thread_terminate_internal(thread, TH_TERMINATE_OPTION_NONE);
 
        /*
         * If a kernel thread is terminating itself, force handle the APC_AST here.
@@ -217,7 +233,21 @@ thread_terminate(
                /* NOTREACHED */
        }
 
-       return (result);
+       return result;
+}
+
+kern_return_t
+thread_terminate_pinned(
+       thread_t                thread)
+{
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
+
+       assert(thread->task != kernel_task);
+
+       kern_return_t result = thread_terminate_internal(thread, TH_TERMINATE_OPTION_UNPIN);
+       return result;
 }
 
 /*
@@ -251,8 +281,9 @@ thread_release(thread_t thread)
        assertf(thread->suspend_count > 0, "thread %p over-resumed", thread);
 
        /* fail-safe on non-assert builds */
-       if (thread->suspend_count == 0)
+       if (thread->suspend_count == 0) {
                return;
+       }
 
        if (--thread->suspend_count == 0) {
                if (!thread->started) {
@@ -269,24 +300,27 @@ thread_suspend(thread_t thread)
 {
        kern_return_t result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL || thread->task == kernel_task)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL || thread->task == kernel_task) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
        if (thread->active) {
-               if (thread->user_stop_count++ == 0)
+               if (thread->user_stop_count++ == 0) {
                        thread_hold(thread);
+               }
        } else {
                result = KERN_TERMINATED;
        }
 
        thread_mtx_unlock(thread);
 
-       if (thread != current_thread() && result == KERN_SUCCESS)
+       if (thread != current_thread() && result == KERN_SUCCESS) {
                thread_wait(thread, FALSE);
+       }
 
-       return (result);
+       return result;
 }
 
 kern_return_t
@@ -294,15 +328,17 @@ thread_resume(thread_t thread)
 {
        kern_return_t result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL || thread->task == kernel_task)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL || thread->task == kernel_task) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
        if (thread->active) {
                if (thread->user_stop_count > 0) {
-                       if (--thread->user_stop_count == 0)
+                       if (--thread->user_stop_count == 0) {
                                thread_release(thread);
+                       }
                } else {
                        result = KERN_FAILURE;
                }
@@ -312,7 +348,7 @@ thread_resume(thread_t thread)
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 /*
@@ -325,19 +361,21 @@ thread_depress_abort_from_user(thread_t thread)
 {
        kern_return_t result;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
-       if (thread->active)
+       if (thread->active) {
                result = thread_depress_abort(thread);
-       else
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 
@@ -349,9 +387,9 @@ thread_depress_abort_from_user(thread_t thread)
  */
 static void
 act_abort(
-       thread_t        thread)
+       thread_t        thread)
 {
-       spl_t           s = splsched();
+       spl_t           s = splsched();
 
        thread_lock(thread);
 
@@ -369,44 +407,46 @@ act_abort(
 
 kern_return_t
 thread_abort(
-       thread_t        thread)
+       thread_t        thread)
 {
-       kern_return_t   result = KERN_SUCCESS;
+       kern_return_t   result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
        if (thread->active) {
                act_abort(thread);
                clear_wait(thread, THREAD_INTERRUPTED);
-       }
-       else
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 kern_return_t
 thread_abort_safely(
-       thread_t                thread)
+       thread_t                thread)
 {
-       kern_return_t   result = KERN_SUCCESS;
+       kern_return_t   result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
        if (thread->active) {
-               spl_t           s = splsched();
+               spl_t           s = splsched();
 
                thread_lock(thread);
                if (!thread->at_safe_point ||
-                               clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) {
+                   clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) {
                        if (!(thread->sched_flags & TH_SFLAG_ABORT)) {
                                thread->sched_flags |= TH_SFLAG_ABORTED_MASK;
                                thread_set_apc_ast_locked(thread);
@@ -421,7 +461,7 @@ thread_abort_safely(
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 /*** backward compatibility hacks ***/
@@ -431,41 +471,44 @@ thread_abort_safely(
 
 kern_return_t
 thread_info(
-       thread_t                        thread,
-       thread_flavor_t                 flavor,
-       thread_info_t                   thread_info_out,
-       mach_msg_type_number_t  *thread_info_count)
+       thread_t                        thread,
+       thread_flavor_t                 flavor,
+       thread_info_t                   thread_info_out,
+       mach_msg_type_number_t  *thread_info_count)
 {
-       kern_return_t                   result;
+       kern_return_t                   result;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
-       if (thread->active || thread->inspection)
+       if (thread->active || thread->inspection) {
                result = thread_info_internal(
-                                               thread, flavor, thread_info_out, thread_info_count);
-       else
+                       thread, flavor, thread_info_out, thread_info_count);
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 static inline kern_return_t
 thread_get_state_internal(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,                  /* pointer to OUT array */
-       mach_msg_type_number_t  *state_count,   /*IN/OUT*/
-       boolean_t                               to_user)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,                  /* pointer to OUT array */
+       mach_msg_type_number_t  *state_count,   /*IN/OUT*/
+       boolean_t                               to_user)
 {
-       kern_return_t           result = KERN_SUCCESS;
+       kern_return_t           result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
@@ -478,63 +521,60 @@ thread_get_state_internal(
                        if (thread_stop(thread, FALSE)) {
                                thread_mtx_lock(thread);
                                result = machine_thread_get_state(
-                                                                               thread, flavor, state, state_count);
+                                       thread, flavor, state, state_count);
                                thread_unstop(thread);
-                       }
-                       else {
+                       } else {
                                thread_mtx_lock(thread);
                                result = KERN_ABORTED;
                        }
 
                        thread_release(thread);
-               }
-               else
+               } else {
                        result = machine_thread_get_state(
-                                                                       thread, flavor, state, state_count);
-       }
-       else if (thread->inspection)
-       {
+                               thread, flavor, state, state_count);
+               }
+       } else if (thread->inspection) {
                result = machine_thread_get_state(
-                                                                       thread, flavor, state, state_count);
-       }
-       else
+                       thread, flavor, state, state_count);
+       } else {
                result = KERN_TERMINATED;
+       }
 
        if (to_user && result == KERN_SUCCESS) {
                result = machine_thread_state_convert_to_user(thread, flavor, state,
-                               state_count);
+                   state_count);
        }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 /* No prototype, since thread_act_server.h has the _to_user version if KERNEL_SERVER */
 
 kern_return_t
 thread_get_state(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  *state_count);
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  *state_count);
 
 kern_return_t
 thread_get_state(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,                  /* pointer to OUT array */
-       mach_msg_type_number_t  *state_count)   /*IN/OUT*/
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,                  /* pointer to OUT array */
+       mach_msg_type_number_t  *state_count)   /*IN/OUT*/
 {
        return thread_get_state_internal(thread, flavor, state, state_count, FALSE);
 }
 
 kern_return_t
 thread_get_state_to_user(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,                  /* pointer to OUT array */
-       mach_msg_type_number_t  *state_count)   /*IN/OUT*/
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,                  /* pointer to OUT array */
+       mach_msg_type_number_t  *state_count)   /*IN/OUT*/
 {
        return thread_get_state_internal(thread, flavor, state, state_count, TRUE);
 }
@@ -545,23 +585,24 @@ thread_get_state_to_user(
  */
 static inline kern_return_t
 thread_set_state_internal(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  state_count,
-       boolean_t                               from_user)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  state_count,
+       boolean_t                               from_user)
 {
-       kern_return_t           result = KERN_SUCCESS;
+       kern_return_t           result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
        if (thread->active) {
                if (from_user) {
                        result = machine_thread_state_convert_from_user(thread, flavor,
-                                       state, state_count);
+                           state, state_count);
                        if (result != KERN_SUCCESS) {
                                goto out;
                        }
@@ -574,60 +615,121 @@ thread_set_state_internal(
                        if (thread_stop(thread, TRUE)) {
                                thread_mtx_lock(thread);
                                result = machine_thread_set_state(
-                                                                               thread, flavor, state, state_count);
+                                       thread, flavor, state, state_count);
                                thread_unstop(thread);
-                       }
-                       else {
+                       } else {
                                thread_mtx_lock(thread);
                                result = KERN_ABORTED;
                        }
 
                        thread_release(thread);
-               }
-               else
+               } else {
                        result = machine_thread_set_state(
-                                                                       thread, flavor, state, state_count);
-       }
-       else
+                               thread, flavor, state, state_count);
+               }
+       } else {
                result = KERN_TERMINATED;
+       }
 
-       if ((result == KERN_SUCCESS) && from_user)
+       if ((result == KERN_SUCCESS) && from_user) {
                extmod_statistics_incr_thread_set_state(thread);
+       }
 
 out:
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
-/* No prototype, since thread_act_server.h has the _from_user version if KERNEL_SERVER */ 
+/* No prototype, since thread_act_server.h has the _from_user version if KERNEL_SERVER */
 kern_return_t
 thread_set_state(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  state_count);
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  state_count);
 
 kern_return_t
 thread_set_state(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  state_count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  state_count)
 {
        return thread_set_state_internal(thread, flavor, state, state_count, FALSE);
 }
+
 kern_return_t
 thread_set_state_from_user(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  state_count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  state_count)
 {
        return thread_set_state_internal(thread, flavor, state, state_count, TRUE);
 }
+
+kern_return_t
+thread_convert_thread_state(
+       thread_t                thread,
+       int                     direction,
+       thread_state_flavor_t   flavor,
+       thread_state_t          in_state,          /* pointer to IN array */
+       mach_msg_type_number_t  in_state_count,
+       thread_state_t          out_state,         /* pointer to OUT array */
+       mach_msg_type_number_t  *out_state_count)   /*IN/OUT*/
+{
+       kern_return_t kr;
+       thread_t to_thread = THREAD_NULL;
+       thread_t from_thread = THREAD_NULL;
+       mach_msg_type_number_t state_count = in_state_count;
+
+       if (direction != THREAD_CONVERT_THREAD_STATE_TO_SELF &&
+           direction != THREAD_CONVERT_THREAD_STATE_FROM_SELF) {
+               return KERN_INVALID_ARGUMENT;
+       }
+
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
+
+       if (state_count > *out_state_count) {
+               return KERN_INSUFFICIENT_BUFFER_SIZE;
+       }
+
+       if (direction == THREAD_CONVERT_THREAD_STATE_FROM_SELF) {
+               to_thread = thread;
+               from_thread = current_thread();
+       } else {
+               to_thread = current_thread();
+               from_thread = thread;
+       }
+
+       /* Authenticate and convert thread state to kernel representation */
+       kr = machine_thread_state_convert_from_user(from_thread, flavor,
+           in_state, state_count);
+
+       /* Return early if one of the thread was jop disabled while other wasn't */
+       if (kr != KERN_SUCCESS) {
+               return kr;
+       }
+
+       /* Convert thread state to target thread user representation */
+       kr = machine_thread_state_convert_to_user(to_thread, flavor,
+           in_state, &state_count);
+
+       if (kr == KERN_SUCCESS) {
+               if (state_count <= *out_state_count) {
+                       memcpy(out_state, in_state, state_count * sizeof(uint32_t));
+                       *out_state_count = state_count;
+               } else {
+                       kr = KERN_INSUFFICIENT_BUFFER_SIZE;
+               }
+       }
+
+       return kr;
+}
+
 /*
  * Kernel-internal "thread" interfaces used outside this file:
  */
@@ -637,12 +739,13 @@ thread_set_state_from_user(
  */
 kern_return_t
 thread_state_initialize(
-       thread_t                thread)
+       thread_t                thread)
 {
-       kern_return_t           result = KERN_SUCCESS;
+       kern_return_t           result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
@@ -656,35 +759,34 @@ thread_state_initialize(
                                thread_mtx_lock(thread);
                                result = machine_thread_state_initialize( thread );
                                thread_unstop(thread);
-                       }
-                       else {
+                       } else {
                                thread_mtx_lock(thread);
                                result = KERN_ABORTED;
                        }
 
                        thread_release(thread);
-               }
-               else
+               } else {
                        result = machine_thread_state_initialize( thread );
-       }
-       else
+               }
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
-
 kern_return_t
 thread_dup(
-       thread_t        target)
+       thread_t        target)
 {
-       thread_t                        self = current_thread();
-       kern_return_t           result = KERN_SUCCESS;
+       thread_t                        self = current_thread();
+       kern_return_t           result = KERN_SUCCESS;
 
-       if (target == THREAD_NULL || target == self)
-               return (KERN_INVALID_ARGUMENT);
+       if (target == THREAD_NULL || target == self) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(target);
 
@@ -697,36 +799,37 @@ thread_dup(
                        thread_mtx_lock(target);
                        result = machine_thread_dup(self, target, FALSE);
 
-                       if (self->affinity_set != AFFINITY_SET_NULL)
+                       if (self->affinity_set != AFFINITY_SET_NULL) {
                                thread_affinity_dup(self, target);
+                       }
                        thread_unstop(target);
-               }
-               else {
+               } else {
                        thread_mtx_lock(target);
                        result = KERN_ABORTED;
                }
 
                thread_release(target);
-       }
-       else
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(target);
 
-       return (result);
+       return result;
 }
 
 
 kern_return_t
 thread_dup2(
-       thread_t        source,
-       thread_t        target)
+       thread_t        source,
+       thread_t        target)
 {
-       kern_return_t           result = KERN_SUCCESS;
-       uint32_t                active = 0;
+       kern_return_t           result = KERN_SUCCESS;
+       uint32_t                active = 0;
 
-       if (source == THREAD_NULL || target == THREAD_NULL || target == source)
-               return (KERN_INVALID_ARGUMENT);
+       if (source == THREAD_NULL || target == THREAD_NULL || target == source) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(source);
        active = source->active;
@@ -746,23 +849,23 @@ thread_dup2(
                if (thread_stop(target, TRUE)) {
                        thread_mtx_lock(target);
                        result = machine_thread_dup(source, target, TRUE);
-                       if (source->affinity_set != AFFINITY_SET_NULL)
+                       if (source->affinity_set != AFFINITY_SET_NULL) {
                                thread_affinity_dup(source, target);
+                       }
                        thread_unstop(target);
-               }
-               else {
+               } else {
                        thread_mtx_lock(target);
                        result = KERN_ABORTED;
                }
 
                thread_release(target);
-       }
-       else
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(target);
 
-       return (result);
+       return result;
 }
 
 /*
@@ -773,24 +876,22 @@ thread_dup2(
  */
 kern_return_t
 thread_setstatus(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  tstate,
-       mach_msg_type_number_t  count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  tstate,
+       mach_msg_type_number_t  count)
 {
-
-       return (thread_set_state(thread, flavor, tstate, count));
+       return thread_set_state(thread, flavor, tstate, count);
 }
 
 kern_return_t
 thread_setstatus_from_user(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  tstate,
-       mach_msg_type_number_t  count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  tstate,
+       mach_msg_type_number_t  count)
 {
-
-       return (thread_set_state_from_user(thread, flavor, tstate, count));
+       return thread_set_state_from_user(thread, flavor, tstate, count);
 }
 
 /*
@@ -800,22 +901,22 @@ thread_setstatus_from_user(
  */
 kern_return_t
 thread_getstatus(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  tstate,
-       mach_msg_type_number_t  *count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  tstate,
+       mach_msg_type_number_t  *count)
 {
-       return (thread_get_state(thread, flavor, tstate, count));
+       return thread_get_state(thread, flavor, tstate, count);
 }
 
 kern_return_t
 thread_getstatus_to_user(
-       thread_t                thread,
-       int                                             flavor,
-       thread_state_t                  tstate,
-       mach_msg_type_number_t  *count)
+       thread_t                thread,
+       int                                             flavor,
+       thread_state_t                  tstate,
+       mach_msg_type_number_t  *count)
 {
-       return (thread_get_state_to_user(thread, flavor, tstate, count));
+       return thread_get_state_to_user(thread, flavor, tstate, count);
 }
 
 /*
@@ -824,13 +925,14 @@ thread_getstatus_to_user(
  */
 kern_return_t
 thread_set_tsd_base(
-       thread_t                        thread,
-       mach_vm_offset_t        tsd_base)
+       thread_t                        thread,
+       mach_vm_offset_t        tsd_base)
 {
-       kern_return_t           result = KERN_SUCCESS;
+       kern_return_t           result = KERN_SUCCESS;
 
-       if (thread == THREAD_NULL)
-               return (KERN_INVALID_ARGUMENT);
+       if (thread == THREAD_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        thread_mtx_lock(thread);
 
@@ -844,23 +946,22 @@ thread_set_tsd_base(
                                thread_mtx_lock(thread);
                                result = machine_thread_set_tsd_base(thread, tsd_base);
                                thread_unstop(thread);
-                       }
-                       else {
+                       } else {
                                thread_mtx_lock(thread);
                                result = KERN_ABORTED;
                        }
 
                        thread_release(thread);
-               }
-               else
+               } else {
                        result = machine_thread_set_tsd_base(thread, tsd_base);
-       }
-       else
+               }
+       } else {
                result = KERN_TERMINATED;
+       }
 
        thread_mtx_unlock(thread);
 
-       return (result);
+       return result;
 }
 
 /*
@@ -928,13 +1029,15 @@ thread_suspended(__unused void *parameter, wait_result_t result)
 
        thread_mtx_lock(thread);
 
-       if (result == THREAD_INTERRUPTED)
+       if (result == THREAD_INTERRUPTED) {
                thread->suspend_parked = FALSE;
-       else
+       } else {
                assert(thread->suspend_parked == FALSE);
+       }
 
-       if (thread->suspend_count > 0)
+       if (thread->suspend_count > 0) {
                thread_set_apc_ast(thread);
+       }
 
        thread_mtx_unlock(thread);
 
@@ -975,7 +1078,7 @@ thread_apc_ast(thread_t thread)
        if (thread->suspend_count > 0) {
                thread->suspend_parked = TRUE;
                assert_wait(&thread->suspend_count,
-                               THREAD_ABORTSAFE | THREAD_WAIT_NOREPORT_USER);
+                   THREAD_ABORTSAFE | THREAD_WAIT_NOREPORT_USER);
                thread_mtx_unlock(thread);
 
                thread_block(thread_suspended);
@@ -985,80 +1088,83 @@ thread_apc_ast(thread_t thread)
        thread_mtx_unlock(thread);
 }
 
+
 /* Prototype, see justification above */
 kern_return_t
 act_set_state(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  count);
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  count);
 
 kern_return_t
 act_set_state(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  count)
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  count)
 {
-    if (thread == current_thread())
-           return (KERN_INVALID_ARGUMENT);
+       if (thread == current_thread()) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
-    return (thread_set_state(thread, flavor, state, count));
-    
+       return thread_set_state(thread, flavor, state, count);
 }
 
 kern_return_t
 act_set_state_from_user(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  count)
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  count)
 {
-    if (thread == current_thread())
-           return (KERN_INVALID_ARGUMENT);
+       if (thread == current_thread()) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
-    return (thread_set_state_from_user(thread, flavor, state, count));
-    
+       return thread_set_state_from_user(thread, flavor, state, count);
 }
 
 /* Prototype, see justification above */
 kern_return_t
 act_get_state(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  *count);
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  *count);
 
 kern_return_t
 act_get_state(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  *count)
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  *count)
 {
-    if (thread == current_thread())
-           return (KERN_INVALID_ARGUMENT);
+       if (thread == current_thread()) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
-    return (thread_get_state(thread, flavor, state, count));
+       return thread_get_state(thread, flavor, state, count);
 }
 
 kern_return_t
 act_get_state_to_user(
-       thread_t                                thread,
-       int                                             flavor,
-       thread_state_t                  state,
-       mach_msg_type_number_t  *count)
+       thread_t                                thread,
+       int                                             flavor,
+       thread_state_t                  state,
+       mach_msg_type_number_t  *count)
 {
-    if (thread == current_thread())
-           return (KERN_INVALID_ARGUMENT);
+       if (thread == current_thread()) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
-    return (thread_get_state_to_user(thread, flavor, state, count));
+       return thread_get_state_to_user(thread, flavor, state, count);
 }
 
 static void
 act_set_ast(
-           thread_t thread,
-           ast_t ast)
+       thread_t thread,
+       ast_t ast)
 {
        spl_t s = splsched();
 
@@ -1071,10 +1177,11 @@ act_set_ast(
                thread_lock(thread);
                thread_ast_set(thread, ast);
                processor = thread->last_processor;
-               if ( processor != PROCESSOR_NULL            &&
-                    processor->state == PROCESSOR_RUNNING  &&
-                    processor->active_thread == thread     )
+               if (processor != PROCESSOR_NULL &&
+                   processor->state == PROCESSOR_RUNNING &&
+                   processor->active_thread == thread) {
                        cause_ast_check(processor);
+               }
                thread_unlock(thread);
        }
 
@@ -1091,7 +1198,7 @@ act_set_ast(
  */
 static void
 act_set_ast_async(thread_t  thread,
-                  ast_t     ast)
+    ast_t     ast)
 {
        thread_ast_set(thread, ast);
 
@@ -1104,7 +1211,7 @@ act_set_ast_async(thread_t  thread,
 
 void
 act_set_astbsd(
-       thread_t        thread)
+       thread_t        thread)
 {
        act_set_ast( thread, AST_BSD );
 }
@@ -1112,20 +1219,42 @@ act_set_astbsd(
 void
 act_set_astkevent(thread_t thread, uint16_t bits)
 {
-       atomic_fetch_or(&thread->kevent_ast_bits, bits);
+       os_atomic_or(&thread->kevent_ast_bits, bits, relaxed);
 
        /* kevent AST shouldn't send immediate IPIs */
        act_set_ast_async(thread, AST_KEVENT);
 }
 
+uint16_t
+act_clear_astkevent(thread_t thread, uint16_t bits)
+{
+       /*
+        * avoid the atomic operation if none of the bits is set,
+        * which will be the common case.
+        */
+       uint16_t cur = os_atomic_load(&thread->kevent_ast_bits, relaxed);
+       if (cur & bits) {
+               cur = os_atomic_andnot_orig(&thread->kevent_ast_bits, bits, relaxed);
+       }
+       return cur & bits;
+}
+
+void
+act_set_ast_reset_pcs(thread_t thread)
+{
+       act_set_ast(thread, AST_RESET_PCS);
+}
+
 void
 act_set_kperf(
-       thread_t        thread)
+       thread_t        thread)
 {
        /* safety check */
-       if (thread != current_thread())
-               if( !ml_get_interrupts_enabled() )
+       if (thread != current_thread()) {
+               if (!ml_get_interrupts_enabled()) {
                        panic("unsafe act_set_kperf operation");
+               }
+       }
 
        act_set_ast( thread, AST_KPERF );
 }
@@ -1133,7 +1262,7 @@ act_set_kperf(
 #if CONFIG_MACF
 void
 act_set_astmacf(
-       thread_t        thread)
+       thread_t        thread)
 {
        act_set_ast( thread, AST_MACF);
 }
@@ -1164,4 +1293,3 @@ act_set_io_telemetry_ast(thread_t thread)
 {
        act_set_ast(thread, AST_TELEMETRY_IO);
 }
-