iOS底層系統:Mach調度原理之調度原語

關於做者

E-moss,程序員,愛好閱讀和擼狗,主要從事iOS開發工做,公衆號:知本集。  
主要分享和編寫技術方面文章,不按期分享讀書筆記,亦可訪問「知本集」Git地址:https://github.com/knowtheroot/KnowTheRoot_iOS,歡迎提出問題和討論。
複製代碼

Git地址:github.com/knowtheroot…git

  • 線程:和全部的現代操做系統同樣,Mach內核調度的對象是線程。
  • 任務:Mach中使用一個比進程更輕量級的概念:任務(task)。

最基本的單位是線程,一個任務包含一個或多個線程。程序員

1、線程(thread)

1.什麼是線程

線程的定義

線程(thread)定義了match中最小的執行單元。github

線程的含義

線程表示的是底層的機器寄存器狀態以及各類調度統計數據bootstrap

線程的設計

線程從設計上提供了調度所須要的大量信息,同時儘量地維持最小開銷。bash

2.線程的實現

這裏以簡化的代碼爲例子:數據結構

struct thread {
    /* 頻繁讀,但不多修改的字段 */
    queue_chain_t links;        /* 運行隊列/等待隊列的鏈表鏈接 */
    wait_queue_t wait_queue;        /* 所在的等待隊列 */
    
    ...
    ...
    
    /* thread_invoke中更新/使用的數據 */
    vm_offset_t kernel_stack;        /* 當前的內核棧 */
    vm_offset_t reserved_stack;      /* 預留的內核棧 */
    
    ...
    ...
    
    /*
     * 線程狀態位
    */
    #define TH_WAIT 0x01 /* 在隊列中等待 */
    #define TH_SUSP 0x02 /* 中止,或請求中止 */
    #define TH_RUN 0x04 /* 正在運行或在運行隊列中 */
    #define TH_UNINT 0x08 /* 在不可中斷的等待 */
    #define TH_TERMINATE 0x10 /* 終止時同時運行 */
    #define TH_TERMINATE2 0x20 /* 添加到終止隊列 */
    #define TH_IDLE 0x80 /* 空閒線程 */
    
    ...
    ...
    
    /* 調度信息 */
    sched_mode_t sched_mode;     /* 調度模式 */
    sched_mode_t saved_mode;     /* 在被迫模式降級時保存的模式 */
    
    ...
    ...
    
    /* 調度相關的狀態位 */
    integer_t sched_pri;     /* 當前調度的優先級 */
    integer_t priority;      /* 基礎優先級 */
    integer_t importance ;   /* 任務相關的重要性 */
    
    ...
    ...
    
    /* 定時相關的數據結構 */
    timer_data_t user_timer;     /* 用戶定時器 */
    
    ...
    ...
}
複製代碼

線程模板thread_template

能夠發現,thread的數據結構是很是巨大的,所以大部分建立線程的時候都是從一個通用的模板複製而來,這個模板使用默認值填充這個數據結構。這個模板名爲thread_template。
內核引導的過程當中,調用thread_bootstrap()方法負責填充這個模板。
thread_create_internal()函數會分配新的線程數據結構。
Mach API的thread_create() 就是經過thread_create_internal()實現的架構

線程的容器

Mach將任務定義爲線程的容器
資源是在任務這個層次處理的,線程只能經過端口訪問包含這個線程的任務中分配的資源和內存函數

2、任務(task)

1.任務的定義

任務(task)是一種容器對象。虛擬內存空間和其餘資源都是經過這個容器對象管理的。
資源被進一步抽象爲端口。
所以資源的共享實際上至關於容許對對應端口進行訪問。spa

每個BSD進程(也就是OS X進程)都在底層關聯了一個Mach任務對象。操作系統

相對於線程,任務是一個比較輕量級的數據結構:

struct task {
    /* 同步相關的信息 */
    unit_32_t ref_count;     /* 引用計數 */
    boolean_t active;        /* 任務尚未終止 */
    boolean_t halting;       /* 任務被中止 */
    
    ...
    ...
    
    /* 雜項 */
    vm_map_t map;       /* 地址空間映射 */
    
    ...
    ...
    
    /* 任務中的線程 */
    queue_head_t threads;            /* 用FIFO隊列保存線程 */
    int thread_count;                /* 線程隊列中的線程數 */
    unit32_t active_thread_count;    /* 活動的線程數 */
    
    integer_t priority;      /* 線程基礎優先級 */
    integer_t max_priority;  /* 線程的最高優先級 */
    
    ...
    ...
    
    //每一個任務都有本身私有的端口名稱空間
    struck ipc_space *itk_space;
    
    ...
    ...
    
    #ifdef MACH_BSD
        void *bsd_info;     //指向BSD進程對象
    #endif
}
複製代碼

2.任務存在的目的

就自己而言,任務是沒有生命的。任務存在的目的就是要成爲一個或多個線程的容器
任務中的線程都在threads成員中維護,這是一個包含thread_count個線程的隊列。

3.任務的操做

大部分針對任務的操做實際上就是遍歷給定任務中的全部線程,並對這些線程進行對應的線程操做

4.帳本

定義

帳本(ledger)是Mach任務的配額記帳和設置限制所須要的機制。
資源(通常指CPU資源和內存資源)能夠在帳本間轉移。

3、任務和線程相關的API

1.獲取當前的任務和線程

在任什麼時候刻,內核都必須可以得到當前任務和當前線程的句柄。
內核分別經過:

  • current_task()
  • current_thread()

兩個函數來完成。

2.函數內部實現

以上兩個函數都是對「fast」版本的函數調用的宏。既:

  • current_task()調用current_task_fast()
  • current_thread()調用current_thread_fast()

4、任務相關的API

Mach提供了完整的一套用於操做任務的API。
這裏列舉幾個接口:

Mach任務相關API 用途
mach_task_self() 獲取任務端口,帶有發送權限的名稱
task_create(task_t target_task, ledger_array_t ledgers, mach_msg_type_number_t boolean_t task_t *child_task) 以target_task爲父任務建立一個child_task。

5、線程相關的API

相似任務相關的API,Mach還提供了豐富的線程管理API。這些API大部分都和任務API的功能相似。
實際上,任務API一般的實現方法就是遍歷任務中的線程列表,而後對每一個線程執行對應的操做
這些調用大部分都是經過Mach消息實現的。

注意:phtread中的指POSLX的系統調用。

1.內核私有的線程API

Mach內核提供了一組線程控制的函數,這些函數只能內核態中調用,這裏暫時不作展開。

2.線程建立

咱們特別關注一下線程建立的API。
這部分接口定義在<mach/ARCH/task.h>中:

Mach線程API 用途
thread_create(task_t parent, thread_act_t *child_act) 在parent任務中建立一個線程,將結果返回在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) 在parent任務中建立一個線程,其初始狀態爲new_state,thread_state_t與機器架構有關

注意第一個參數是task_t,這個參數表示建立線程的任務。
從Mach的角度看,線程能夠建立在任何任務中,只要用戶具備任務對應的端口便可。

當調用pthread_create()的時候,底層轉而會調用Mach的APi調用thread_create()方法。

注意:

建立一個線程並不困難,可是要讓線程作有意義的事情則不是那麼容易了。這一內容將在後面討論。

相關文章
相關標籤/搜索