linux中0號任務的建立以及堆疊初始化

2021-07-26 22:56:04 字數 4643 閱讀 5889

開啟linux系統的命令列,敲下「ps -a」命令,就能看到系統中的所有任務:其中有乙個pid號為0任務格外的顯眼。

我們知道linux中的task都是通過fork族函式由父程序創造出來,而這個0號程序卻是個例外,它由人類捏造出來,沒有parent。

linux中所有task都由乙個task_struct結構來代表,一旦task有了task_struct,我們就能夠看得見摸得著;乙個新task的建立過程首先就是為其分配task_struct結構,使它的靈魂有所寄託。

而這個0號程序(在linux中一般採用「任務」來指代乙個程序,這裡「程序」的說法和「任務」乙個意思)的task_struct結構的物件通過靜態全域性變數的方式建立,這個物件例項叫init_task。它隨核心**一起編到核心映象之中,核心映象一旦編譯完成0號程序的task_struct例項init_task也隨之生成,即在核心中已經有存在。這個例項init_task的定義在init/init_task.c目錄下:

struct task_struct init_task = init_task(init_task);
這個init_task就是0號程序task_struct結構物件例項,init_task中的各個成員通過init_task(init_task)這個巨集來初始化,我們列舉出一些我們關注的初始化成員值,沒有列出的用省略號代替:

#define init_task(tsk)    \  

可以看出init_task的成員就是通過上面的巨集展開後被一一賦予了給定的值:

1. 核心堆疊

乙個任務核心堆疊指標由task_struct.stack來指定,init_task的stack指標也是靜態分配的:

.stack        = &init_thread_info
2. 任務標誌

init_task是乙個核心任務,其標誌也初始設定為pf_kthread。

.flags        = pf_kthread
3. 排程策略

init_task雖然是核心中的第乙個任務,但它並不高特殊,不論是排程策略(sched_normal)還是優先順序(120),都是最普通的:

.prio        = max_prio-20,                    \  

.static_prio    = max_prio-20,                    \  

.normal_prio    = max_prio-20,                    \  

.policy        = sched_normal,                    \

4. init_task的父輩

init_task是系統中的第乙個任務,所以它就是系統中的始祖:

.real_parent    = &tsk,                        \  

.parent        = &tsk,                        \

.comm        = init_task_comm  

一旦核心編譯完成生成映象,這個init_task就已經在其中占有自己的一席之地,核心已啟動它便存在!

從上面我們已經看到0號任務的堆疊,準確的叫核心堆疊,已經初始化為init_thread_info:

.stack        = &init_thread_info
#define init_thread_info    (init_thread_union.thread_info)
看到沒?這個init_thread_info只是乙個幌子,實際上stack指向的是 .stack = &init_thread_union.thread_info;而這個init_thread_union是乙個與架構無關的全域性union,定義在init/init_task.c中:

union thread_union init_thread_union __init_task_data =  

;

這個init_thread_union又是乙個巨集,我們再將他展開看看.....等等,思路似乎有些亂。我們先縷一縷:

1) 前面已經確定了0號任務的核心堆疊指標init_task.stack指向的是&init_thread_union.thread_info;

2) 乙個task的核心堆疊指標指向一片連續的記憶體區域(即核心堆疊使用區域),這片堆疊區域的大小隨架構的不同其size也有所差異,一般通過巨集thread_size來表示。

3) 綜合1)和2)可以知道0號程序核心堆疊指標與&init_thread_union.thread_info相等,即這片核心堆疊區域的底端實際放的就是init_thread_union.thread_info。而實際在一般情況下乙個task的核心堆疊底部確實放著乙個thread_info結構!

4) 核心堆疊的作用就是用來儲存資料用的,而0號任務的這塊堆疊區域卻是靜態分配的;那這塊區域是在**分配的呢??

好,我們就再來深挖一下0號任務堆疊以及init_thread_union.thread_info的真面目。

既然0號task的堆疊指標指向init_thread_union.thread_info的位址,那就撥開雲霧見天日,研究一下我們深挖的重點:0號任務init_task.stack指標指向的大小thread_size的區域究竟在**分配。

首先,init_task.stack是與init_thread_union這個變數關聯,我們先來關注它。

union thread_union init_thread_union __init_task_data =  

;

這個thred_union聯合體定義如下:

union thread_union ;
即這個靜態全域性變數 init_thread_union實際上已經靜態分配了thread_size的大小,由於它是乙個聯合體,所以我們引用init_thread_union.thread_info就可以夠著這個thread_size的記憶體區域,我們的init_task.stack也就在這裡著落。

一般情況下全域性變數都放在核心映象的資料段,但是這裡可以的init_thread_union通過__init_task_data屬性使其init_thread_union最終鏈結到映象中的__init_task_data這個段中,即init_task的核心堆疊thread_size大小的區域最終放在這個__init_task_data屬性段中。

既然我們知道0號任務核心堆疊是在__init_task_data屬性段中,那我們就來研究一下:

#define __init_task_data __attribute__((__section__(".data..init_task")))
即init_thread_union最終是鏈結到.data..init_task這個資料段中,即init_task的堆疊指向.data..init_task這個位置。

而.data..init_task這個段的位置是在vmlinux.lds.s檔案中決定的,不同的架構其位置不一樣:

在arm架構中如下所示:

.data : at(__data_loc)         /* r3指向__mmap_switched_data + 4*sizeof(long) */  

cmp    r4, r5                @ copy data segment if needed  

......  

/* 將 init_thread_union+thread_start_sp 裝入sp暫存器 */  

arm(    ldmia    r3, )    

........  

b    start_kernel  

.....................  

__mmap_switched_data:  

.long    __data_loc            @ r4  

.long    _sdata                @ r5  

.long    __bss_start            @ r6  

.long    _end                @ r7  

/* 執行ldmia  r3!, 後r3指向這裡 */  

.long    processor_id            @ r4   

.long    __machine_arch_type        @ r5  

.long    __atags_pointer            @ r6  

#ifdef config_cpu_cp15  

.long    cr_alignment            @ r7  

#else  

.long    0                @ r7  

#endif  

/* 這裡存放值 init_thread_union+thread_start_sp */  

.long    init_thread_union + thread_start_sp @ sp

Linux中的0號程序和1號程序

系統允許乙個程序建立新程序,新程序即為子程序,子程序還可以建立新的子程序,形成程序樹結構模型。整個linux系統的所有程序也是乙個樹形結 構。樹根是系統自動構造的,即在核心態下執行的0號程序,它是所有程序的祖先。由0號程序建立1號程序 核心態 1號負責執行核心的部分初始化工作及進 行系統配置,並建立...

Linux中的延時任務以及定時任務

root localhost at 23 37 設定任務執行時間 at rm fr mnt 任務執行動作 at ctrl d 用ctrl d發起任務 root localhost at now 1min 延時1分鐘 at rm fr mnt at 命令 注釋at l 檢視任務列表 at c 檢視任務...

Linux中建立定時任務

首先來看一下 crontab的常用命令 crontab e user 使用預設的文字編輯器開啟指定使用者的任務列表檔案,user是要開啟的使用者的檔案 crontab l user 列出當前執行的任務,相當於檢視任務列表檔案的內容 我們一般的用法就是 第一步 crontab e 打卡任務列表 第二步...