進(jìn)程是多程序設(shè)計(jì)的操作系統(tǒng)的基本概念,通常把程序運(yùn)行的實(shí)體叫做進(jìn)程,Linux就是一個(gè)多用戶(hù)多進(jìn)程的操作系統(tǒng),常把進(jìn)程稱(chēng)為線程或任務(wù)。
在linux操作系統(tǒng)中,為什么進(jìn)程也叫線程,線程也是進(jìn)程?閱讀完下面的進(jìn)程創(chuàng)建和銷(xiāo)毀就自然而然理解了。
1、創(chuàng)建進(jìn)程的入口函數(shù)
第一次遇見(jiàn)創(chuàng)建進(jìn)程是在Linux啟動(dòng)流程中,reset_init函數(shù)調(diào)用kernel_thread函數(shù)創(chuàng)建了2個(gè)內(nèi)核進(jìn)程:kernel_init和kthreadd。
1.1 kernel_thread的原型
定義在kernel/fork.c文件內(nèi),是調(diào)用_do_fork實(shí)現(xiàn)的,源碼如下:
我們知道kthreadd進(jìn)程負(fù)責(zé)創(chuàng)建所有內(nèi)核線程,那么它是如何創(chuàng)建的呢?循著鏈表kthread_create_list,可以找到鏈表是__kthread_create_on_node函數(shù)內(nèi)插入的,進(jìn)而我們引出了kthread_create、kthread_run等函數(shù)。
1.2 kthread_create的原型
定義在include/linux/kthread.h文件內(nèi),是個(gè)宏定義。
kthread_create_on_node函數(shù)定義在kernel/kthread.c文件內(nèi),內(nèi)部是調(diào)用__kthread_create_on_node實(shí)現(xiàn)。
當(dāng)看到EXPORT_SYMBOL標(biāo)識(shí)時(shí),可以知道kthread_create_on_node是對(duì)全部?jī)?nèi)核代碼公開(kāi)的,內(nèi)核和驅(qū)動(dòng)都可以調(diào)用,調(diào)用時(shí)只需extern該函數(shù)聲明或包含頭文件即可,實(shí)際操作中,更多的是使用kthread_create宏。 我們繼續(xù)看kthread_create_on_node的主要實(shí)現(xiàn)函數(shù)是__kthread_create_on_node,line 299顯示task的數(shù)據(jù)結(jié)構(gòu)體是struct task_sttruct,?便是進(jìn)程描述符。
1.3 kthread_run的原型
kthread_run是定義在include/linux/kthread.h頭文件的宏,可以看出內(nèi)部也是調(diào)用kthread_create函數(shù)實(shí)現(xiàn)的。
1.4 對(duì)比三個(gè)內(nèi)核創(chuàng)建進(jìn)程函數(shù)
kernel_thread直接調(diào)用_do_fork創(chuàng)建進(jìn)程,但不對(duì)外開(kāi)放。
kthread_create創(chuàng)建了進(jìn)程由kthread進(jìn)程具體完成創(chuàng)建,間接調(diào)用_do_fork實(shí)現(xiàn),但它對(duì)所有內(nèi)核開(kāi)放。
kthread_run調(diào)用kthread_create創(chuàng)建了進(jìn)程,并立即喚醒去執(zhí)行。
2、用戶(hù)進(jìn)程該如何創(chuàng)建
在Linux應(yīng)用編程的時(shí)候我們常用三個(gè)函數(shù),fork、vfork和pthead__create,區(qū)別與內(nèi)核進(jìn)程的創(chuàng)建,用戶(hù)態(tài)不能直接調(diào)用內(nèi)核態(tài)的進(jìn)程創(chuàng)建函數(shù),必須經(jīng)由系統(tǒng)調(diào)用system call機(jī)制(system call不是本文重點(diǎn),后面單獨(dú)一篇詳述)。
2.1 fork函數(shù)
fork函數(shù)調(diào)用_do_fork函數(shù)創(chuàng)建進(jìn)程。
2.2 vfork函數(shù)
vfork函數(shù)調(diào)用_do_fork函數(shù)創(chuàng)建進(jìn)程。不同于fork函數(shù),args內(nèi)多了flags的賦值。
2.3 clone函數(shù)
clone函數(shù)也是調(diào)用_do_fork函數(shù)創(chuàng)建進(jìn)程。不同于fork、vfork函數(shù),args內(nèi)多了更多參數(shù)的賦值。
2.4?小節(jié)
創(chuàng)建內(nèi)核進(jìn)程的接口有kernel_thread、kthread_create和kthread_run。 創(chuàng)建用戶(hù)進(jìn)程的接口有fork、vfork和pthread__create。 這六個(gè)接口最終都是調(diào)用_do_fork實(shí)現(xiàn)的。
3、創(chuàng)建進(jìn)程的具體實(shí)現(xiàn)之_do_fork
用戶(hù)態(tài)和內(nèi)核態(tài)創(chuàng)建進(jìn)程最終都是直接或間接調(diào)用_do_fork實(shí)現(xiàn)的。可見(jiàn)_do_fork函數(shù)的重要性,內(nèi)部實(shí)現(xiàn)是調(diào)用copy_process來(lái)創(chuàng)建進(jìn)程描述符以及子進(jìn)程執(zhí)行所需要的所有其他數(shù)據(jù)結(jié)構(gòu)。
4、進(jìn)程描述符之struct task_struct
調(diào)用copy_process來(lái)創(chuàng)建進(jìn)程描述符,描述符的數(shù)據(jù)結(jié)構(gòu)是struct task_struct,定義在include/linux/sched.h文件內(nèi)。 我們可以簡(jiǎn)單一撇結(jié)構(gòu)體內(nèi)的成員變量(有大量刪減),單獨(dú)講每個(gè)成員變量沒(méi)有意義,后續(xù)我們?cè)趯?shí)際內(nèi)核功能中理解它們。
5、進(jìn)程銷(xiāo)毀
當(dāng)一個(gè)進(jìn)程運(yùn)行結(jié)束或者因?yàn)楫惓6K止退出時(shí),該如何操作呢?在用戶(hù)態(tài)常用exit函數(shù)來(lái)終止,在內(nèi)核態(tài)直接調(diào)用do_exit()。 最終都會(huì)調(diào)用內(nèi)核函數(shù)do_exit(),?該函數(shù)可以理解為進(jìn)程創(chuàng)建的逆過(guò)程,即把進(jìn)程創(chuàng)建的資源一一釋放,并調(diào)整與其父子進(jìn)程的關(guān)系。具體實(shí)現(xiàn)過(guò)程不再分析,直接看源碼。
6、總結(jié)與下一篇計(jì)劃
本篇主要講解內(nèi)核態(tài)和用戶(hù)態(tài)創(chuàng)建和銷(xiāo)毀進(jìn)程的接口函數(shù),并側(cè)重介紹了創(chuàng)建過(guò)程函數(shù)_do_fork。 本篇中講到用戶(hù)態(tài)調(diào)用內(nèi)核態(tài)的函數(shù)需要用到系統(tǒng)調(diào)用,下一篇著重講解系統(tǒng)調(diào)用的過(guò)程。
編輯:黃飛
?
評(píng)論