linux0.11文件分析
在kernel包中有幾個重要的文件夾和文件,他們各司其職,處理著有關內核的一些功能操作。其中文件夾有三個:blk_drv(塊設備驅動),chr_drv(字符設備驅動),math(數學協處理器)? 文件中asm.s? fork.c?? mktime.c?? panic.c printk.c? sched.c? signal.c? exit.c?? sys.c?? traps.c? system_call.c? vsprintf.c?? 該文件夾下的代碼文件從功能上來可以分為三類:
1.硬件中斷處理類程序。(asm.s?? trap.c)asm.s用于實現大部分硬件異常所引起的中斷的匯編語言處理過程。在80X86組成的PC機中,采用了兩片8259A可編程中斷控制芯片。每片可以管理8個中斷源。通過多片的級聯方式,能夠構成最多可以管理64個中斷向量的系統。在PC/AT系列兼容機中,使用了兩片8259A芯片,共可管理15級中斷向量。如下圖:
對于Linux內核來說,中斷信號通常分為兩類:硬件中斷和軟件中斷(異常)。每個中斷時由0-255之間的一個數字來標示。對于中斷int0-int31(0x00--0x1f),每個中斷的功能有INTEL公司固定設定或者保留用,屬于軟件中斷,單INTEL公司稱之為異常。因為這些中斷時在CPU執行指令時探測到異常而引起的。中斷int32--int255可以由用戶自己設定使用,在Linux中int32--int47對應于8259A中斷控制芯片發出的硬件中斷請求信號IRQ0--IRQ15,并把程序編程發出的系統調用(system_call)中斷設置為int128(0x80)。
traps.c程序則實現了asm.s的中斷處理過程中調用的C函數。
2.系統調用處理相關程序(system_call.s? fork.c?? signal.c? sys.c? exit.c)在Linux中應用程序調用內核的功能是通過中斷調用int0x80進行的
3.其他通用類程序(schedule.c?? mktime.c? panic.c? printk.c vsprintf.c)?? 其中,schedule.c最為重要,是內核的核心調度程序,用于對進程的執行進行切換或改變進程的執行狀態。
?
下面是一些具體的文件
1.system_call.s對于軟中斷,處理過程基本上是首先為調用相應C函數處理程序作準備,將一些參數壓入堆棧,然后調用C函數進行相應功能的處理。? 對于硬中斷請求型號IRQ發來的中斷,其處理過程首先是向中斷控制芯片8259A發送結束硬件中斷控制字指令EOI,然后調用相應的C函數處理程序。?? 對于系統調用的中斷處理過程,可以把它看做是一個“接口”程序,實際每個系統調用功能的處理基本上都是通過調用相應的C函數進行的。即所謂的? 下半區? 函數。
2.schedule.c是對整個內核進程的調度,這里面把代碼貼上,比說什么都要明白。
/** 'schedule()'是調度函數。這是個很好的代碼!沒有任何理由對它進行修改,因為它可以在所有的* 環境下工作(比如能夠對IO-邊界處理很好的響應等)。只有一件事值得留意,那就是這里的信號* 處理代碼。* 注意!!任務0 是個閑置('idle')任務,只有當沒有其它任務可以運行時才調用它。它不能被殺* 死,也不能睡眠。任務0 中的狀態信息'state'是從來不用的。*/ void schedule (void) {int i, next, c;struct task_struct **p; // 任務結構指針的指針。/* check alarm, wake up any interruptible tasks that have got a signal *//* 檢測alarm(進程的報警定時值),喚醒任何已得到信號的可中斷任務 */// 從任務數組中最后一個任務開始檢測alarm。for (p = &LAST_TASK; p > &FIRST_TASK; --p)if (*p){// 如果任務的alarm 時間已經過期(alarm<jiffies),則在信號位圖中置SIGALRM 信號,然后清alarm。// jiffies 是系統從開機開始算起的滴答數(10ms/滴答)。定義在sched.h 第139 行。if ((*p)->alarm && (*p)->alarm < jiffies){(*p)->signal |= (1 << (SIGALRM - 1));(*p)->alarm = 0;}// 如果信號位圖中除被阻塞的信號外還有其它信號,并且任務處于可中斷狀態,則置任務為就緒狀態。// 其中'~(_BLOCKABLE & (*p)->blocked)'用于忽略被阻塞的信號,但SIGKILL 和SIGSTOP 不能被阻塞。if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&(*p)->state == TASK_INTERRUPTIBLE)(*p)->state = TASK_RUNNING; //置為就緒(可執行)狀態。}/* this is the scheduler proper: *//* 這里是調度程序的主要部分 */while (1){c = -1;next = 0;i = NR_TASKS;p = &task[NR_TASKS];// 這段代碼也是從任務數組的最后一個任務開始循環處理,并跳過不含任務的數組槽。比較每個就緒// 狀態任務的counter(任務運行時間的遞減滴答計數)值,哪一個值大,運行時間還不長,next 就// 指向哪個的任務號。while (--i){if (!*--p)continue;if ((*p)->state == TASK_RUNNING && (*p)->counter > c)c = (*p)->counter, next = i;}// 如果比較得出有counter 值大于0 的結果,則退出124 行開始的循環,執行任務切換(141 行)。if (c)break;// 否則就根據每個任務的優先權值,更新每一個任務的counter 值,然后回到125 行重新比較。// counter 值的計算方式為counter = counter /2 + priority。[右邊counter=0??]for (p = &LAST_TASK; p > &FIRST_TASK; --p)if (*p)(*p)->counter = ((*p)->counter >> 1) + (*p)->priority;}switch_to (next); // 切換到任務號為next 的任務,并運行之。 }pause()系統調用。轉換當前任務的狀態為可中斷的等待狀態,并重新調度。 // 該系統調用將導致進程進入睡眠狀態,直到收到一個信號。該信號用于終止進程或者使進程調用 // 一個信號捕獲函數。只有當捕獲了一個信號,并且信號捕獲處理函數返回,pause()才會返回。 // 此時pause()返回值應該是-1,并且errno 被置為EINTR。這里還沒有完全實現(直到0.95 版)。 int sys_pause (void) {current->state = TASK_INTERRUPTIBLE;schedule ();return 0; }// 把當前任務置為不可中斷的等待狀態,并讓睡眠隊列頭的指針指向當前任務。 // 只有明確地喚醒時才會返回。該函數提供了進程與中斷處理程序之間的同步機制。 // 函數參數*p 是放置等待任務的隊列頭指針。(參見列表后的說明)。 void sleep_on (struct task_struct **p) {struct task_struct *tmp;// 若指針無效,則退出。(指針所指的對象可以是NULL,但指針本身不會為0)。if (!p)return;if (current == &(init_task.task)) // 如果當前任務是任務0,則死機(impossible!)。panic ("task[0] trying to sleep");tmp = *p; // 讓tmp 指向已經在等待隊列上的任務(如果有的話)。*p = current; // 將睡眠隊列頭的等待指針指向當前任務。current->state = TASK_UNINTERRUPTIBLE; // 將當前任務置為不可中斷的等待狀態。schedule (); // 重新調度。// 只有當這個等待任務被喚醒時,調度程序才又返回到這里,則表示進程已被明確地喚醒。// 既然大家都在等待同樣的資源,那么在資源可用時,就有必要喚醒所有等待該資源的進程。該函數// 嵌套調用,也會嵌套喚醒所有等待該資源的進程。然后系統會根據這些進程的優先條件,重新調度// 應該由哪個進程首先使用資源。也即讓這些進程競爭上崗。if (tmp) // 若還存在等待的任務,則也將其置為就緒狀態(喚醒)。tmp->state = 0; }// 將當前任務置為可中斷的等待狀態,并放入*p 指定的等待隊列中。參見列表后對sleep_on()的說明。 void interruptible_sleep_on (struct task_struct **p) {struct task_struct *tmp;if (!p)return;if (current == &(init_task.task))panic ("task[0] trying to sleep");tmp = *p;*p = current; repeat:current->state = TASK_INTERRUPTIBLE;schedule ();// 如果等待隊列中還有等待任務,并且隊列頭指針所指向的任務不是當前任務時,則將該等待任務置為// 可運行的就緒狀態,并重新執行調度程序。當指針*p 所指向的不是當前任務時,表示在當前任務被放// 入隊列后,又有新的任務被插入等待隊列中,因此,既然本任務是可中斷的,就應該首先執行所有// 其它的等待任務。if (*p && *p != current){(**p).state = 0;goto repeat;}// 下面一句代碼有誤,應該是*p = tmp,讓隊列頭指針指向其余等待任務,否則在當前任務之前插入// 等待隊列的任務均被抹掉了。參見圖4.3。*p = NULL;if (tmp)tmp->state = 0; }// 喚醒指定任務*p。 void wake_up (struct task_struct **p) {if (p && *p){(**p).state = 0; // 置為就緒(可運行)狀態。*p = NULL;} }
3.signal.c主要對信號的判斷,對于一個進程,當收到一個信號時,可以由三種不同的處理或者操作方式。a。忽略該信號,但是SIGKILL和SIGSTOP不能忽略。b。捕獲該信號。c。執行默認操作,內核為每種信號都提供一種默認操作,通常這些默認操作就是終止進程的執行。(對于信號的具體內容還有待研究)
4.fork.c主要是copy_process函數。該函數通過get_free_page ()(為新任務數據結構分配內存)函數得到一個新的task_struct空間。然后將current的信息復制給對方。得到新進程
?
?
----
轉載于:https://www.cnblogs.com/Ph-one/p/4578772.html
總結
以上是生活随笔為你收集整理的linux0.11文件分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: easyui打开新的选项卡_easyUI
- 下一篇: 查看linux版本的三种常用方法