一 功能描述
1,sched.c 是內(nèi)核中有關(guān)進(jìn)程調(diào)度管理的程序,其中有關(guān)調(diào)度的基本函數(shù)(sleep_on() , wakeup() ,schedule() 函數(shù)等) ,其中比較重要的一個(gè)函數(shù)是schedule()函數(shù),
該函數(shù)負(fù)責(zé)選擇系統(tǒng)中,下一個(gè)將要運(yùn)行的進(jìn)程,它首先對(duì)所有的任務(wù)進(jìn)行選擇,喚醒任何一個(gè)已經(jīng)得到信號(hào)的任務(wù)。
具體方法是針對(duì)任務(wù)數(shù)組中的每個(gè)任務(wù),檢查其報(bào)警定時(shí)值alarm。如果任務(wù)的alarm時(shí)間已經(jīng)過(guò)期(alarm < jiffies), 則在它的信號(hào)位圖中設(shè)置SIGALRM信號(hào),
然后清alarm的值,jiffies是系統(tǒng)是從開(kāi)機(jī)開(kāi)始算起的滴答數(shù),如果進(jìn)程的信號(hào)位圖中除被阻塞的的信號(hào)外還有其他的信號(hào),并且讀進(jìn)程處于可中斷睡眠狀態(tài),
則置進(jìn)程為就緒狀態(tài)。
隨后是調(diào)度函數(shù)的核心處理部分,這部分代碼根據(jù)進(jìn)程的時(shí)間片和優(yōu)先權(quán)調(diào)度機(jī)制,來(lái)選擇隨后要執(zhí)行的任務(wù)。它首先循環(huán)檢查任務(wù)數(shù)組中的所有任務(wù),根據(jù)每個(gè)就緒態(tài)任務(wù)剩余執(zhí)行時(shí)間的值counter,來(lái)選取該值最大的一個(gè)任務(wù),并利用switch_to()函數(shù)切換到該任務(wù)。若所有就緒態(tài)任務(wù)該值都為0,表示此刻所有任務(wù)的時(shí)間片都
已經(jīng)運(yùn)行完畢,于是就根據(jù)任務(wù)的優(yōu)先權(quán)值priority,重置每個(gè)任務(wù)的運(yùn)行時(shí)間片值counter,再重新執(zhí)行循環(huán)檢查所有任務(wù)的執(zhí)行時(shí)間片值。
sleep_on()函數(shù)的主要功能是當(dāng)一個(gè)進(jìn)程所請(qǐng)求的資源正忙或不在內(nèi)存中時(shí)暫時(shí)切換出去,放在等待隊(duì)列中等待一段時(shí)間, 當(dāng)切換回來(lái)之后再繼續(xù)運(yùn)行,放入等待隊(duì)列的方式利用了函數(shù)中的tmp指針作為各個(gè)正在等待任務(wù)的聯(lián)系。
以下是 內(nèi)核模塊中的 sched.c函數(shù)代碼
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>

#include <signal.h>

//讀宏取信號(hào)nr在信號(hào)位圖中對(duì)應(yīng)位的二進(jìn)制數(shù)值,信號(hào)編號(hào)1-32.比如信號(hào)5的位圖就是1<<(5-1),等于0010000b
#define _S(nr) (1<<((nr)-1))

//定義阻塞信號(hào)位圖
#define _BLOCKABLE(~(_S(SIGKILL) | _S(SIGSTOP)))

//內(nèi)核調(diào)試函數(shù)。顯示任務(wù)號(hào)nr的進(jìn)程號(hào),進(jìn)程狀態(tài),和內(nèi)核堆棧空閑字節(jié)數(shù)
void show_task(int nr , struct task_struct * p)


{
int i , j = 4096 - sizeof(struct task_struct) ;
printk("%d: pid= %d , state=%d," , nr, p->pid , p->state) ;
i = 0 ;
while(i < j && !((char *)(p + 1))[i]) //檢測(cè)指定任務(wù)數(shù)據(jù)結(jié)構(gòu)以后等于0的字節(jié)數(shù)
i++ ;
printk("%d(of%d) chars free in kernel stack \n\r" , i , j) ;

}

