午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

Linux2.4內(nèi)核說明文檔(進(jìn)程與中斷管理篇)

 guitarhua 2011-12-31
Linux2.4內(nèi)核說明文檔(進(jìn)程與中斷管理篇)        作者:wantin6  時(shí)間:2006-08-08 23:34
[list=]

本文檔是《Linux2.4 內(nèi)核說明文檔》中的第二部分。以下是整個(gè)文檔大致目錄:

1,啟動(dòng) ([url=http://bbs./forum/viewtopic.php?t=557946]http://bbs./forum/viewtopic.php?t=557946[/url] )

2,進(jìn)程和中斷管理

3,虛擬文件系統(tǒng)

4,Linux 頁緩沖

5,IPC機(jī)制



本篇文檔的目錄為:

2.1.        Tack結(jié)構(gòu)和進(jìn)程表       

2.2.        創(chuàng)建和中止任務(wù)與內(nèi)核線程       

2.3.        調(diào)度程序       

2.4.        Linux執(zhí)行鏈表       

2.5.        等待隊(duì)列       

2.6.        內(nèi)核時(shí)鐘       

2.7.        Bottom Halves       

2.8.        任務(wù)隊(duì)列       

2.9.        I386體系中系統(tǒng)調(diào)用實(shí)現(xiàn)       

2.10.        原子操作       

2.11.        旋轉(zhuǎn)鎖、讀寫旋轉(zhuǎn)鎖和Big-Reader旋轉(zhuǎn)鎖

2.12.        信號(hào)燈和讀寫信號(hào)燈       

2.13.        裝載模塊的內(nèi)核支持



一下是正文:

2.        進(jìn)程和中斷管理



2.1.        Tack結(jié)構(gòu)和進(jìn)程表

  linux下的每個(gè)進(jìn)程都是動(dòng)態(tài)分配一個(gè)task_struct結(jié)構(gòu),整個(gè)系統(tǒng)可以創(chuàng)建的最大進(jìn)程數(shù)僅由當(dāng)前可用物理內(nèi)存總數(shù)限制,并且等于(見kernel/fork.c:fork_init()函數(shù)):

  

   /*

    * The default maximum number of threads is set to a safe

    * value: the thread structures can take up at most half

    * of memory.

    */

    max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 2;

   

    這個(gè)式子在IA32體系結(jié)構(gòu)上主要意味著最大數(shù)為物理內(nèi)存頁數(shù)/4,例如:在一個(gè)512M內(nèi)存機(jī)器上你可以創(chuàng)建32K線程。這對(duì)于舊版本(2.2或者更老)內(nèi)核的4K限制是一個(gè)可觀的改進(jìn),而且這可以在運(yùn)行時(shí)使用系統(tǒng)調(diào)用sysctl(2)修改KERN_MAX_THREADS,或者簡(jiǎn)單使用procfs系統(tǒng)接口來調(diào)整。



# cat /proc/sys/kernel/threads.max

32764

# echo 100000 >; /proc/sys/kernel/threads.max

# cat /proc/sys/kernel/threads.max

100000

# gdb .q vmlinux /proc/kcore

Core was generated by `BOOT_IMAGE=240ac18 ro root=306 video=matrox:vesa:0x118'.

#0 0x0 in ?? ()

(gdb) p max_threads

$1 = 100000



  Linux系統(tǒng)上進(jìn)程的關(guān)聯(lián)表現(xiàn)為一個(gè)以下兩個(gè)方式鏈接的task_struct結(jié)構(gòu)的集合:

1)        以pid為鍵值的hash表。

2)        通過p->;next_task和p->;prev_task指針連接的雙向鏈表。

這個(gè)hash表名為pidhash,并在include/linux/sched.h中定義:



/* PID hashing. (shouldnt this be dynamic?) */

#define PIDHASH_SZ (4096 >;>; 2)

extern struct task_struct *pidhash[PIDHASH_SZ];

#define pid_hashfn(x) ((((x) >;>; ^ (x)) & (PIDHASH_SZ . 1))



   所有的任務(wù)以他們的pid為鍵值存放到hash表中,并假定均勻地從(0 to PID_MAX-1)分布。這個(gè)hash表用來通過指定的pid快速的找到task結(jié)構(gòu),搜索函數(shù)find_task_pid()定義在include/linux/sched.h中:



static inline struct task_struct *find_task_by_pid(int pid)

{

struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];

for(p = *htable; p && p.>;pid != pid; p = p.>;pidhash_next)

;

return p;

}



  在每個(gè)hash鏈上的所有任務(wù)都通過p->;pidhash_next和p->;pidhash_pprev連接起來,這在hash_pid函數(shù)和unhash_pid函數(shù)將指定進(jìn)程插入hash表或者移出hash表時(shí)使用。所有的操作都受到tasklist_lock寫同步鎖保護(hù)。

而雙向鏈表則為系統(tǒng)遍歷所有的任務(wù)提供了方便,這個(gè)操作由定義在include/linux/sched.h中的for_each_tack()宏來實(shí)現(xiàn)。



#define for_each_task(p) \

for (p = &init_task ; (p = p.>;next_task) != &init_task ; )



for_each_task()函數(shù)的使用者必須使用tasklist_lock讀同步鎖。注意for_each_task()函數(shù)采用init_task標(biāo)識(shí)鏈表的起點(diǎn),這樣才是安全的,因?yàn)榭杖蝿?wù)(pid = 0) 是不在鏈表里的。進(jìn)程hash表和進(jìn)程鏈表的修改操作,特別是fork函數(shù),exit函數(shù)和ptrace函數(shù),必須調(diào)用tasklist_lock寫同步鎖。更有趣的是,所有的寫操作還必須屏蔽當(dāng)前CPU的中斷,這個(gè)原因是顯而易見的:send_sigio函數(shù)遍歷了進(jìn)程表,這樣需要調(diào)用tasklist_lock讀同步鎖,并且該函數(shù)是kill_fasync函數(shù)在中斷環(huán)境下調(diào)用的。

現(xiàn)在我們已經(jīng)知道task_struct結(jié)構(gòu)是怎樣鏈接到一起的,現(xiàn)在讓我們分析一下task_struct結(jié)構(gòu)的成員。這些成員是UNIX系統(tǒng)的proc結(jié)構(gòu)和user結(jié)構(gòu)松散組合到一起的。

其他UNIX版本總是將進(jìn)程狀態(tài)信息作為單獨(dú)一部分常駐內(nèi)存,其他部分則作為進(jìn)程運(yùn)行時(shí)所需信息,如此簡(jiǎn)陋的設(shè)計(jì)僅僅因?yàn)閮?nèi)存時(shí)非常寶貴的資源。現(xiàn)代操作系統(tǒng)(如Linux或者FreeBSD)并不做如此區(qū)分,而是在內(nèi)核常駐內(nèi)存的數(shù)據(jù)結(jié)構(gòu)中維護(hù)進(jìn)程狀態(tài)。

include/linux/sched.h中定義了task_struct結(jié)構(gòu),并且通常大寫為1680字節(jié),狀態(tài)宏也定義同一個(gè)頭文件中。



volatile long state; /* .1 unrunnable, 0 runnable, >;0 stopped */

#define TASK_RUNNING 0

#define TASK_INTERRUPTIBLE 1

#define TASK_UNINTERRUPTIBLE 2

#define TASK_ZOMBIE 4

#define TASK_STOPPED 8

#define TASK_EXCLUSIVE 32



為什么TASK_EXCLUSIVE宏定義為32而不是16呢?這是由于16被TASK_SWAPPING使用了,并且后來在移出TASK_SWAPPING時(shí)沒有把TASK_EXCLUSIVE的值上調(diào)。

可變量p->;state的定義意味著它自身可以被中斷處理者異步修改。

1)        TASK_RUNNING:含義是假定任務(wù)已經(jīng)處于運(yùn)行隊(duì)列中。至于不是已經(jīng)處于運(yùn)行隊(duì)列的原因是由于將一個(gè)任務(wù)標(biāo)識(shí)為TASK_RUNNING和將該任務(wù)移動(dòng)到運(yùn)行隊(duì)列不是一個(gè)原子操作。從運(yùn)行隊(duì)列角度考慮,操作時(shí)需要保持runqueue_lock讀同步鎖。如果這樣操作,你將發(fā)現(xiàn)在運(yùn)行隊(duì)列的每個(gè)任務(wù)都處于TASK_RUNNING狀態(tài)。然后,反過來卻不一定。同樣地,驅(qū)動(dòng)程序可以標(biāo)識(shí)他們自身狀態(tài)為TASK_INTERRUPTIBLE,然后調(diào)用schedule()函數(shù),這個(gè)函數(shù)將從運(yùn)行隊(duì)列移出它自己(除非當(dāng)時(shí)有一個(gè)導(dǎo)致它滯留在運(yùn)行隊(duì)列的未處理信號(hào))。

2)        TASK_INTERRUPTIBLE:含義是任務(wù)處于休眠狀態(tài)但可以通過一個(gè)信號(hào)或者休眠中止時(shí)鐘喚醒。

3)        TASK_UNINTERRUPTIBLE:含義類似于TASK_INTERRUPTIBL,但任務(wù)不能被喚醒。

4)        TASK_ZOMBIE:含義是任務(wù)已經(jīng)被中止但它的狀態(tài)還沒被父進(jìn)程獲取。

5)        TASK_STOPPED:含義是由于任務(wù)控制信號(hào)或者ptrace系統(tǒng)調(diào)用,任務(wù)已經(jīng)被停止。

6)        TASK_EXCLUSIVE:含義是這不是一個(gè)單獨(dú)狀態(tài),但能夠與TASK_INTERRUPTIBLE或者TASK_UNINTERRUPTIBLE狀態(tài)并存(OR操作)。這意味著當(dāng)任務(wù)與其他在等待隊(duì)列休眠時(shí),它可以單獨(dú)被喚醒而不需要喚醒整個(gè)等待隊(duì)列的任務(wù)。

任務(wù)標(biāo)記包含了關(guān)于非互相排斥的進(jìn)程狀態(tài)信息。



unsigned long flags; /* per process flags, defined below */

/*

* Per process flags

*/

#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */

/* Not implemented yet, only for 486*/

#define PF_STARTING 0x00000002 /* being created */

#define PF_EXITING 0x00000004 /* getting shut down */

#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */

#define PF_SUPERPRIV 0x00000100 /* used super.user privileges */

#define PF_DUMPCORE 0x00000200 /* dumped core */

#define PF_SIGNALED 0x00000400 /* killed by a signal */

#define PF_MEMALLOC 0x00000800 /* Allocating memory */

#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */

#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */



p->;has_cpu, p->;processor, p->;counter, p->;priority, p->;policy and p->;rt_priority字段和調(diào)度程序關(guān)聯(lián),并將在后面描述。

p->;mm 和p->;active_mm字段分別指向mm_struct結(jié)構(gòu)描述的進(jìn)程地址空間和有效地址空間(如果這個(gè)進(jìn)程不是內(nèi)核進(jìn)程的話)。這使得當(dāng)任務(wù)被調(diào)度離開時(shí)TLB能夠在地址空間自由切換。所以,如果當(dāng)前正在執(zhí)行內(nèi)核任務(wù)(沒有p->;mm),則它的next->;active_mm將被設(shè)置為已經(jīng)被調(diào)度離開的任務(wù)的prev->;active_mm,如果pre-mm != NULL,則這個(gè)地址將和prev->;mm相同。如果CLONE_VM標(biāo)識(shí)傳遞到了clone系統(tǒng)調(diào)用或者依靠vfork系統(tǒng)調(diào)用,則地址空間可以在任務(wù)之間共享。

p->;exec_domain和p->;personality字段與任務(wù)的特性相關(guān),也就是為了模仿UNIX特性的唯一系統(tǒng)調(diào)用。

p->;fs字段包含了文件系統(tǒng)信息,在linux下有三個(gè)方面的含義:

1)        root目錄實(shí)體結(jié)構(gòu)和掛載點(diǎn);

2)        預(yù)備的root目錄實(shí)體和掛載點(diǎn);

3)        當(dāng)前工作目錄實(shí)體和掛載點(diǎn);

這個(gè)結(jié)構(gòu)同樣包含了一個(gè)引用計(jì)數(shù),因?yàn)楫?dāng)進(jìn)行帶CLONE_FS標(biāo)識(shí)的clone系統(tǒng)調(diào)用時(shí),它是共享的。

p->;files字段包含了文件句柄表,這在進(jìn)行帶CLONE_FILES標(biāo)識(shí)clone系統(tǒng)調(diào)用時(shí)也是多任務(wù)共享的。

p->;sig字段包含了信號(hào)處理函數(shù)入口,以CLONE_SIGHAND參數(shù)執(zhí)行clone操作后頁可以在進(jìn)程間共享。





__________________________________

雪,是我的印記;

風(fēng),是我的侍從.

請(qǐng),別問我是誰;

我,其實(shí)不是誰.

我只是飄搖的飛雪,陽光下融在風(fēng)里的孤雕.





  





2.2.        創(chuàng)建和中止任務(wù)與內(nèi)核線程

不同的操作系統(tǒng)書籍,從一個(gè)“正在執(zhí)行的程序的實(shí)例”到“由clone或者fork系統(tǒng)調(diào)用產(chǎn)生的任務(wù)”等不同方式定義了“進(jìn)程”。在linux下,共有三種類型程序:

        空線程;

        內(nèi)核線程;

        用戶任務(wù);

空線程在為第一個(gè)CPU引導(dǎo)時(shí)創(chuàng)建,然后依靠定義在arch/i386/kernel/smpboot.c的fork_by_hand()函數(shù)手工為每個(gè)CPU創(chuàng)建這個(gè)線程。所有的空線程共享一個(gè)init_task結(jié)構(gòu),但都擁有各自的存放在CPU隊(duì)列里的init_tss表示的TSS結(jié)構(gòu)。他們以CLONE_PID方式clone,PID都為零,其他任務(wù)都不能共享這個(gè)PID。

內(nèi)核模式下,kernel_thread函數(shù)調(diào)用clone系統(tǒng)調(diào)用創(chuàng)建了內(nèi)核線程。內(nèi)核線程通常沒有用戶地址空間,也就是p->;mm=NULL,因?yàn)樗麄兠鞔_通過daemonize()函數(shù)執(zhí)行exit_mm()函數(shù)。內(nèi)核線程通??梢灾苯硬僮鲀?nèi)核地址空間,并被分配低范圍的pid號(hào)。當(dāng)在處理器模式下運(yùn)行時(shí)意味著內(nèi)核線程將享用所有的I/O特權(quán)并不能被調(diào)用程序預(yù)清空。

用戶任務(wù)通過clone或者fork系統(tǒng)調(diào)用創(chuàng)建,他們都在內(nèi)部調(diào)用了kernel/fork.c的do_fork()函數(shù)。

讓我們分析一下當(dāng)用戶進(jìn)程調(diào)用fork系統(tǒng)調(diào)用時(shí)發(fā)生了什么。雖然fork操作在傳遞用戶堆棧和寄存器時(shí)依賴于體系架構(gòu),但在下面真實(shí)執(zhí)行這個(gè)操作的do_fork()函數(shù)確實(shí)簡(jiǎn)潔的,并位于kernel/fork.c文件。

以下步驟將被執(zhí)行:

1)        本地變量被設(shè)置為-ENOMEM,當(dāng)fork創(chuàng)建一個(gè)新任務(wù)結(jié)構(gòu)失敗時(shí)將作為錯(cuò)誤代碼返回。

2)        .如果CLONE_PID標(biāo)識(shí)被設(shè)置,則返回-EPERM錯(cuò)誤,除非調(diào)用者是空線程。普通用戶線程clone時(shí)不能傳遞CLONE_PID標(biāo)識(shí)并期待操作成功。SIFCHLDclone標(biāo)識(shí),對(duì)于fork來說,它被認(rèn)為是不相關(guān)的,僅在sys_clone調(diào)用do_fork時(shí)才被認(rèn)為是相關(guān)的。

3)        初始化current->;vfork_sem。它將在sys_vfork函數(shù)為了休眠父進(jìn)程直到子進(jìn)程執(zhí)行mm_release函數(shù)時(shí)使用,就像執(zhí)行其他程序或者中止其他程序一樣。

4)        通過alloc_task_struct()宏分配一個(gè)新的任務(wù)結(jié)構(gòu)。在x86系統(tǒng)上,它僅是一個(gè)GFP_KERNEL優(yōu)先級(jí)的gfp。這酒是為何fork系統(tǒng)調(diào)用可能休眠的第一個(gè)原因。如果分配失敗,返回-ENOMEM錯(cuò)誤。

5)        通過結(jié)構(gòu)拷貝*p = *current,將所有當(dāng)前進(jìn)程結(jié)構(gòu)的數(shù)據(jù)都拷貝到新進(jìn)程,或許這個(gè)操作應(yīng)該被memcpy替換。然后,所有不能被子進(jìn)程修改的字段將被設(shè)置為正確的值。

6)        大范圍的內(nèi)核鎖被采用以防止其他部分執(zhí)行本段代碼。

7)        如果父進(jìn)程擁有用戶資源則校驗(yàn)是否超出了RLIMIT_NPROC限制。如果是這樣,則返回-EAGAIN錯(cuò)誤;如果沒有,則通過指定的uid將計(jì)數(shù)器p->;user->;count進(jìn)程數(shù)刷新。

        如果系統(tǒng)所有的任務(wù)數(shù)目超過了最大線程數(shù),返回-EAGAIN錯(cuò)誤。

9)        如果進(jìn)程是依賴預(yù)模塊執(zhí)行的,則增加依賴模塊的引用計(jì)數(shù)。

10)        如果進(jìn)程是依賴預(yù)模塊二進(jìn)制格式的,也增加依賴模塊的引用計(jì)數(shù)。

11)        子進(jìn)程被標(biāo)識(shí)為“沒有被執(zhí)行”(p->;did_exec=0)。

12)        子進(jìn)程被標(biāo)識(shí)為'not.swappable' (p->;swappable = 0)。

13)        子進(jìn)程被置為TASK_UNINTERRUPTIBLE狀態(tài),即p->;state = TASK_UNINTERRUPTIBLE。

14)        依照clone_flags的數(shù)值設(shè)置子進(jìn)程的p->;flags,如果是簡(jiǎn)單fork,p->;flags= PF_FORKNOEXEC。

15)        通過快速算法kernel/fork.c的get_pid()函數(shù)設(shè)置子進(jìn)程號(hào)p->;pid。

16)        初始化子進(jìn)程其他任務(wù)結(jié)構(gòu)。最后子進(jìn)程結(jié)構(gòu)被插入到pidhash表中,并且被喚醒。

這樣任務(wù)就被創(chuàng)建了。停止任務(wù)有很多方式。

1)        通過exit系統(tǒng)調(diào)用;

2)        收到一個(gè)中止信號(hào);

3)        被確定異常強(qiáng)制中止;

4)        以func == 1參數(shù)調(diào)用bdflush。

系統(tǒng)調(diào)用的實(shí)現(xiàn)函數(shù)都有sys_前綴,當(dāng)他們通常僅與參數(shù)檢測(cè)或者以細(xì)節(jié)方式傳遞信息,真正的操作是由do_**函數(shù)完成的。所以sys_exit()函數(shù)調(diào)用了do_exit來完成操作。盡管如此,內(nèi)核其他部分有時(shí)也通過調(diào)用sys_exit實(shí)現(xiàn)堆do_exit的調(diào)用。

do_exit函數(shù)定義在kernel/exit.c中,按照以下幾個(gè)步驟執(zhí)行:

        獲取內(nèi)核全局鎖;

        在最后調(diào)用一直循環(huán)的schedule()函數(shù);

        設(shè)置任務(wù)狀態(tài)為TASK_ZOMBIE;

        以current->;pdeath_signa信號(hào)通知所有的子進(jìn)程;

        以等同于SIGCHLD的信號(hào)current.>;exit_signal通知父進(jìn)程;

        釋放fork函數(shù)分配的資源,關(guān)閉已經(jīng)打開的文件;

        在采用少量FPU切換的體系中,不管硬件設(shè)備要求什么都向FPU的所有者傳遞一個(gè)“none”;

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多