Next: , Previous: Thread Settings, Up: Thread Interface


7.1.5 Thread Execution

— Function: kern_return_t thread_suspend (thread_t target_thread)

Increments the thread's suspend count and prevents the thread from executing any more user level instructions. In this context a user level instruction is either a machine instruction executed in user mode or a system trap instruction including page faults. Thus if a thread is currently executing within a system trap the kernel code may continue to execute until it reaches the system return code or it may suspend within the kernel code. In either case, when the thread is resumed the system trap will return. This could cause unpredictable results if the user did a suspend and then altered the user state of the thread in order to change its direction upon a resume. The call thread_abort is provided to allow the user to abort any system call that is in progress in a predictable way.

The suspend count may become greater than one with the effect that it will take more than one resume call to restart the thread.

The function returns KERN_SUCCESS if the thread has been suspended and KERN_INVALID_ARGUMENT if target_thread is not a thread.

— Function: kern_return_t thread_resume (thread_t target_thread)

Decrements the thread's suspend count. If the count becomes zero the thread is resumed. If it is still positive, the thread is left suspended. The suspend count may not become negative.

The function returns KERN_SUCCESS if the thread has been resumed, KERN_FAILURE if the suspend count is already zero and KERN_INVALID_ARGUMENT if target_thread is not a thread.

— Function: kern_return_t thread_abort (thread_t target_thread)

The function thread_abort aborts the kernel primitives: mach_msg, msg_send, msg_receive and msg_rpc and page-faults, making the call return a code indicating that it was interrupted. The call is interrupted whether or not the thread (or task containing it) is currently suspended. If it is suspended, the thread receives the interrupt when it is resumed.

A thread will retry an aborted page-fault if its state is not modified before it is resumed. msg_send returns SEND_INTERRUPTED; msg_receive returns RCV_INTERRUPTED; msg_rpc returns either SEND_INTERRUPTED or RCV_INTERRUPTED, depending on which half of the RPC was interrupted.

The main reason for this primitive is to allow one thread to cleanly stop another thread in a manner that will allow the future execution of the target thread to be controlled in a predictable way. thread_suspend keeps the target thread from executing any further instructions at the user level, including the return from a system call. thread_get_state/thread_set_state allows the examination or modification of the user state of a target thread. However, if a suspended thread was executing within a system call, it also has associated with it a kernel state. This kernel state can not be modified by thread_set_state with the result that when the thread is resumed the system call may return changing the user state and possibly user memory. thread_abort aborts the kernel call from the target thread's point of view by resetting the kernel state so that the thread will resume execution at the system call return with the return code value set to one of the interrupted codes. The system call itself will either be entirely completed or entirely aborted, depending on the precise moment at which the abort was received. Thus if the thread's user state has been changed by thread_set_state, it will not be modified by any unexpected system call side effects.

For example to simulate a Unix signal, the following sequence of calls may be used:

  1. thread_suspend: Stops the thread.
  2. thread_abort: Interrupts any system call in progress, setting the return value to `interrupted'. Since the thread is stopped, it will not return to user code.
  3. thread_set_state: Alters thread's state to simulate a procedure call to the signal handler
  4. thread_resume: Resumes execution at the signal handler. If the thread's stack has been correctly set up, the thread may return to the interrupted system call. (Of course, the code to push an extra stack frame and change the registers is VERY machine-dependent.)

Calling thread_abort on a non-suspended thread is pretty risky, since it is very difficult to know exactly what system trap, if any, the thread might be executing and whether an interrupt return would cause the thread to do something useful.

The function returns KERN_SUCCESS if the thread received an interrupt and KERN_INVALID_ARGUMENT if target_thread is not a thread.

— Function: kern_return_t thread_get_state (thread_t target_thread, int flavor, thread_state_t old_state, mach_msg_type_number_t *old_stateCnt)

The function thread_get_state returns the execution state (e.g. the machine registers) of target_thread as specified by flavor. The old_state is an array of integers that is provided by the caller and returned filled with the specified information. old_stateCnt is input set to the maximum number of integers in old_state and returned equal to the actual number of integers in old_state.

target_thread may not be mach_thread_self().

The definition of the state structures can be found in machine/thread_status.h.

The function returns KERN_SUCCESS if the state has been returned, KERN_INVALID_ARGUMENT if target_thread is not a thread or is mach_thread_self or flavor is unrecognized for this machine. The function returns MIG_ARRAY_TOO_LARGE if the returned state is too large for old_state. In this case, old_state is filled as much as possible and old_stateCnt is set to the number of elements that would have been returned if there were enough room.

— Function: kern_return_t thread_set_state (thread_t target_thread, int flavor, thread_state_t new_state, mach_msg_type_number_t new_state_count)

The function thread_set_state sets the execution state (e.g. the machine registers) of target_thread as specified by flavor. The new_state is an array of integers. new_state_count is the number of elements in new_state. The entire set of registers is reset. This will do unpredictable things if target_thread is not suspended.

target_thread may not be mach_thread_self.

The definition of the state structures can be found in machine/thread_status.h.

The function returns KERN_SUCCESS if the state has been set and KERN_INVALID_ARGUMENT if target_thread is not a thread or is mach_thread_self or flavor is unrecognized for this machine.