//顯示所有任務(wù)的任務(wù)號(hào),進(jìn)程號(hào),進(jìn)程狀態(tài)和內(nèi)核堆棧空閑字節(jié)數(shù)
void show_stat(void)


{
int i ;
for(i = 0 ; i < NR_TASKS ; i++)
if(task[i])
show_task(i , task[i]) ;
}



/**////設(shè)置8253芯片初值
#define LATCH(1193180/HZ)

extern void mem_use(void) ;

extern int timer_interrupt(void) ;

extern int system_call(void) ;

//每個(gè)任務(wù)在內(nèi)核態(tài)運(yùn)行時(shí),都會(huì)有自己的內(nèi)核態(tài)堆棧,這里定義了任務(wù)的內(nèi)核態(tài)堆棧結(jié)構(gòu)

union task_union
{
struct task_struct_task ; //因?yàn)橐粋€(gè)任務(wù)的數(shù)據(jù)結(jié)構(gòu)與其內(nèi)核態(tài)堆棧結(jié)構(gòu)在同一個(gè)內(nèi)存頁(yè)中
char stack[PAGE_SIZE] ; //所以從堆棧段寄存器ss可以獲得其數(shù)據(jù)段選擇符
} ;




static union task_union init_task =
{INIT_TASK , } ;
long volatile jiffies = 0 ; //volatile 表示要從內(nèi)存取值,因?yàn)镃PU會(huì)把經(jīng)常使用的變量放在
//通用寄存器中,但是若其他的程序修改這些變量之后,寄存器中的值,可能
//并不發(fā)生變化,這就造成了臟數(shù)據(jù)。 使用volatile 表示每次取值,都會(huì)從內(nèi)存取值

long start_time = 0 ;
struct task_struct * current = &(init_task.task) ; //當(dāng)前任務(wù)指針,默認(rèn)指向任務(wù)0
struct task_struct * last_task_uesd_math = NULL ; //使用協(xié)處理器的任務(wù)指針

struct task_struct * task[NR_TASKS] =
{&(init_task.task) , } ; //定義任務(wù)指針數(shù)組

long user_stack[PAGE_SIZE >> 2] ;

struct
{

long * a ;
short b ;

} stack_start =
{&user_stack[PAGE_SIZE >> 2] , 0x10} ;

void math_state_restore()


{
//如果任務(wù)沒(méi)變,則返回
if(last_task_used_math == current)
return ;

_asm_("fwait") ;
if(last_task_used_math)

{
_asm_("fnsave %0" :: "m"(last_task_used_math->tss.i387)) ;
}

last_task_used_math = current ;

if(current->uesd_math)
{ //已經(jīng)使用過(guò)協(xié)處理器
_asm_("frstor %0"::"m"(current->tss.i387)) ;

} else
{ //第一次使用協(xié)處理器,需要初始化相關(guān)信息
_asm_("fninit"::) ;
current->used_math = 1 ;//設(shè)置已經(jīng)使用過(guò)協(xié)處理器
}

}

void schedule(void)


{
int i , next , c ;
struct task_struct **p ;//任務(wù)結(jié)構(gòu)指針的指針
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)

if(*p)
{
//如果設(shè)置國(guó)任務(wù)的定時(shí)值alarm,并且已經(jīng)過(guò)期(alarm<jiffies),則在信號(hào)位圖中置SIGRAM信號(hào),
//即向任務(wù)發(fā)送SIGRAM信號(hào)。然后清alarm。 該信號(hào)的默認(rèn)操作是終止進(jìn)程。
//jiffies是從系統(tǒng)開(kāi)始啟動(dòng)算起的滴答數(shù)。
if((*p)->alarm && (*p)->alarm < jiffies)

{
(*p)->signal |= (1<<(SIGALRM - 1)) ;
(*P)->alarm = 0 ;
}
//如果信號(hào)位圖中除被阻塞的信號(hào)外還有其他的信號(hào),并且任務(wù)處于可中斷狀態(tài),則置任務(wù)為就緒狀態(tài)。
if(((*p)->signal & ~(_BLOCKABLE&(*p)->blocked))&&(*p)->state == TASK_INTERRUPTIBLE)
(*p)->state - TASK_RUNNING ; //置為就緒狀態(tài)

}

