進程管理源碼
『壹』 給我一個操作系統源代碼的下載地址
我勸你要是製作操作系統的話不要依靠那些免費的資源,買幾本書比什麼都好。linux源代碼我下載過,根本沒法看。你需要先明白操作系統的工作原理,熟練使用匯編+C語言才可能編寫出一個很爛的操作系統。給你推薦一本《30天自製操作系統》,不是打廣告,我看完也有很大收獲。裡面還有源代碼光碟。
你實在想要的話,可以用這個
網頁鏈接
這是Linux的內核代碼,你可以免費看。不過我估計你看到後已經崩潰了。
順便說一句,我其實早就看到過這個貼,而且我打賭你現在已經忘記這個了。
加油。
還有,在知道上提問,態度要好一點。
『貳』 如何查看linux系統源碼
一般在Linux系統中的/usr/src/linux*.*.*(*.*.*代表的是內核版本,如2.4.23)目錄下就是內核源代碼(如果沒有類似目錄,是因為還沒安裝內核代碼)。另外還可從互連網上免費下載。注意,不要總到http://www.kernel.org/去下載,最好使用它的鏡像站點下載。請在http://www.kernel.org/mirrors/里找一個合適的下載點,再到pub/linux/kernel/v2.6/目錄下去下載2.4.23內核。
代碼目錄結構
在閱讀源碼之前,還應知道Linux內核源碼的整體分布情況。現代的操作系統一般由進程管理、內存管理、文件系統、驅動程序和網路等組成。Linux內核源碼的各個目錄大致與此相對應,其組成如下(假設相對於Linux-2.4.23目錄):
1.arch目錄包括了所有和體系結構相關的核心代碼。它下面的每一個子目錄都代表一種Linux支持的體系結構,例如i386就是Intel CPU及與之相兼容體系結構的子目錄。PC機一般都基於此目錄。
2.include目錄包括編譯核心所需要的大部分頭文件,例如與平台無關的頭文件在include/linux子目錄下。
3.init目錄包含核心的初始化代碼(不是系統的引導代碼),有main.c和Version.c兩個文件。這是研究核心如何工作的好起點。
4.mm目錄包含了所有的內存管理代碼。與具體硬體體系結構相關的內存管理代碼位於arch/*/mm目錄下。
5.drivers目錄中是系統中所有的設備驅動程序。它又進一步劃分成幾類設備驅動,每一種有對應的子目錄,如音效卡的驅動對應於drivers/sound。
6.ipc目錄包含了核心進程間的通信代碼。
7.moles目錄存放了已建好的、可動態載入的模塊。
8.fs目錄存放Linux支持的文件系統代碼。不同的文件系統有不同的子目錄對應,如ext3文件系統對應的就是ext3子目錄。
Kernel內核管理的核心代碼放在這里。同時與處理器結構相關代碼都放在arch/*/kernel目錄下。
9.net目錄里是核心的網路部分代碼,其每個子目錄對應於網路的一個方面。
10.lib目錄包含了核心的庫代碼,不過與處理器結構相關的庫代碼被放在arch/*/lib/目錄下。
11.scripts目錄包含用於配置核心的腳本文件。
12.documentation目錄下是一些文檔,是對每個目錄作用的具體說明。
一般在每個目錄下都有一個.depend文件和一個Makefile文件。這兩個文件都是編譯時使用的輔助文件。仔細閱讀這兩個文件對弄清各個文件之間的聯系和依託關系很有幫助。另外有的目錄下還有Readme文件,它是對該目錄下文件的一些說明,同樣有利於對內核源碼的理解。
在閱讀方法或順序上,有縱向與橫向之分。所謂縱向就是順著程序的執行順序逐步進行;所謂橫向,就是按模塊進行。它們經常結合在一起進行。對於Linux啟動的代碼可順著Linux的啟動順序一步步來閱讀;對於像內存管理部分,可以單獨拿出來進行閱讀分析。實際上這是一個反復的過程,不可能讀一遍就理解。
『叄』 windows 進程管理源代碼詳解,要詳細的,
Windows 是閉源開發的商業軟體,受商業版權法保護,別說大家都沒有,就算有也不能給你的(被微軟起訴那可不是小事)。
Linux的是開源的,幹嘛不去讀Linux源碼呢?
新版本的太長,寫不開,給你最經典的0.11版的進程管理源碼。其他的你自己去查。作為一個好的程序員,必須學會充分利用搜索引擎。
---------------------------------------
linux0.11通過一個進程數組管理進程,最大允許64個進程存在。進程的狀態有就緒態,運行態,暫停態,睡眠態和僵死態等。睡眠態又可分為可中斷和不可中斷兩種。對於進程的管理,我覺得按照進程的狀態來講會清晰一些。
1.0號任務
0號比較特殊,是"純手工製作",下面就是製作過程
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
char_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti();
move_to_user_mode();
這么多init當然不全是為0任務准備的,他們是初始化系統。對任務0來說,重要的是sched_init()和move_to_user_mode()兩個。sched_init()中手動設置了任務0的任務段描述符tss和局部段描述符ldt,並設置了tr和ldtr寄存器:
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); //設置tss段描述符
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));//設置ldt描述符
...
ltr(0); //載入tss描述符地址到tr
lldt(0); //載入ldt描述符地址到ldtr
我們來看一下任務0的tss和ldt是什麼樣子
/*ldt*/ {0,0},\
{0x9f,0xc0fa00},\
{0x9f,0xc0f200},\
/*tss*/{0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
0,0,0,0,0,0,0,0,\
0,0,0x17,0x17,0x17,0x17,0x17,0x17,\
_LDT(0),0X80000000,\
{}\
},\
從ldt 可以看到,任務的代碼和數據段均為640k,基址為0,DPL=3。這說明雖然任務0的代碼還是處在內核段內,但是任務的級別已經是用戶態了。從tss也可以看到這一點,代碼和數據都被置為0x17,也就是局部段描述符表第2項。還可以看到任務0的內核太堆棧被設置在init_task之後的一頁處,用戶態堆棧就是move_to_user_mode之前的內核態堆棧。這和普通進程不一樣,普通進程的用戶態堆棧在其64Mb地址空間的末端。
move_to_user_mode是在堆棧中創建一個任務切換的假象,用iret跳轉到外層3,這樣cpu就會自動根據tr載入tss,並初始化各個寄存器運行任務0。所以,任務0其實就是內核空間中的用戶態任務。
2.進程的創建
進程創建是由系統調用sys_fork完成的,主要使用了兩個函數find_empty_process和_process。前者在進程在進程數組中找一個不用的進程號給子進程,後者完成子進程信息的創建,主要是復制父進程的信息。
我們來看一下_process的代碼:
int _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)
{
struct task_struct *p;
int i;
struct file *f;
//首先為子進程的進程描述符分配一塊內存
p=(struct task_struct *)get_free_page();
if(!p)
return -EAGAIN;
//將新任務結構指針加入數組中
task[nr]=p;
//復制當前用戶的任務結構到子進程中。當然堆棧不復制
*p=*current;
//將子進程的狀態設為不可中斷等待,防止現在被調度
p->state=TASK_UNINTERRUPTIBLE;
P->pid=last_pid;
p->father=current->pid;
p->count=p->priority;
p->signal=0;
p->alarm=0;
p->leader=0;
p->utime=p->stime=0;
p->cutime=p->cstime=0;
p->start_time=jiffies;
p->tss.back_link=0;
//新進程的內核態堆棧在進程描述符頁末端
p->tss.esp0=PAGE_SIZE+(long)p;
P->tss.ss0=0x10;
//ip為父進程調用fork的下一條指令
p->tss.eip=eip;
//fork的返回值對子進程來說是0,對父進程來說是它的pid,通過這個區別,在fork調用返回後,父子進程的代碼段便被分割來,
p->tss.eax=0;
//雖然他們是在一個代碼文件中寫的
p->tss.ecx=ecx;
p->tss.edx=edx;
p->tss.ebx=ebx;
p->tss.esp=esp;
p->tss.ebp=ebp;
p->tss.esi=esi;
p->tss.edi=edi;
p->tss.es=es&0xffff;
p->tss.cs=cs&0xffff;
p->tss.ss=ss&0xffff;
p->tss.ds=ds&0xffff;
p->tss.fs=fs&0xffff;
p->tss.gs=gs&0xffff;
p->tss.ldt=_LDT(nr);
p->tss.trace_bitmap=0x80000000;
//如果父任務使用了協處理器,還要保存到tss中
if(last_task_used_math==current)
_asm("clts;fnsave %0"::"m"(p->tss.i387));
//為新任務設置新的代碼和數據段基地址。注意,因為linux0.11隻支持64M的進程空間,所以進程的線性地址空間在64M的邊界處。
//然後為新任務復制父進程的頁表。通過_page_tales,父子任務此時共用一個只讀的代碼數據段。在寫操作時,寫時復制會為新進程申請新的物理頁面。
if(_mem(nr,p)){
task[nr]=NULL;
free_page((long)p);
return -EAGAIN;
}
for(i=0;i<NR_OPEN;i++)
if(f=p->filp)
f->f_count++;
if(current->pwd)
current->pwd->i_count++;
if(current->root)
current->root->i_count++;
if(current->executable)
current->executable->i_count++;
//設置新任務的tss和ldt描述符
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
//返回子進程的pid
return last_pid;
}
參數都是堆棧中的值,nr是調用_process之前的find_empty_process的返回值,作為任務數組的序號。
3.進程的調度
進程創建之後並不是立即執行。系統會在適當的時刻調用系統調度函數schele,它會選擇適當的進程運行。調度函數可能在系統調用結束之後,進程暫停/ 睡眠/退出,時鍾中斷等多個地方調用。調度函數主要是通過進程的時間片來選擇一個運行時間最短的進程運行。如果沒有找到就運行空閑pause系統調用,在 Pause中,調度函數又會被調用。下面是主要代碼
while(1){
c=-1;
next=0;
i=NR_TASKS;
p=&task[NR_TASKS];
//尋找就緒任務中運行時間最短的任務
while(--i){
if(!(*--p))
continue;
if((*p)->state==TASK_RUNNING&&(*p)->counter>c)
c=(*p)->counter,next=i;
}
//如果找到,就退出。否則重新計算任務的時間片。注意,如果沒有任務,next始終為0,結果就被切換到任務0
if(c)break;
for(p=&LAST_TASK;p>&FIRST_TASK;--p)
if(*p)
(*p)->counter=((*p)->counter>>1)+(*)->priority;
}
switch_to(next);//通過長跳轉,轉換任務到新任務。
}
時鍾中斷是執行調度的重要措施,正是由於不斷的執行調度,系統才能在多個任務之間進行切換,完成多任務操作系統的目標。在調度器初始化時,除了手動設置了任務0,還對8253開啟了定時器中斷,對系統"點火".中斷中調用了do_timer函數。現在這是個很短的函數:
void do_timer(long cpl)
{
...
//根據優先順序調整進程運行時間
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)();
}
}
..
//對進程時間片減1。如果大於0 ,表示時間片還沒有用完,繼續
if((--current->counter>0)return;
//注意,內核態任務是不可搶占的,在0.11中,除非內核任務主動放棄處理器,它將一直運行。
if(!cpl)return;
//調度
schele();
}
4.進程的終止
進程可以自己中止,也可以被中止信號中止。do_exit執行退出。如果它有子進程的話,子進程就會成為孤兒進程,這里會將它的孩子託付給進程1(即init進程)管理。在成為僵死進程之後,還要通知父進程,因為他的父進程可能在等它呢。
『肆』 如何查看 linux 內核源代碼
Linux的內核源代碼可以從很多途徑得到。一般來講,在安裝的linux系統下,/usr/src/linux目錄下的東西就是內核源代碼。
對於源代碼的閱讀,要想比較順利,事先最好對源代碼的知識背景有一定的了解。對於linux內核源代碼來講,我認為,基本要求是:1、操作系統的基本知識;2、對C語言比較熟悉,最好要有匯編語言的知識和GNU C對標准C的擴展的知識的了解。另外在閱讀之前,還應該知道Linux內核源代碼的整體分布情況。我們知道現代的操作系統一般由進程管理、內存管理、文件系統、驅動程序、網路等組成。看一下Linux內核源代碼就可看出,各個目錄大致對應了這些方面。Linux內核源代碼的組成如下(假設相對於linux目錄):
arch 這個子目錄包含了此核心源代碼所支持的硬體體系結構相關的核心代碼。如對於X86平台就是i386。
include 這個目錄包括了核心的大多數include文件。另外對於每種支持的體系結構分別有一個子目錄。
init 此目錄包含核心啟動代碼。
mm 此目錄包含了所有的內存管理代碼。與具體硬體體系結構相關的內存管理代碼位於arch/*/mm目錄下,如對應於X86的就是arch/i386/mm/fault.c 。
drivers 系統中所有的設備驅動都位於此目錄中。它又進一步劃分成幾類設備驅動,每一種也有對應的子目錄,如音效卡的驅動對應於drivers/sound。
ipc 此目錄包含了核心的進程間通訊代碼。
moles 此目錄包含已建好可動態載入的模塊。
fs Linux支持的文件系統代碼。不同的文件系統有不同的子目錄對應,如ext2文件系統對應的就是ext2子目錄。
kernel 主要核心代碼。同時與處理器結構相關代碼都放在arch/*/kernel目錄下。
net 核心的網路部分代碼。裡面的每個子目錄對應於網路的一個方面。
lib 此目錄包含了核心的庫代碼。與處理器結構相關庫代碼被放在arch/*/lib/目錄下。
scripts此目錄包含用於配置核心的腳本文件。
Documentation 此目錄是一些文檔,起參考作用。
俗話說:「工欲善其事,必先利其器」。 閱讀象Linux核心代碼這樣的復雜程序令人望而生畏。它象一個越滾越大的雪球,閱讀核心某個部分經常要用到好幾個其他的相關文件,不久你將會忘記你原來在干什麼。所以沒有一個好的工具是不行的。由於大部分愛好者對於Window平台比較熟悉,並且還是常用Window系列平台,所以在此我介紹一個Window下的一個工具軟體:Source Insight。這是一個有30天免費期的軟體,可以從www.sourcedyn.com下載。安裝非常簡單,和別的安裝一樣,雙擊安裝文件名,然後按提示進行就可以了。安裝完成後,就可啟動該程序。這個軟體使用起來非常簡單,是一個閱讀源代碼的好工具。它的使用簡單介紹如下:先選擇Project菜單下的new,新建一個工程,輸入工程名,接著要求你把欲讀的源代碼加入(可以整個目錄加)後,該軟體就分析你所加的源代碼。分析完後,就可以進行閱讀了。對於打開的閱讀文件,如果想看某一變數的定義,先把游標定位於該變數,然後點擊工具條上的相應選項,該變數的定義就顯示出來。對於函數的定義與實現也可以同樣操作。別的功能在這里就不說了,有興趣的朋友可以裝一個Source Insight,那樣你閱讀源代碼的效率會有很大提高的。怎麼樣,試試吧!