About the author

E-moss, a programmer who reads and wanks dogs, works on iOS development. Major share and write technical articles, not on a regular basis to share reading notes, can also access to "the best" Git address: https://github.com/knowtheroot/KnowTheRoot_iOS, welcome to ask questions and discussion.Copy the code

Git address: github.com/knowtheroot…

  • Threads: Like all modern operating systems, the Mach kernel schedules threads.
  • Tasks: Mach uses a more lightweight concept than processes: tasks.

The most basic unit is threads, where a task contains one or more threads.

1. Thread

1. What are threads

Definition of thread

Threads define the smallest execution unit in a match.

Meaning of thread

Threads represent the underlying machine register state and various scheduling statistics.

Thread design

Threads are designed to provide much of the information needed for scheduling while maintaining as little overhead as possible.

2. Thread implementation

Here’s an example of simplified code:

Struct thread {/* Queue_chain_t links */ queue_chain_t links; /* Run queue/wait queue link */ wait_queue_t wait_queue; /* Wait queue */... . /* Update/data used in thread_invoke */ vm_offset_t kernel_stack; /* Current kernel stack */ vm_offset_t reserved_stack; /* Reserved kernel stack */... . /* * Thread status bit */#define TH_WAIT 0x01 /* Wait in queue */
    #define TH_SUSP 0x02 /* Stop */
    #define TH_RUN 0x04 /* Running or in a run queue */
    #define TH_UNINT 0x08 /* In uninterruptible wait */
    #define TH_TERMINATE 0x10 /* Run at the same time */
    #define TH_TERMINATE2 0x20 /* Add to termination queue */
    #define TH_IDLE 0x80 /* Idle thread */. . /* sched_mode_t sched_mode; /* sched_mode_t saved_mode; /* Mode saved when forced mode is degraded */... . /* Scheduling related status bits */ integer_t sched_pri; /* Current scheduling priority */ integer_t priority; /* Basic priority */ integer_t importance; /* Task-related importance */... . /* Timer_data_t user_timer; /* User timer */... . }Copy the code

Thread template thread_template

As you can see, the data structure for threads is very large, so most thread creation is copied from a common template that populates the data structure with default values. This template is called thread_template. During kernel boot, the thread_bootstrap() method is called to fill in the template. The thread_create_internal() function allocates a new thread data structure. The Mach API’s thread_create() is implemented through thread_create_internal().

Thread container

Mach defines tasks as containers for threads. Resources are handled at the task level, and threads can only access resources and memory allocated in the task containing the thread through the port.

Ii. Task

1. Definition of tasks

A task is a container object. Virtual memory space and other resources are managed through this container object. Resources are further abstracted as ports. Therefore, sharing resources effectively allows access to corresponding ports.

Each BSD process (that is, an OS X process) has an underlying Mach task object associated with it.

Compared to threads, a task is a relatively lightweight data structure:

Struct task {/* synchronize information */ unit_32_t ref_count; /* Reference count */ boolean_t active; /* Halting */ Boolean_t HALTING; /* The task was stopped */... . /* miscellaneous */ vm_map_t map; /* Address space mapping */... . /* Threads in a task */ queue_head_t threads; /* use FIFO queue to save threads */ int thread_count; /* Number of threads in the thread queue */ unit32_t active_thread_count; /* Number of active threads */ integer_t priority; /* Thread base priority */ integer_t max_priority; /* The highest priority of the thread */... . // Each task has its own private port namespace struck ipc_space *itk_space; . .#ifdef MACH_BSDvoid *bsd_info; // Points to the BSD process object#endif
}
Copy the code

2. The purpose of the task

Missions are inanimate in and of themselves. The purpose of a task is to be a container for one or more threads. The threads in the task are maintained in the Threads member, which is a queue containing thread_count threads.

3. Task operations

Most task-specific operations are actually traversing all threads in a given task and performing corresponding thread operations on those threads.

4. The book

define

Ledgers are the mechanism required for quota accounting and setting limits for Mach tasks. Resources (typically CPU and memory resources) can be moved between ledgers.

Task – and thread-related apis

1. Obtain the current task and thread

At all times, the kernel must be able to get a handle to the current task and the current thread. The kernel passes:

  • current_task()
  • current_thread()

Two functions to do that.

2. Internal implementation of the function

The above two functions are macros called to the “fast” version of the function. Both:

  • Call current_task_fast current_task () ()
  • Call current_thread_fast current_thread () ()

4. Task-related apis

Mach provides a complete set of apis for manipulating tasks. Here are a few interfaces:

Mach task-related apis use
mach_task_self() Gets the task port with the name of the send permission
task_create(task_t target_task, ledger_array_t ledgers, mach_msg_type_number_t boolean_t task_t *child_task) Create a child_task with target_task as the parent task.

Thread-related apis

Similar to task-related apis, Mach also provides a rich thread management API. Most of these apis have similar functionality to the task API. In fact, a typical implementation of a task API is to iterate through a list of threads in a task and then perform an action on each thread. Most of these calls are implemented through Mach messages.

Note: Phtread refers to a POSLX system call.

1. Kernel proprietary threading API

The Mach kernel provides a set of thread-controlled functions that can only be called in kernel-state and are not expanded here.

2. Create a thread

Let’s pay particular attention to the thread-creation API. This part of the interface is defined in < Mach /ARCH/task.h> :

The Mach thread API use
thread_create(task_t parent, thread_act_t *child_act) Create a thread in the parent task and return the result in child_act
thread_create_running(task_t parent, thread_state_flavor_t flavor, thread_state_t new_state, mach_msg_type_number_t nsCnt, thread_act_t *child_act) Create a thread in the parent task whose initial state is new_state and thread_state_t is machine architecture-dependent

Note that the first parameter is task_t, which represents the task that created the thread. From a Mach perspective, threads can be created in any task, as long as the user has the port corresponding to the task.

When pthread_create() is called, the underlying APi calls the thread_create() method instead.

Note:

Creating a thread is not difficult, but getting a thread to do something meaningful is not. This will be discussed later.