//這是調(diào)度程序的主要部分
while(1)

{
c = -1 ;
next = 0 ;
i = NR_TASKS ;
p = &task[NR_TASKS] ;
//這段代碼也是從任務(wù)數(shù)組的最后一個(gè)任務(wù)開(kāi)始循環(huán)處理,并跳過(guò)不含任務(wù)的數(shù)組槽
//比較每個(gè)就緒狀態(tài)任務(wù)的counter(任務(wù)運(yùn)行時(shí)間的遞減滴答數(shù)),哪個(gè)值最大,運(yùn)行時(shí)間還不長(zhǎng),
//next就指向哪個(gè)任務(wù)號(hào)

while(--i)
{
if(!*--p)
continue ;
if((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i ;
}

//如果比較得出有counter值不等于0的結(jié)果,或者系統(tǒng)中沒(méi)有一個(gè)可以運(yùn)行的程序,那么就跳出最上層的
//while循環(huán),執(zhí)行任務(wù)切換程序
if(c != 0 ) break ;
//全部的任務(wù)的時(shí)間片都已經(jīng)使用完畢,那么就需要重新設(shè)置時(shí)間片值,重新執(zhí)行。
// counter值最大的先執(zhí)行
for(p = &LAST_TASK ; p > &FIRST_TASK ;p++)
if(*p)
(*p)->counter = ((*p)->counter >> 1) + (*p)->priority ;

}


switch_to(next) ; //切換到任務(wù)號(hào)為next的任務(wù),并運(yùn)行之

}



/**//*
線程中斷系統(tǒng)調(diào)用
*/
int sys_pause(void)

{
current->state = TASK_INTERRUPTIBLE ;
schedule() ;
return 0 ;
}
//把任務(wù)變?yōu)椴豢芍袛嗟牡却隣顟B(tài),并讓睡眠隊(duì)列的頭指針指向當(dāng)前的任務(wù)
//只有明確的喚醒,才會(huì)返回,該函數(shù)提供了進(jìn)程與中斷處理程序之間的同步機(jī)制
//函數(shù)參數(shù)P是等待任務(wù)隊(duì)列的頭指針,為了修改調(diào)用該函數(shù)程序中原來(lái)的指針變量的值,
//就需要提供(*p)指針的指針。


void sleep_on(struct task_struct **p) //等待任務(wù)隊(duì)列的頭指針

{
struct task_struct * tmp ;
if(!p)
return ;
//如果進(jìn)程0將要休眠,則死機(jī)
if(current == &(init_task.task))
panic("task[0] trying to sleep");
//讓tmp指向已經(jīng)在等待隊(duì)列之上的任務(wù),并且將等待隊(duì)列頭的等待指針指向當(dāng)前任務(wù)
//這樣就把當(dāng)前任務(wù)插入到了*p的等待隊(duì)列中。然后將當(dāng)前任務(wù)變?yōu)椴豢芍袛嗟牡却隣顟B(tài),并執(zhí)行重新調(diào)度
tmp = *p ;
*p = current ;
current->state = TASK_UNINTERRUPTIBLE ;
schedule() ;
if(tmp) //若在其前還有等待任務(wù),則將其變?yōu)榫途w狀態(tài)
tmp->state = 0 ;


}
//將當(dāng)前的任務(wù)置為可中斷的等待狀態(tài),并放入*p指定的等待隊(duì)列中
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() ;//執(zhí)行調(diào)度程序,切換任務(wù)
//只有當(dāng)這個(gè)等待程序被喚醒的時(shí)候,程序才會(huì)又回到這里執(zhí)行,表示進(jìn)程已被明確地喚醒并執(zhí)行。

if(*p && *p!= current)
{
(**p).state = 0 ;
goto repeat ;
}
*p = NULL ;
if(tmp)
tmp->state = 0 ;
}



