程序1的建立與輪轉

2021-07-24 03:25:38 字數 4083 閱讀 1962

一. 程序1的建立

程序1是由程序0建立的,建立過程如下:

main() ---> _syscall0(int,fork) ---> int 0x80中斷進入系統呼叫(特權級由3切換到0) ---> _sys_call --->sys_fork() ---> find_empty_process()為程序申請乙個可用的程序號pid ---> copy_process(),在該函式中初始化建立的程序1的tss結構,將tss段插入到gdt描述符表中,並設定好tss的段基址和段長度。

程序1的建立主要是通過copy_process()函式來完成,copy_process()函式主要完成以下任務:

(1)呼叫get_free_page()函式,在主記憶體申請乙個空閒頁面,並將申請的空閒頁面清零,用於程序1的task_struct及核心棧。

(2)將父程序0的task_struct的內容複製給程序1的task_struct

(3)為程序1的task_struct、tss做個性化設定:特別要注意,將程序1的tss.eip設定為建立過程中int 0x80中斷程式執行時,保護現場壓入棧中的eip了,這一點會影響後面輪轉後,程序1的執行。

(4)為程序1建立第乙個頁表,將程序0的頁表項內容賦給這個頁表

(5)程序1共享程序0的檔案

(6)設定程序1的gdt項

(7)最後將程序1設定為就緒狀態,使其可以參與程序間的輪轉

**如下:

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,

long ebx,long ecx,long edx,

long fs,long es,long ds,

long eip,long cs,long eflags,long esp,long ss)

//引數是int 0x80、system_call、sys_fork呼叫時多次累積壓棧的結果

for (i=0; ifilp[i])

f->f_count++;

if (current->pwd)

current->pwd->i_count++;

if (current->root)

current->root->i_count++;

if (current->executable)

current->executable->i_count++;

set_tss_desc(gdt+(nr<<1)+first_tss_entry,&(p->tss)); //first_tss_entry = 4對應gdt表中tss0

set_ldt_desc(gdt+(nr<<1)+first_ldt_entry,&(p->ldt));

p->state = task_running;    /* do this last, just in case */

return last_pid;

}

其中copy_process()輸入引數都是之前入棧的資料,按照順序如下:

1)內聯函式_syscall0(int,fork) ---> 執行int 0x80中斷服務程式:為中斷返回保護現場,cpu硬體自動將ss esp eflags cs eip壓棧

2)_system_call ---> sys_fork():程式將ds es fs edx ecx ebx壓棧

3)sys_fork() ---> copy_process(): 將gs esi edi ebp eax壓棧,其中eax將會作為nr

二. 程序1的輪轉

程序跳轉流程:

當程序1建立完成後會回到main()中,執行main()函式中的pause()函式 --- >_syscall0(int,pause) --->int 0x80中斷進入系統呼叫 ---> _sys_call --->sys_pause() ---> schedule() --- switch_to() 完成程序切換。

下面解析一下程序排程部分的**:

引用兩篇文章:

//**路徑:/kernel/sched.c

void schedule(void)

if (((*p)->signal & ~(_blockable & (*p)->blocked)) &&

(*p)->state==task_interruptible)

(*p)->state=task_running;

} while (1)

if (c) break;

for(p = &last_task ; p > &first_task ; --p)

if (*p)

(*p)->counter = ((*p)->counter >> 1) + //設定程序初始時時間片大小為: 程序priority值(初始時counter = 0)

(*p)->priority;

} switch_to(next);

}//**路徑:/include/sched.h

#define first_tss_entry 4

#define first_ldt_entry (first_tss_entry+1)

#define _tss(n) ((((unsigned long) n)<<4)+(first_tss_entry<<3)) //生成tss的段選擇符

#define _ldt(n) ((((unsigned long) n)<<4)+(first_ldt_entry<<3))

#define switch_to(n) __tmp; \ //為ljmp的cs、eip準備的資料結構

__asm__("cmpl %%ecx,_current\n\t" \ //比較程序n與當前程序

"je 1f\n\t" \ //如果相等,就沒必要切換,退出

"movw %%dx,%1\n\t" \ //把edx低字部分賦給tmp.b

"xchgl %%ecx,_current\n\t" \ //task[n]與task[current]交換

"ljmp %0\n\t" \ //

"cmpl %%ecx,_last_task_used_math\n\t" \ //比較上次是否使用過協處理器

"jne 1f\n\t" \

"clts\n" \ //清除cr0中的任務切換標誌

"1:" \

::"m" (*&__tmp.a),"m" (*&__tmp.b), \ //a對應eip,b對應cs

"d" (_tss(n)),"c" ((long) task[n])); \ //edx是tssn的索引號,ecx是task[n]

}

說明:

(1)_tss(n): 生成tss的段選擇符

ti=0 :表示段描述符在gdt中

ti=1 :表示段選擇符在ldt中

rpl:表示優先順序

(2)gdt表

(3)程序切換過程:switch_to(n)

ljmp %0
在保護模式下cpu進行長跳轉,如果發現段選擇符指向tss段,那麼cpu將會忽略偏移,自動將tss段的內容載入到當前cpu暫存器中,比如eax,ldr,cs,ss,esp,eip等,其實就是104位元組的tss結構的所有成員變數賦值給cpu暫存器(注意這裡是ss0和esp0),從而任務切換到該tss對應的程序。再次強調這個過程是自動完成的。

注意,執行完ljmp %0後,後面的 cmpl %%ecx,_last_task_used_math還沒執行,int 0x80中斷沒有返回,cpu就開始執行程序1了。現在cpu中的eip是copy_process()中為程序1的tss.eip,裡面的值是:內聯函式_syscall0(int,fork) ---> 執行int 0x80中斷服務程式:為中斷返回保護現場,cpu硬體自動將ss esp eflags cs eip壓棧,時的值,因此程序1接下來會去執行fork中int 0x80中斷返回時下一行**,即if(__res>=0),所以之後將從這行**開始執行,不會像建立程序1那樣原路返回。

1 程序建立

示例不錯 文字不錯 先貼上 1 fork建立程序。子程序從父程序複製。include include include includeint main else if 0 pid 子程序得到的返回值是0,這段 在子程序中執行 else 建立程序失敗 printf func s exit n func ...

程序建立與執行緒建立

1.程序建立fork asmlinkage int sys fork struct pt regs regs long do fork unsigned long clone flags,unsigned long stack start,struct pt regs regs,unsigned l...

程序2的建立與執行

程序1第一次執行,完成設定硬碟資訊 格式化虛擬盤 根裝置 載入根檔案系統後會回到下面語句 if fork 分隔符 init 1.開啟終端裝置檔案 open dev tty0 o rdwr,0 建立標準輸入裝置,其中 dev tty0是該檔案的路徑名 sys open dev tty0 o rdwr,...