久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標(biāo)題: linux 0.11 內(nèi)核學(xué)習(xí) -- sched.c,調(diào)度進(jìn)程。 [打印本頁]

作者: 51黑tt    時(shí)間: 2016-3-5 18:18
標(biāo)題: linux 0.11 內(nèi)核學(xué)習(xí) -- sched.c,調(diào)度進(jìn)程。
/*
* 2010-1-21
* 該文件時(shí)內(nèi)核中有關(guān)任務(wù)調(diào)度的函數(shù)程序,其中包含基本函數(shù)sleep_on,
* wakeup,schedule等,以及一些簡(jiǎn)單的系統(tǒng)調(diào)用。同時(shí)將軟盤的幾個(gè)操作
* 函數(shù)也放置在這里。
*
* schedule函數(shù)首先對(duì)所有的任務(wù)檢查,喚醒任何一個(gè)已經(jīng)得到信號(hào)的任務(wù),
* 具體的方法是針對(duì)任務(wù)數(shù)組中的每個(gè)任務(wù),檢查其警報(bào)定時(shí)值alarm。如果任務(wù)
* 的alarm已經(jīng)超期(alarm < jiffies),則在它的信號(hào)位圖中設(shè)置SIGALARM,然后
* 情書alarm值。jiffies是系統(tǒng)自從開機(jī)之后算起的滴答數(shù)。在scheed.h中定義,
* 如果進(jìn)程信號(hào)的位圖中除去被阻塞的信號(hào)之外還有其他信號(hào),并且任務(wù)處于可
* 中斷睡眠狀態(tài),則置任務(wù)為就緒狀態(tài)。
* 隨后是調(diào)度函數(shù)的核心處理,這部分代碼根據(jù)進(jìn)程時(shí)間片和優(yōu)先權(quán)的調(diào)度機(jī)制,
* 來選擇將要執(zhí)行的程序。他首先是循環(huán)檢查任務(wù)數(shù)組中的所有任務(wù)。根據(jù)每個(gè)就緒
* 任務(wù)剩余執(zhí)行時(shí)間值counter中選取一個(gè)最大的,利用switch_to函數(shù)完成任務(wù)
* 轉(zhuǎn)換。如果所有的就緒任務(wù)的該值都是0,則表示此刻所有任務(wù)的時(shí)間片都已運(yùn)行完。
* 于是就根據(jù)任務(wù)的優(yōu)先權(quán)值priority,重置每個(gè)任務(wù)的運(yùn)行時(shí)間counter。在重新
* 循環(huán)檢查所有的任務(wù)重的執(zhí)行的時(shí)間片值。
* 另一個(gè)值得一說的是sleep_on函數(shù),該函數(shù)雖短,卻要比schedule函數(shù)難理解,
* 簡(jiǎn)單的講,sleep_on函數(shù)主要的功能是當(dāng)一個(gè)進(jìn)程所請(qǐng)求的資源正在忙,或者是
* 不在內(nèi)存中被切換出去,放在等待隊(duì)列中等待一段時(shí)間。切換回來后在繼續(xù)執(zhí)行。
* 放入等待隊(duì)列的方式是,利用了函數(shù)中的tmp指針為各個(gè)正在等待任務(wù)的聯(lián)系。
* 還有一個(gè)函數(shù)interrupt_sleep_on,該函數(shù)的主要功能是在進(jìn)程調(diào)度之前,把當(dāng)前
* 任務(wù)設(shè)置為可中斷等待狀態(tài),并在本任務(wù)被喚醒之后還需要查看隊(duì)列上是否還有
* 后來的等待任務(wù),如果有,先調(diào)度他們。
*
*/
/*
*  linux/kernel/sched.c
*
*  (C) 1991  Linus Torvalds
*/
/*
* 'sched.c' is the main kernel file. It contains scheduling primitives
* (sleep_on, wakeup, schedule etc) as well as a number of simple system
* call functions (type getpid(), which just extracts a field from
* current-task
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h> // 軟驅(qū)頭文件
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h> // 端操作頭文件,定義端操作的匯編函數(shù)
#include <signal.h>
#define _S(nr) (1<<((nr)-1)) // 取nr(1-32)對(duì)應(yīng)的位的二進(jìn)制數(shù)值,取出的
// 并不是一位
// 定義除了SIGKILL和SIGSTOP之外,其他信號(hào)位全是阻塞的
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
//----------------------------------------------------------------------
// show_task
// 顯示任務(wù)號(hào)nr,pid,進(jìn)程狀態(tài)和內(nèi)核堆棧空閑字節(jié)
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])
i++;
printk("%d (of %d) chars free in kernel stack\n\r",i,j);
}
//---------------------------------------------------------------------
// show_stat
// 顯示所有任務(wù)的信息
void show_stat(void)
{
int i;
for (i=0;i<NR_TASKS;i++)
if (task[i]) // task是一個(gè)指針數(shù)組,如果存在”任務(wù)“
show_task(i,task[i]);
}
#define LATCH (1193180/HZ) // 每個(gè)時(shí)間片滴答數(shù)
extern void mem_use(void);
extern int timer_interrupt(void); // 時(shí)鐘中斷處理程序
extern int system_call(void); // 系統(tǒng)調(diào)用處理程序
union task_union
{
// 定義任務(wù)聯(lián)合(任務(wù)結(jié)構(gòu)成員和stack 字符數(shù)組程序成員),聯(lián)合體是共享內(nèi)存的
struct task_struct task; // 因?yàn)橐粋(gè)任務(wù)數(shù)據(jù)結(jié)構(gòu)與其堆棧放在同一內(nèi)存頁中,所以
char stack[PAGE_SIZE]; // 從堆棧段寄存器ss 可以獲得其數(shù)據(jù)段選擇符
};
static union task_union init_task = {INIT_TASK,}; // 定義初始任務(wù)數(shù)據(jù)
long volatile jiffies=0; // 定義開機(jī)以來時(shí)鐘滴答數(shù)
long startup_time=0; // 開機(jī)時(shí)間
struct task_struct *current = &(init_task.task); // 當(dāng)前任務(wù)指針
struct task_struct *last_task_used_math = NULL; // 使用過協(xié)處理器的任務(wù)指針
struct task_struct * task[NR_TASKS] = {&(init_task.task), }; // 定義任務(wù)數(shù)組
long user_stack [ PAGE_SIZE>>2 ] ; // 定義系統(tǒng)堆棧指針
struct { // 該結(jié)果用于設(shè)置堆棧ss:esp
long * a;
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
//---------------------------------------------------------------------
// math_state_restore
/*
*  'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
*/
/*
* 將當(dāng)前協(xié)處理器內(nèi)容保存在原來協(xié)處理器數(shù)組中,并將當(dāng)前任務(wù)的協(xié)處理器
* 內(nèi)容加載到協(xié)處理器
*
*/
// 當(dāng)任務(wù)被調(diào)度交換之后,該函數(shù)用以保存員任務(wù)的協(xié)處理器的狀態(tài),并回復(fù)
// 新調(diào)度進(jìn)來的當(dāng)前協(xié)處理器的執(zhí)行狀態(tài)
void math_state_restore()
{
if (last_task_used_math == current) // 如果任務(wù)沒有改變返回
return;
__asm__("fwait"); // 在發(fā)送協(xié)處理器指令之前首先發(fā)出wait指令
if (last_task_used_math) // 如果上個(gè)使用協(xié)處理器的進(jìn)程存在
{
// 保存狀態(tài)
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
}
last_task_used_math=current; // 現(xiàn)在last_task_used_math指向當(dāng)前任務(wù)
if (current->used_math) // 如果當(dāng)前的任務(wù)使用過協(xié)處理器
{
__asm__("frstor %0"::"m" (current->tss.i387));// 恢復(fù)狀態(tài)
} else // 沒有使用過協(xié)處理器
{
__asm__("fninit"::); // 初始化協(xié)處理器
current->used_math=1; // 設(shè)置使用協(xié)處理器標(biāo)志
}
}
//--------------------------------------------------------------------
// schedule
/*
*  'schedule()' is the scheduler function. This is GOOD CODE! There
* probably won't be any reason to change this, as it should work well
* in all circumstances (ie gives IO-bound processes good response etc).
* The one thing you might take a look at is the signal-handler code here.
*
*   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
*/
void schedule(void)
{
int i,next,c;
struct task_struct ** p;
/* check alarm, wake up any interruptible tasks that have got a signal */
/* 檢查alarm,喚醒任何已得到信號(hào)的可中斷任務(wù) */
// 從任務(wù)數(shù)組最后開始檢查alarm
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p) // 任務(wù)存在?
{
if ((*p)->alarm && (*p)->alarm < jiffies)
/*
* 下面是對(duì)(*p)->alarm < jiffies理解:
* 如果不調(diào)用alarm()函數(shù),alarm的值就是0,但是調(diào)用了alarm函數(shù)
* 之后,比如說alarm(5),就是5秒后報(bào)警
*/
{
// 在位圖信號(hào)中置位AIGALARM
(*p)->signal |= (1<<(SIGALRM-1));
// 將alarm值置位0
(*p)->alarm = 0;
}
// 如果信號(hào)位圖中除被阻塞的信號(hào)外還有其他信號(hào),即是該
// 進(jìn)程申請(qǐng)的自愿被別的進(jìn)程釋放,或者是其他條件導(dǎo)致該
// 進(jìn)程能夠被執(zhí)行,并且該任務(wù)處于的是可中斷編程。linux
// 內(nèi)核進(jìn)程轉(zhuǎn)換見文檔<進(jìn)程運(yùn)行狀態(tài)圖.txt>。此時(shí)將該進(jìn)程
// 進(jìn)程狀態(tài)置位就緒。
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
(*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
}
/* this is the scheduler proper: */
/* 這是調(diào)度的主要部分 */
while (1) // 循環(huán),直到存在counter的值大于0
{
c = -1;
next = 0;
i = NR_TASKS;
p = &task[NR_TASKS];
////////////////////////////////////////////////
// 下面的代碼是尋找最大counter值的進(jìn)程。counter
// 值的含義見文檔 <linux0.11task_struct中counter解釋.txt>
while (--i) {
if (!*--p)
continue;
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
////////////////////////////////////////////////
if (c) break; // 如果進(jìn)程存在。退出,去執(zhí)行switch_to
// 否則更新counter值
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
}
switch_to(next);
}
//--------------------------------------------------------------------
// sys_pause
// 將當(dāng)前任務(wù)設(shè)置為可中斷,執(zhí)行調(diào)度函數(shù)
int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
schedule();
return 0;
}
//-------------------------------------------------------------------
// sleep_on
// struct task_struct **p是等待隊(duì)列頭指針
// 該函數(shù)就是首先將當(dāng)前任務(wù)設(shè)置為TASK_UNINTERRUPTIBLE,并讓睡眠隊(duì)列
// 頭指針指向當(dāng)前任務(wù),執(zhí)行調(diào)度函數(shù),直到有明確的喚醒時(shí),該任務(wù)才重新
// 開始執(zhí)行。
void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p) // 無效指針
return;
if (current == &(init_task.task)) // 當(dāng)前任務(wù)是0,死機(jī)
panic("task[0] trying to sleep");
tmp = *p;
*p = current;
current->state = TASK_UNINTERRUPTIBLE; // 設(shè)置狀態(tài)
schedule(); // 執(zhí)行調(diào)度,直到明確的喚醒
// 肯能存在多個(gè)任務(wù)此時(shí)被喚醒,那么如果還存在等待任務(wù)
// if (tmp),則將狀態(tài)設(shè)置為”就緒“
if (tmp)
tmp->state=0;
}
//--------------------------------------------------------------------------
// interruptible_sleep_on
// struct task_struct **p是等待隊(duì)列對(duì)頭
void interruptible_sleep_on(struct task_struct **p)
{
/*
* 首先需要明確的是TASK_INTERRUPTIBLE。它是指當(dāng)進(jìn)
* 程處于可中斷等待狀態(tài)時(shí),系統(tǒng)不會(huì)調(diào)度該進(jìn)行執(zhí)行。
*/
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp=*p;
*p=current; // 保存該任務(wù)指針
repeat: current->state = TASK_INTERRUPTIBLE;
schedule();
if (*p && *p != current)
{
/*
* *p != current表示當(dāng)前任務(wù)不是原來保存的任務(wù),即是
* 有新的任務(wù)插入到等待隊(duì)列中了。由于本任務(wù)是不可中斷的
*,所以首先執(zhí)行其他的任務(wù)
*/
(**p).state=0;
goto repeat;
}
/*
* 下面的代碼錯(cuò)誤,應(yīng)該是*p = tmp,讓隊(duì)列頭指針指向隊(duì)列中其他任務(wù)
*/
*p=NULL;
// 原因同上。sleep_on
if (tmp)
tmp->state=0;
}
//----------------------------------------------------------------
// wake_up
// 喚醒任務(wù)p
void wake_up(struct task_struct **p)
{
if (p && *p)
{
(**p).state=0; // 置狀態(tài)為可運(yùn)行
*p=NULL;
}
}
/*
* OK, here are some floppy things that shouldn't be in the kernel
* proper. They are here because the floppy needs a timer, and this
* was the easiest way of doing it.
*/
/*
* 由于軟盤需要時(shí)鐘,所以就將軟盤的程序放到這里了
*/
// 利用下面的數(shù)組來存儲(chǔ)的是馬達(dá)運(yùn)轉(zhuǎn)或者是停止的滴答數(shù),下列的
// 數(shù)組在函數(shù)do_floppy_timer中更新
static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
static int  mon_timer[4]={0,0,0,0}; // 軟驅(qū)到正常運(yùn)轉(zhuǎn)還需要的時(shí)間
static int moff_timer[4]={0,0,0,0}; // 馬達(dá)到停止運(yùn)轉(zhuǎn)還剩下的時(shí)刻
unsigned char current_DOR = 0x0C; // 數(shù)字輸出寄存器(初值:允許dma和中斷請(qǐng)求,啟動(dòng)fdc)
// oxoc -- 0000,1100
//----------------------------------------------------------------
// ticks_to_floppy_on
// 指定軟盤到正常運(yùn)轉(zhuǎn)所需的滴答數(shù)
// nr -- 軟盤驅(qū)動(dòng)號(hào),該函數(shù)返回的是滴答數(shù)
int ticks_to_floppy_on(unsigned int nr)
{
extern unsigned char selected; // 當(dāng)前選中軟盤號(hào)
// ox10 -- 0001, 0000
unsigned char mask = 0x10 << nr; // 所選軟盤對(duì)應(yīng)的數(shù)字輸出
// 寄存器啟動(dòng)馬達(dá)比特位
/*
* 數(shù)字輸出端口(數(shù)字控制端口)是一個(gè)8位寄存器,它控制驅(qū)動(dòng)器馬達(dá)開啟
* ,驅(qū)動(dòng)器選擇,啟動(dòng)和復(fù)位FDC,以及允許和禁止DMA及中斷請(qǐng)求。
* FDC的主狀態(tài)寄存器也是一個(gè)8位寄存器,用戶反映軟盤控制器FDC和軟盤
* 驅(qū)動(dòng)器FDD的基本狀態(tài)。通常,在CPU想FDC發(fā)送命令之前或者是從FDC獲得
* 操作結(jié)果之前,都要讀取主狀態(tài)寄存器的狀態(tài)位,以判定當(dāng)前的數(shù)據(jù)是否
* 準(zhǔn)備就緒,以及確定數(shù)據(jù)的傳輸方向
*
*/
if (nr>3) // 最多3個(gè)軟盤驅(qū)動(dòng)號(hào)
panic("floppy_on: nr>3");
moff_timer[nr]=10000; /* 100 s = very big :-) */
cli(); /* use floppy_off to turn it off 關(guān)中斷 */
mask |= current_DOR; // mask =
// 如果不是當(dāng)前軟驅(qū),則首先復(fù)位其它軟驅(qū)的選擇位,然后置對(duì)應(yīng)軟驅(qū)選擇位
if (!selected)
{
mask &= 0xFC; // 0xfc -- 1111,1100
mask |= nr;
}
if (mask != current_DOR) // 如果數(shù)字輸出寄存器的當(dāng)前值和要求不同
// 即是需要的狀態(tài)還沒有到達(dá)
{
outb(mask,FD_DOR); // 于是向FDC數(shù)字輸出端口輸出新值
if ((mask ^ current_DOR) & 0xf0) // 如果需要啟動(dòng)的馬達(dá)還沒有
// 啟動(dòng),則置相應(yīng)的軟驅(qū)馬達(dá)定
// 時(shí)器值(50個(gè)滴答數(shù))
mon_timer[nr] = HZ/2;
else if (mon_timer[nr] < 2)
mon_timer[nr] = 2;
current_DOR = mask; // 更新數(shù)字輸出寄存器的值current_DOR,即是反映
// 當(dāng)前的狀態(tài)
}
sti(); // 開中斷
return mon_timer[nr];
}
//--------------------------------------------------------------
// floppy_on
// 等待指定軟驅(qū)馬達(dá)啟動(dòng)所需時(shí)間,啟動(dòng)時(shí)間
void floppy_on(unsigned int nr)
{
cli(); // 關(guān)中斷
while (ticks_to_floppy_on(nr))// 還沒有到時(shí)間?
sleep_on(nr+wait_motor); // 為不可中斷睡眠狀態(tài)并放在
// 等待馬達(dá)運(yùn)行隊(duì)列中
sti(); // 開中斷
}
//---------------------------------------------------------------
// floppy_off
// 初始化數(shù)組moff_timer,即是表示置相應(yīng)軟驅(qū)馬達(dá)停轉(zhuǎn)定時(shí)器(3秒)
void floppy_off(unsigned int nr)
{
moff_timer[nr]=3*HZ;
}
//----------------------------------------------------------------
// do_floppy_timer
// 軟盤定時(shí)處理子程序。更新馬達(dá)啟動(dòng)定時(shí)值和馬達(dá)關(guān)閉停轉(zhuǎn)計(jì)時(shí)值。該子程序
// 是在時(shí)鐘定時(shí)中斷被調(diào)用,因此每一個(gè)滴答(10ms)被嗲用一次,更新馬達(dá)開啟
// 或者是停止轉(zhuǎn)動(dòng)定時(shí)器值。如果在某一個(gè)馬達(dá)停轉(zhuǎn)時(shí)刻到達(dá),那么則將數(shù)字輸出
// 寄存器馬達(dá)啟動(dòng)復(fù)位標(biāo)志
void do_floppy_timer(void)
{
int i;
unsigned char mask = 0x10;
for (i=0 ; i<4 ; i++,mask <<= 1) {
if (!(mask & current_DOR)) // 如果不是指定馬達(dá)
continue;
if (mon_timer[i])
{
if (!--mon_timer[i])// 如果馬達(dá)啟動(dòng)定時(shí)器到達(dá)
wake_up(i+wait_motor);//則喚醒進(jìn)程
} else if (!moff_timer[i]) { // 如果馬達(dá)停止運(yùn)轉(zhuǎn)時(shí)刻到達(dá)
current_DOR &= ~mask; // 復(fù)位相應(yīng)馬達(dá)啟動(dòng)位
outb(current_DOR,FD_DOR); // 更新數(shù)字輸出寄存器
} else
moff_timer[i]--; // 馬達(dá)停轉(zhuǎn)計(jì)時(shí)器遞減
}
}
#define TIME_REQUESTS 64
static struct timer_list {
long jiffies; // 定時(shí)滴答數(shù)
void (*fn)(); // 定時(shí)處理函數(shù)
struct timer_list * next;
} timer_list[TIME_REQUESTS], * next_timer = NULL;
//----------------------------------------------------------------------
// add_timer
// 增加定時(shí)器。輸入?yún)?shù)為指定的定時(shí)器的滴答數(shù)和相應(yīng)的處理函數(shù)指針。
// jiffies -- 以10ms計(jì)時(shí)的滴答數(shù)
// *fn() -- 定時(shí)時(shí)間到達(dá)時(shí)執(zhí)行函數(shù)
void add_timer(long jiffies, void (*fn)(void))
{
struct timer_list * p;
if (!fn) // 如果處理函數(shù)為空
return; // 退出
cli(); // 關(guān)中斷
if (jiffies <= 0) // 定時(shí)器到達(dá)
(fn)(); // 執(zhí)行函數(shù)fn
else { // 否則,從定時(shí)器數(shù)組中,找到一個(gè)空閑項(xiàng),使用fn來標(biāo)識(shí)
for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
if (!p->fn)
break;
// 當(dāng)上面的循環(huán)結(jié)束時(shí),可能存在p == timer_list + TIME_REQUESTS
if (p >= timer_list + TIME_REQUESTS) // 這樣的話,表明用完了數(shù)組
panic("No more time requests free");
// 將定時(shí)器數(shù)據(jù)結(jié)構(gòu)填入相應(yīng)信息
p->fn = fn;
p->jiffies = jiffies;
p->next = next_timer;
next_timer = p;
// 鏈表項(xiàng)按定時(shí)器值的大小排序。下面就是鏈表排序的實(shí)現(xiàn)。這樣的好處是
// 在查看是否有定時(shí)器到期時(shí),只需要查看鏈表的頭結(jié)點(diǎn)即可
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->jiffies = p->next->jiffies;
p->next->jiffies = jiffies;
p = p->next;
}
}
sti(); // 開中斷
}
//------------------------------------------------------------------------
// do_timer
// 時(shí)鐘中斷處理函數(shù),在/kernel/system_call.s中_timer_interrupt_中被調(diào)用
// 參數(shù)cpl是當(dāng)前的特權(quán)級(jí)0或3,0標(biāo)識(shí)在內(nèi)核代碼段運(yùn)行
// 對(duì)于一個(gè)進(jìn)程由于時(shí)間片用完,則進(jìn)行內(nèi)核任務(wù)切換。并進(jìn)行及時(shí)更新工作
void do_timer(long cpl)
{
extern int beepcount; // 揚(yáng)聲器發(fā)聲時(shí)間滴答數(shù)
extern void sysbeepstop(void); // 關(guān)閉揚(yáng)聲器
if (beepcount)
if (!--beepcount) // 如果揚(yáng)聲器計(jì)數(shù)次數(shù)到
sysbeepstop(); // 關(guān)閉發(fā)生器
if (cpl) // 如果實(shí)在內(nèi)核程序,即是超級(jí)用戶
current->utime++; // 超級(jí)用戶時(shí)間增加
else
current->stime++; // 普通用戶運(yùn)行時(shí)間增加
// 如果有用戶定時(shí)器存在的話,則將第一個(gè)定時(shí)器的值減去1,如果已經(jīng)等于0
// 那么調(diào)用函數(shù)fn,并將函數(shù)指針置為空值,然后去掉該定時(shí)器。注意的是上述
// 鏈表已經(jīng)排序,同時(shí)在尋找空閑結(jié)點(diǎn)時(shí),是通過fn是否為空來判斷的,所以
// 將fn置位null
if (next_timer)
{
next_timer->jiffies--;
while (next_timer && next_timer->jiffies <= 0) {
void (*fn)(void); //

// 刪除定時(shí)器
fn = next_timer->fn;
next_timer->fn = NULL;
next_timer = next_timer->next;
(fn)();
}
}
// 如果當(dāng)前軟盤控制器FDC的數(shù)字輸出寄存器馬達(dá)啟動(dòng)位有置位,則執(zhí)行相應(yīng)的
// 軟盤定時(shí)程序
if (current_DOR & 0xf0)
do_floppy_timer();
if ((--current->counter)>0) return; // 如果進(jìn)程運(yùn)行時(shí)間還沒有完,退出
current->counter=0;
if (!cpl) return; // 超級(jí)用戶程序,不依賴counter值來調(diào)度
schedule();
}
//----------------------------------------------------------------------
// sys_alarm
// 如果已經(jīng)設(shè)置了alarm的值,那么返回的是舊值,如果沒有設(shè)置返回0
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);
}
//-----------------------------------------------------------------------
// sys_getpid
// 取得當(dāng)前的進(jìn)程號(hào)
int sys_getpid(void)
{
return current->pid;
}
//----------------------------------------------------------------------
// sys_getppid
// 取得父進(jìn)程進(jìn)程號(hào)
int sys_getppid(void)
{
return current->father;
}
//-----------------------------------------------------------------------
// sys_getuid
// 取得用戶號(hào)uid
int sys_getuid(void)
{
return current->uid;
}
//------------------------------------------------------------------------
// sys_geteuid
// 取得用戶號(hào)euid
int sys_geteuid(void)
{
return current->euid;
}
//----------------------------------------------------------------------
// sys_getgid
// 取得組號(hào)gid
int sys_getgid(void)
{
return current->gid;
}
//----------------------------------------------------------------------
// sys_getegid
// 取得進(jìn)程的egid,有關(guān)egid的解釋,參見文檔<Linux 關(guān)于SUID和SGID的解釋.txt>
int sys_getegid(void)
{
return current->egid;
}
//--------------------------------------------------------------------
// sys_nice
// 改變進(jìn)程優(yōu)先級(jí)
int sys_nice(long increment)
{
if (current->priority-increment>0)
current->priority -= increment;
return 0;
}
//----------------------------------------------------------------------
// sched_init
// 調(diào)度程序初始化,即是初始化進(jìn)程0,init
void sched_init(void)
{
int i;
struct desc_struct * p;
if (sizeof(struct sigaction) != 16) // sigaction中存放的是信號(hào)狀態(tài)結(jié)構(gòu)
panic("Struct sigaction MUST be 16 bytes");
// 設(shè)置初始任務(wù)(任務(wù)0)的任務(wù)狀態(tài)描述符表和局部數(shù)據(jù)描述符表
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
// 清楚任務(wù)數(shù)組和描述符表項(xiàng)
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++;
}
/* Clear NT, so that we won't have troubles with that later on */
/* nt標(biāo)志置位的話,那么當(dāng)前的中斷任務(wù)執(zhí)行iret命令時(shí)引起任務(wù)的切換 */
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
ltr(0); // 將任務(wù)0的tss加載到寄存器
lldt(0); // 將局部描述符表加載到局部描述符表寄存器
// 是將gdt和相應(yīng)的ldt描述符的選擇符加載到ldtr。只是明確的加載這一次
// 以后任務(wù)的ldt加載,是cpu根據(jù)tss中的ldt自動(dòng)加載的
// 初始化8253定時(shí)器
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
// 設(shè)置時(shí)鐘中斷控制處理程序句柄
set_intr_gate(0x20,&timer_interrupt);
// 修改中斷控制器屏蔽碼,允許時(shí)鐘中斷
outb(inb_p(0x21)&~0x01,0x21);
// 設(shè)置系統(tǒng)調(diào)用中斷門
set_system_gate(0x80,&system_call);
}
/*
* 下面解釋linux的init進(jìn)程的整體認(rèn)識(shí)
* 1.在系統(tǒng)的啟動(dòng)階段時(shí),bootsect.s文件只是見將系統(tǒng)加載到內(nèi)存中,內(nèi)核都
* 沒有加載完成,談不上對(duì)于進(jìn)程管理的影響。setup.s中加載了全局的gdtr,
* 但是此時(shí)的gdt只是為了讓程序運(yùn)行在保護(hù)模式下,沒有什么作用。在setup.s
* 文件中設(shè)置的gdt的格式如下 :
*  -----------
*  | 0 0 0 0 |
*  -----------
*  | code seg|
*  ------------
*  | data seg|
*  -----------
*  |  ...... |
* 在head.s文件中還需要改寫該gdt。經(jīng)過該文件的修改后新生成的gdt如下:
*  -----------
*  | 0 0 0 0 |
*  -----------
*  |  code   |
*  -----------
*  |  data   |
*  -----------
*  |  system | -- do not use in linux
*  -----------
*  |         | -|
*  -----------  |--剩下的各項(xiàng)是預(yù)留給其他任務(wù),用于放置ldt和tss
*  |         | -|
*
* 在main.c文件中調(diào)用函數(shù)sched_init,此函數(shù)加載進(jìn)程init。
* 加載init進(jìn)程的ldt和tdd段
* |
* 由程序來執(zhí)行加載ldt和tss段寄存器的任務(wù)
* |
* 即實(shí)現(xiàn)init進(jìn)程的加載,即是手工創(chuàng)建的第一次進(jìn)程。
* 此時(shí)的gdt大概上講是:
*  ----------
*  | 0 0 0 0 |
*  -----------
*  | code    |
*  -----------
*  | data    |
*  -----------
*  | system  |
*  -----------
*  |   ldt0  |
*  -----------
*  |  tss0   |
*  -----------
*  | ...     |
* 此后,進(jìn)程使用fork系統(tǒng)調(diào)用來產(chǎn)生新的進(jìn)程,同時(shí)進(jìn)程調(diào)度開始起作用。
*
*/






歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: www亚洲精品 | 国产精品日韩在线观看 | 国产精品亚洲一区二区三区在线观看 | 免费的黄色片子 | 久久久久黑人 | 久久久天天 | 男人的天堂中文字幕 | 在线日韩av电影 | 国产成人高清成人av片在线看 | 亚洲第一成人av | 久久com | 9porny九色视频自拍 | 高清av电影 | 美女黄色在线观看 | 国产精品久久久久久久久久久久午夜片 | 91伊人| 自拍偷拍视频网 | 日韩字幕| 欧美日韩不卡合集视频 | 日本视频在线播放 | 国产中文 | 久久久精品一区二区三区 | 99re在线视频 | 欧美日韩成人一区二区 | 久久精品国产免费 | av一区二区三区四区 | 日韩中文字幕免费 | av日韩精品 | 国产乱码精品一区二区三区五月婷 | 一区在线观看 | 成人夜晚看av | 91亚洲精品久久久电影 | 欧美日高清视频 | 成人自拍视频 | 久久久久久高潮国产精品视 | 日韩久久久久 | av中文字幕在线观看 | 国产高清视频一区二区 | 美女久久 | avhd101在线成人播放 | 久久久久国产精品 |