/**//*喚醒等待的任務(wù)*/
void wake_up(struct task_struct **p)

{
if(p && *p)

{
(**p).state = 0 ;//置為就緒狀態(tài)
*p = NULL ;
}

}
//下列進(jìn)程數(shù)組存放的是軟驅(qū)馬達(dá)啟動(dòng)到正常轉(zhuǎn)數(shù)的進(jìn)程指針,數(shù)組索引0-3對(duì)應(yīng)軟驅(qū)A-D

static struct task_struct * wait_motor[4] =
{NULL , NULL , NULL , NULL} ;
//每個(gè)馬達(dá)啟動(dòng)所需要的時(shí)間數(shù)

static int mon_timer[4] =
{0 , 0 , 0 ,0} ;
//記錄每個(gè)馬達(dá)停轉(zhuǎn)之前維持的時(shí)間

static int moff_timer[4] =
{0,0,0,0} ;
unsigned char current_DOR = 0x0C ;//這里設(shè)置初值,允許DMA和中斷請(qǐng)求。啟動(dòng)FDC
//指定軟驅(qū)啟動(dòng)到正常運(yùn)轉(zhuǎn)狀態(tài)所需要的等待時(shí)間
int ticks_to_floppy_on(unsigned int nr)

{
extern unsigned char selected ;
unsigned char mask = 0x10 << nr ;
if(nr > 3)
panic("floppy_on : nr > 3") ;
moff_timer[nr] = 10000 ;
cli() ;
mask |= current_DOR ;

if(!selected)
{
mask &= 0xFC ;
mask |= nr ;
}

if(mask != current_DOR)

{
outb(mask , FD_DOR) ;
if((mask ^ current_DOR) & 0xf0)
mon_timer[nr] = HZ / 2 ;
else if(mon_timer[nr] < 2)
mon_timer[nr] = 2 ;

current_DOR = mask ;
}
sti() ;
return mon_timer[nr] ;
}

void floppy_on(unsigned int nr)

{
cli() ;
while(ticks_to_floppy_on(nr))
sleep_on(nr + wait_motor) ;
sti() ;
}

void floppy_off(unsigned int nr)

{
moff_timer[nr] = 3 * HZ ;
}


/**//*軟盤(pán)定時(shí)處理子程序*/

/**//*更新馬達(dá)啟動(dòng)定時(shí)值和馬達(dá)關(guān)閉停轉(zhuǎn)定時(shí)值*/

/**//*系統(tǒng)每當(dāng)經(jīng)過(guò)一個(gè)滴答就會(huì)被調(diào)用一次,隨時(shí)更新馬達(dá)開(kāi)啟或者停轉(zhuǎn)的時(shí)間*/
void do_floppy_timer(void)

{
int i ;
unsigned char mask = 0x10 ;
for(i = 0 ; i < 4 ; i ++ , mask <<= 1)

{
if(!(mask & current_DOR))
continue ;


if(mon_timer[i])
{
if(!--mon_timer[i])
wake_up(i + wait_motor) ;
} else if(!moff_timer[i])

{
current_DOR &= ~mask ;
outb(current_DOR , FD_DOR) ;
} else
moff_timer[i]-- ;

}

}

#define TIME_REQUEST 64
//下面是定時(shí)器的代碼。最多可以有64個(gè)計(jì)時(shí)器

static struct timer_list
{
long jiffies ; //定時(shí)滴答數(shù)
void(* fn)() ; //定時(shí)處理程序
struct timer_list * next ; //鏈接指向下一個(gè)定時(shí)器
} timer_list[TIME_REQUEST] , * next_timer = NULL ;


/**//*添加一個(gè)新的定時(shí)器*/
void add_timer(long jiffies , void(*fn)(void))

{
struct timer_list * p ;
if(!fn)
return ;
cli() ;
if(jiffies <= 0)//如果定時(shí)值為0,則立即執(zhí)行處理程序,并且該定時(shí)器不加入鏈表
(fn)() ;
//否則從定時(shí)器數(shù)組中,找出一個(gè)空的項(xiàng)

else
{
for(p = timer_list ; p < timer_list + TIMER_REQUEST ; p++)
if(!p->fn) //找到一個(gè)空項(xiàng),然后退出
break ;

//如果已經(jīng)用完了定時(shí)器數(shù)組,則系統(tǒng)崩潰,否則向定時(shí)器的數(shù)據(jù)結(jié)構(gòu)中填入相應(yīng)的信息,并連入鏈表頭
if(p >= timer_list + TIME_REQUEST)
panic("no more time request free");

p->fn = fn ;
p->jiffies = jiffies ;
p->next = next_timer ;
next_timer = p ;
//下面的函數(shù)其實(shí)是一個(gè) 雙向隊(duì)列

while(p->next && p->next->jiffies < p->jiffies)
{
p->jiffies -= p->next->jiffies ;
fn = p->fn ;
p->fn = p->next->fn ;
p->next->fn = fn ;
jiffies = p->jiffies ;
p->next->jiffies = jiffies ;
p = p->next ;
}
}

}

void do_timer(long cpl)

{
extern int beepcount ; //揚(yáng)聲器發(fā)生時(shí)間滴答數(shù)
extern void sysbeepstop (void) ; //關(guān)閉揚(yáng)聲器
if(beepcount)
if(!--beppcount)
sysbeepstop() ;
if(cpl)
current->utime++ ;
else
current->stime++ ;

if(next_timer)
{
next_timer->jiffies-- ;

while(next_timer && next_timer->jiffies <= 0)
{
void(*fn)(void) ;
fn = next_timer->fn ;
next_timer->fn = NULL ;
next_timer = next_timer->next ;
(fn)() ;
}
}


if(current_DOR & 0xf0)
do_floppy_timer() ;
if((--current->counter) > 0) return ;
current->counter = 0;
if(!cpl) return ;
schedule() ;

}


//系統(tǒng)調(diào)用功能,設(shè)置報(bào)警定時(shí)時(shí)間值
int sys_alarm(long seconds)

{
int old = current->alarm ;
if(old)
old = (old - jiffies) / HZ ;
current->alarm = (seconds > 0 ) ? (jiffies + HZ * seconds):0 ;
return old ;
}

//取當(dāng)前的進(jìn)程號(hào)pid

int sys_getpid(void)

{

return current->pid ;
}

//取父進(jìn)程號(hào)ppid
int sys_getppid(void)

{
return current->father ;
}

//取用戶號(hào)
int sys_getuid(void)

{
return current->uid ;
}
//取有效的用戶號(hào)euid
int sys_geteuid(void)

{
return current->euid ;
}

//取組號(hào)gid
int sys_getgid(void)

{
return current->gid ;
}

//取有效的組號(hào)
int sys_getegid(void)

{
return current->egid ;
}
//系統(tǒng)調(diào)用功能---降低對(duì)CPU的優(yōu)先使用權(quán)
int sys_nice(long increment)

{
if(current->priority - increment > 0)
current->priority -= increment ;
return 0 ;
}
//內(nèi)核調(diào)度程序初始化

void sched_init(void)

{
int i ;
struct desc_struct * p ; //描述符表結(jié)構(gòu)指針
set_tss_desc(gdt + FIRST_TSS_ENTRY , &(init_task.tss)) ;
set_ldt_desc(gdt + FIRST_LDT_ENTRY , &(init_task.task.ldt));
p = gdt + 2 + FIRST_TSS_ENTRY ;
for(i = 1 ; i < NR_TASKS ;i++)

{
task[i] = NULL ;
p->a = p->b = 0 ;
p++ ;
p->a = p->b = 0 ;
p++ ;
}

_asm_("pushfl ; andl $0xffffbfff , (%esp) ; popfl" ) ;
ltr(0) ;
lldt(0) ;

outb_p(0x36 , 0x43) ;
outb_p(LATCH & 0xff , 0x40) ;
outb(LATCH >> 8 , 0x40) ;

set_intr_gate(0x20 , &timer_interrupt) ;
outb(inb_p(0x21)&~0x01 , 0x21) ;
set_system_gate(0x80 , &system_call) ;

}

