




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
《Linux內(nèi)核分析》實(shí)驗(yàn)指導(dǎo)書10《Linux內(nèi)核分析》課程試驗(yàn)指導(dǎo)書
試驗(yàn)一、進(jìn)程管理試驗(yàn)
1、加深對(duì)進(jìn)程概念的理解,明確進(jìn)程和程序的區(qū)分
2、進(jìn)一步熟悉并發(fā)執(zhí)行的實(shí)質(zhì)
3、分析進(jìn)程爭用資源的現(xiàn)象,學(xué)習(xí)理解進(jìn)程互斥的方法
4、了解linux系統(tǒng)中進(jìn)程通信的基本原理
編寫一段程序,實(shí)現(xiàn)軟中斷通信。
使用系統(tǒng)調(diào)用fork()創(chuàng)建兩個(gè)子進(jìn)程,再用系統(tǒng)調(diào)用signal()讓父進(jìn)程捕獲鍵盤上發(fā)出的中斷信號(hào)(即按Del鍵),當(dāng)父進(jìn)程接受到這兩個(gè)軟中斷的其中某一個(gè)后,父進(jìn)程用系統(tǒng)調(diào)用kill()向兩個(gè)子進(jìn)程分別發(fā)送整數(shù)值為16和17軟中斷信號(hào),子進(jìn)程獲得對(duì)應(yīng)軟中斷信號(hào),然后分別輸出下列信息后終止:
Childprocess1iskilledbyparent!!Childprocess2iskilledbyparent!!
父進(jìn)程調(diào)用wait()函數(shù)等待兩個(gè)子進(jìn)程終止后,輸出以下信息,結(jié)束進(jìn)程執(zhí)行:Parentprocessiskilled!!
多運(yùn)行幾次編寫的程序,簡略分析消失不同結(jié)果的緣由。
(1)算法流程圖(圖1-1)
圖1-1軟中斷通信程序流程圖(2)參考程序源代碼
#include
#include
#include
#include
intwait_flag;
voidstop();
main()
{
intpid1,pid2;//定義兩個(gè)進(jìn)程號(hào)變量
signal(3,stop);//或者signal(14,stop);
while((pid1=fork())==-1);//若創(chuàng)建子進(jìn)程1不勝利,則空循環(huán)。if(pid1>0){//子進(jìn)程創(chuàng)建勝利,pid1為進(jìn)程號(hào)
while((pid2=fork())==-1);//創(chuàng)建子進(jìn)程2
if(pid2>0){
wait_flag=1;
sleep(5);//父進(jìn)程等待5秒
kill(pid1,16);//殺死進(jìn)程1
kill(pid2,17);//殺死進(jìn)程2
wait(0);//等待子進(jìn)程1結(jié)束的信號(hào)
wait(0);//等待子進(jìn)程2結(jié)束的信號(hào)
printf(“\nParentprocessiskilled!!\n”);
exit(0);//父進(jìn)程結(jié)束
}
else{
wait_flag=1;
signal(17,stop);//等待進(jìn)程2被殺死的中斷號(hào)17printf(“\nChildprocess2iskilledbyparent!!\n”);
exit(0);
}
}
else{
wait_flag=1;
signal(16,stop);//等待進(jìn)程1被殺死的中斷號(hào)16printf(“\nChildprocess1iskilledbyparent!!\n”);
exit(0);
}
}
voidstop(){
wait_flag=0;
}
(3)程序運(yùn)行結(jié)果
編譯運(yùn)行后,等待從鍵盤輸入“Del”,有如下結(jié)果:Childprocess1iskilledbyparent!!Childprocess2iskilledbyparent!!Parentprocessiskilled!!
或者:(運(yùn)行多次后會(huì)消失如下結(jié)果)
Childprocess2iskilledbyparent!!
Childprocess1iskilledbyparent!!
Parentprocessiskilled!!
試驗(yàn)二、模塊編程試驗(yàn)
通過學(xué)習(xí)內(nèi)核模塊的編寫和運(yùn)行,了解模塊是LinuxOS的一種特有的機(jī)制,可依據(jù)用戶的實(shí)際需要在不需要對(duì)內(nèi)核進(jìn)行重新編譯的狀況下,模塊能在內(nèi)核中被動(dòng)態(tài)地加載和卸載。編寫一個(gè)模塊,將它作為LinuxOS內(nèi)核空間的擴(kuò)展來執(zhí)行,并通過insmod命令來手工加載,通過命令rmmod來手工卸載。
Linux模塊是一些可以作為獨(dú)立程序來編譯的函數(shù)和數(shù)據(jù)類型的集合。在裝載這些模塊時(shí),將它的代碼鏈接到內(nèi)核中。Linux模塊有兩種裝載方式:靜態(tài)裝載(內(nèi)核啟動(dòng)時(shí)裝載)和動(dòng)態(tài)裝載(在內(nèi)核運(yùn)行過程中裝載)。若在模塊裝載之前就調(diào)用了動(dòng)態(tài)模塊的一個(gè)函數(shù),則此調(diào)用將失敗;若模塊已被裝載,則內(nèi)核就可以使用系統(tǒng)調(diào)用,并將其傳遞到模塊中的相應(yīng)函數(shù)。模塊通常用來實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)程序(這要求模塊的API和設(shè)備驅(qū)動(dòng)程序的API相全都)。模塊可用來實(shí)現(xiàn)所期望的任何功能。
一、模塊的組織結(jié)構(gòu)
模塊一旦被裝載進(jìn)系統(tǒng),就在內(nèi)核地址空間中管態(tài)下執(zhí)行。它就像任何標(biāo)準(zhǔn)的內(nèi)核代碼一樣成為內(nèi)核的一部分,并擁有其它內(nèi)核代碼相同的權(quán)限和職責(zé)(當(dāng)然也會(huì)引起系統(tǒng)的崩潰)。若模塊知道內(nèi)核數(shù)據(jù)結(jié)構(gòu)的地址,則它可以讀寫內(nèi)核數(shù)據(jù)結(jié)構(gòu)。但Linux是一個(gè)整體式的內(nèi)核(monolithickernel)結(jié)構(gòu),整個(gè)內(nèi)核是一個(gè)單獨(dú)的且非
常大的程序,從而存在一個(gè)普遍的問題:在一個(gè)文件中實(shí)現(xiàn)的函數(shù)可能需要在其它文
件中定義的數(shù)據(jù)。在傳統(tǒng)的程序中,這個(gè)問題是通過鏈接編輯器在生成可執(zhí)行對(duì)象文
件時(shí),使用鏈接編輯器可以解析的外部(全局)變量來解決的。又由于模塊的設(shè)計(jì)和
實(shí)現(xiàn)與內(nèi)核無關(guān),所以模塊不能靠靜態(tài)鏈接通過變量名引用內(nèi)核數(shù)據(jù)結(jié)構(gòu)。恰好相反,
Linux內(nèi)核采納了另外一種機(jī)制:實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)的文件可以導(dǎo)出結(jié)構(gòu)的符號(hào)名(可以
從文件/proc/ksyms或文件/…/kernel/ksyms.c中以文本方式讀取這個(gè)公開符號(hào)表),
這樣在運(yùn)行時(shí)就可以使用這個(gè)結(jié)構(gòu)了。不過在編寫模塊的過程中,編寫(修改)導(dǎo)出
變量時(shí)要非常留意,由于通過修轉(zhuǎn)變量會(huì)修改內(nèi)核的狀態(tài),其結(jié)果可能并不是內(nèi)核設(shè)
計(jì)者所期望的。在確信自己了解修改內(nèi)核變量的后果之前,應(yīng)當(dāng)對(duì)這些變量只進(jìn)行讀
操作。
模塊作為一種抽象數(shù)據(jù)類型,它具有一個(gè)可以通過靜態(tài)內(nèi)核中斷的接口。最小的
模塊結(jié)構(gòu)必需包括兩個(gè)函數(shù),它們?cè)谙到y(tǒng)裝載模塊和卸載模塊時(shí)調(diào)用,分別是
init_module()和cleanup_module()。可以編寫一個(gè)只包括這兩個(gè)函數(shù)的模塊,這樣
該模塊中唯一會(huì)被調(diào)用的函數(shù)就是模塊被裝載時(shí)所調(diào)用的函數(shù)init_module()和模塊
被卸載時(shí)所調(diào)用的函數(shù)cleanup_module()。并且用函數(shù)init_module()來啟動(dòng)模塊裝
載期間的操作,用函數(shù)cleanup_module()來停止這些操作。
由于模塊可以實(shí)現(xiàn)相當(dāng)簡單的功能,故可以在模塊中加入許多新函數(shù)以實(shí)現(xiàn)所要
期望的功能。不過加入模塊的每個(gè)新函數(shù)都必需在該模塊裝載到內(nèi)核中時(shí)進(jìn)行注冊(cè)。
若該模塊是靜態(tài)裝載的,則該模塊的全部函數(shù)都是在內(nèi)核啟動(dòng)時(shí)進(jìn)行注冊(cè)的;若該模
塊是動(dòng)態(tài)裝載的,則這些新函數(shù)必需在裝載這個(gè)模塊時(shí)動(dòng)態(tài)注冊(cè)。當(dāng)然,假如該模塊
被動(dòng)態(tài)卸載了,則該模塊的函數(shù)都必需從系統(tǒng)中注銷。通過這種方式,當(dāng)這個(gè)模塊不
在系統(tǒng)中時(shí),就不能調(diào)用該模塊的函數(shù)。其中注冊(cè)工作通常是在函數(shù)init_module()
中完成的,而注銷工作通常是在函數(shù)cleanup_module()中完成的。
由上述定義的模塊應(yīng)有如下的格式:
#include#include……//其它header信息
intinit_module(){……//裝載時(shí),初始化模塊的編碼
}……
……//期望該模塊所能實(shí)現(xiàn)的一些功能函數(shù),如open()、release()、
write()、
//read()、ioctl()等函數(shù)
……
voidcleanup_module()
{……//卸載時(shí),注銷模塊的編碼
}
二.模塊的編譯
一旦設(shè)計(jì)并編寫好模塊,必需將其編譯成一個(gè)適合內(nèi)核裝載的對(duì)象文件。由于編
寫模塊是用C語言來完成的,故采納gcc編譯器來進(jìn)行編譯。若需要通知編譯程序把
這個(gè)模塊作為內(nèi)核代碼而不是一般的用戶代碼來編譯,則就需向gcc編譯器傳遞參數(shù)
“-D__KERNEL__”;若需要通知編譯程序這個(gè)文件是一個(gè)模塊而不是一個(gè)一般文件,
則就需向gcc編譯器傳遞參數(shù)“-DMODULE”;若需要對(duì)模塊程序進(jìn)行優(yōu)化編譯、連接,
則就需使用“-O2”參數(shù);若還需要對(duì)裝載后的模塊進(jìn)行調(diào)試,則就需使用“-g”參
數(shù);同時(shí)需要使用“-Wall”參數(shù)來向裝載程序傳遞all,使用“-c”開關(guān)通知編譯程
序在編譯完這個(gè)模塊文件后不調(diào)用鏈接程序。
一般編譯模塊文件的命令格式如下:
#gcc-O2-g-Wall-DMODULE-D__KERNEL__-cfilename.c//filename.c為自己編寫的模塊程序源代碼文件
執(zhí)行命令后就會(huì)得到文件filename.o,該文件就是一個(gè)可裝載的目標(biāo)代碼文件。
三.模塊的裝載
內(nèi)核模塊的裝載方式有兩種。一種是使用insmod命令手工裝載模塊;另一種是
懇求裝載demandloading(在需要時(shí)裝載模塊),即當(dāng)有必要裝載某個(gè)模塊時(shí),若用
戶安裝了核心中不存在的文件系統(tǒng)時(shí),核心將懇求內(nèi)核守護(hù)進(jìn)程kerneld預(yù)備裝載適
當(dāng)?shù)哪K。該內(nèi)核守護(hù)進(jìn)程是一個(gè)帶有超級(jí)用戶權(quán)限的一般用戶進(jìn)程。此試驗(yàn)中我們
主要采納insmod命令手工裝載模塊。
系統(tǒng)啟動(dòng)時(shí),kerneld開頭執(zhí)行,并為內(nèi)核打開一個(gè)IPC通道,內(nèi)核通過向kerneld
發(fā)送消息懇求執(zhí)行各種任務(wù)。kerneld的主要功能是裝載和卸載內(nèi)核模塊,kerneld
自身并不執(zhí)行這些任務(wù),它通過某些程序(如insmod)來完成。Kerneld只是內(nèi)核的
代理,只為內(nèi)核進(jìn)行調(diào)度。
insmod程序必需找到懇求裝載的內(nèi)核模塊(該懇求裝載的模塊一般被保存在
/lib/modules/kernel-version中)。這些模塊與系統(tǒng)中其它程序一樣是已連接的目標(biāo)
文件,但不同的是它們被連接成可重定位映象(即映象沒有被連接到在特定的地址上
運(yùn)行,其文件格式是a.out或ELF)。亦就是說,模塊在用戶空間(使用適當(dāng)?shù)臉?biāo)志)
進(jìn)行編譯,結(jié)果產(chǎn)生一個(gè)可執(zhí)行格式的文件。在用insmod命令裝載一個(gè)模塊時(shí),將
會(huì)發(fā)生如下大事:
(1)新模塊(通過內(nèi)核函數(shù)create_module())加入到內(nèi)核地址空間。
(2)insmod執(zhí)行一個(gè)特權(quán)級(jí)系統(tǒng)調(diào)用get_kernel_syms()函數(shù)以找到內(nèi)核的輸
出符號(hào)(一個(gè)符號(hào)表示為符號(hào)名和符號(hào)值,如地址值)。
(3)create_module()為這個(gè)模塊安排內(nèi)存空間,并將新模塊添加在內(nèi)核模塊鏈
表的尾部,然后將新模塊標(biāo)記為UNINITIALIZED(模塊未初始化)。
(4)通過init_module()系統(tǒng)調(diào)用裝載模塊。(該模塊定義的符號(hào)在此時(shí)被導(dǎo)出,供其它可能后來裝載的模塊使用)
(5)insmod為新裝載的模塊調(diào)用init_module()函數(shù),然后將新模塊標(biāo)志為RUNNING(模塊正在運(yùn)行)。
在執(zhí)行完insmod命令后,就可在/proc/modules文件中看到裝載的新模塊了。(為證明其正確性,可在執(zhí)行insmod命令之前先查看/proc/modules文件,執(zhí)行之后再查看比較)
四.模塊的卸載
當(dāng)一個(gè)模塊不需要使用時(shí),可以使用rmmod命令卸載該模塊。由于無需連接,故它的任務(wù)比加載模塊要簡潔得多。但假如懇求裝載模塊在其使用計(jì)數(shù)為0時(shí),kerneld將自動(dòng)從系統(tǒng)中卸載該模塊。卸載時(shí)調(diào)用模塊的cleanup_module()釋放安排給該模塊的內(nèi)核資源,并將其標(biāo)志為DELETED(模塊被卸載);同時(shí)斷開內(nèi)核模塊鏈表中的連接,修改它所依靠的其它模塊的引用,重新安排模塊所占的內(nèi)核內(nèi)存。
五.模塊連接到內(nèi)核的示意圖
該圖比較明顯地展現(xiàn)了模塊連接到內(nèi)核所使用的命令和函數(shù),以及各個(gè)函數(shù)之間的調(diào)用關(guān)系。通過該圖,可以比較清楚地看出模塊連接到內(nèi)核的整個(gè)連接過程,這也有助于內(nèi)核模塊的編寫。
六.模塊程序中管理模塊的幾個(gè)文件操作
在內(nèi)核內(nèi)部用一個(gè)file結(jié)構(gòu)來識(shí)別模塊,而且內(nèi)核使用file_operatuions結(jié)構(gòu)
來訪問模塊程序中的函數(shù)。file_operatuions結(jié)構(gòu)是一個(gè)定義在中的函
數(shù)指針表。管理模塊的文件操作,通常也稱為“方法”,它們都為struct
file_operations供應(yīng)函數(shù)指針。在structfile_operations中的操作一般按如下順
序消失,除非說明,它們返回0值時(shí)表示訪問勝利;發(fā)生錯(cuò)誤時(shí)返回一個(gè)負(fù)的錯(cuò)誤值
(目前共有13個(gè)操作):
int(*lseek)()、int(*read)()、int(*write)()、int(*readdir)()、int
(*select)()、int(*ioctl)()、int(*mmap)()、int(*open)()、void(*release)()、
int(*fsync)()、int(*fasync)()、int(*check_media_change)()、int
(*revalidate)()下面我們只簡潔介紹其中的幾個(gè)操作,其它在以后涉準(zhǔn)時(shí)再介紹:
1、方法int(*read)(structinode*,structfile*,char*,int)
該方法用來從模塊中讀取數(shù)據(jù)。當(dāng)其為NULL指針時(shí)將引起read系統(tǒng)調(diào)用返回
-EINVAL(“非法參數(shù)”)。函數(shù)返回一個(gè)非負(fù)值表示勝利地讀取了多少字節(jié)。
2、方法int(*write)(structinode*,structfile*,constchar*,int)
該方法用來向模塊發(fā)送數(shù)據(jù)。當(dāng)其為NULL指針時(shí)將引起write系統(tǒng)調(diào)用返回
-EINVAL。假如函數(shù)返回一個(gè)非負(fù)值,則表示勝利地寫入了多少字節(jié)。
3、方法int(*open)(structinode*,structfile*)
該方法是用來打開模塊的操作,它是操作在模塊節(jié)點(diǎn)上的第一個(gè)操作,即使這樣,
該方法還是可以為NULL指針。假如為NULL指針,則表示該模塊的打開操作永久勝利,
但系統(tǒng)不會(huì)通知你的模塊程序。
4、方法void(*release)(structinode*,structfile*)
該方法是用來關(guān)閉模塊的操作。當(dāng)節(jié)點(diǎn)被關(guān)閉時(shí)就調(diào)用這個(gè)操作。與open類似,
release也可以為NULL指針。
當(dāng)在你的模塊中需要上面這些方法時(shí),相應(yīng)的方法若沒有,則在struct
file_operations中相應(yīng)的地方將其令為NULL指針。這樣我們需要的也許象下面這樣:structfile_operationsmodulename_fops={NULL,//modulename_lseekmodulename_read,modulename_write,NULL,//modulename_readdirNULL,//modulename_select
NULL,//modulename_ioctlNULL,//modulename_mmapmodulename_open,modulename_release,NULL,//modulename_fsyncNULL,//modulename_fasyncNULL,//modulename_check_media_changeNULL//modulename_revalidate}
1、編寫一個(gè)簡潔的內(nèi)核模塊,該模塊至少需要有兩個(gè)函數(shù):一個(gè)是init_module()
函數(shù),在把模塊裝載到內(nèi)核時(shí)被調(diào)用,它為內(nèi)核的某些東西注冊(cè)一個(gè)處理程序,或是
用自身的代碼取代某個(gè)內(nèi)核函數(shù);另一個(gè)是cleanup_module()函數(shù),在卸載模塊時(shí)被
調(diào)用,其任務(wù)是清除init_module()函數(shù)所做的一切操作。編寫完成后進(jìn)行該模塊的
編譯、裝載和卸載操作。
2、向上面模塊中再添加一些新函數(shù),如open()、release()、write()和read()
函數(shù),并編寫一個(gè)函數(shù)來測試你的模塊能否實(shí)現(xiàn)自己添加的函數(shù)的功能。其中open()、
release()和write()函數(shù)都可以是空操作或較少的操作,它們僅僅為結(jié)構(gòu)
file_operations供應(yīng)函數(shù)指針。
一、一個(gè)簡潔的內(nèi)核模塊
1、必要的header文件:
除了前面講到的頭文件#include和#include
外,假如你的內(nèi)核打開了版本檢查,那么我們就還必需增加頭文件
#include,否則就會(huì)出錯(cuò)。
2、init_module()函數(shù):
由于題目的要求不高,故可只在該函數(shù)里完成一個(gè)打印功能,如printk(“Hello!
Thisisatestingmodule!\n”);等。為便于檢查模塊是否裝載勝利,我們可以給
一個(gè)返回值,如return0;若返回一個(gè)非0值,則表示init_module()失敗,從而不
能裝載模塊。
3、cleanup_module()函數(shù):
只需用一條打印語句來取消init_module()函數(shù)所做的打印功能操作就可以了,
如printk(“Sorry!Thetestingmoduleisunloadednow!\n”);等。
4、模塊的編寫:
此處把該模塊文件取名為testmodule.c#include//在內(nèi)核模塊中共享
#include//一個(gè)模塊
//處理CONFIG_MODVERSIONS#ifCONFIG_MODVERSIONS==1#defineMODVERSIONS#include#endifintinit_module()//初始化模塊
{printk(“Hello!Thisisatestingmodule!\n”);
return0;
}voidcleanup_module()//取消init_module()函數(shù)所做的打印功能操作
{printk(“Sorry!Thetestingmoduleisunloadingnow!\n”);
}
5、模塊的編譯、裝載和卸載:
#gcc–O2–Wall–DMODULE–D__KERNEL__-ctestmodule.c#ls–s//在當(dāng)前名目下查看生成的目標(biāo)文件testmodule.o現(xiàn)在,模塊testmodule已經(jīng)編譯好了。用下面命令將它裝載到系統(tǒng)中:
#insmod–ftestmodule.o
假如裝載勝利,則在/proc/modules文件中就可看到模塊testmodule,并可看到
它的主設(shè)備號(hào)。同時(shí)在終端顯示:
Hello!Thisisatestingmodule!
假如要卸載,就用如下命令:
#rmmodtestmodule
假如卸載勝利,則在/proc/devices文件中就可看到模塊testmodule已經(jīng)不存在
了。同時(shí)在終端顯示:
Sorry!Thetestingmoduleisunloadingnow!
二、向testmodule模塊中添加新函數(shù)open()、release()、write()和read()
1、函數(shù)open()
intopen(structinode*inode,structfile*filp){MOD_INC_USE_COUNT;//增加該模塊的用戶數(shù)目
printk(“Thismoduleisinopen!\n”);
return0;
}
2、函數(shù)release()
voidrelease(structinode*inode,structfile*filp)
{MOD_DEC_USE_COUNT;//該模塊的用戶數(shù)目減1printk(“Thismoduleisinrelease!\n”);
return0;
#ifdefDEBUGprintk(“release(%p,%p)\n”,inode,filp);
#endif}
3、函數(shù)read()
intread(structinode*inode,structfile*filp,char*buf,intcount)
{
intleave;
if(verify_area(VERIFY_WRITE,buf,count)==DEFAULT)returnDEFAULT;
for(leave=count;leave>0;leave--)
{
__put_user(1,buf,1);
buf++;
}
returncount;
}
4、函數(shù)write()
intwrite(structinode*inode,structfile*filp,constchar*buf,int
count){returncount;
}三、模塊的測試
在該模塊程序編譯加載后,再在/dev名目下創(chuàng)建模塊設(shè)備文件moduledev,使用
命令:#mknod/dev/moduledevcmajorminor,其中“c”表示moduledev是
字符設(shè)備,“major”是moduledev的主設(shè)備號(hào)。(該字符設(shè)備驅(qū)動(dòng)程序編譯加載后,
可在/proc/modules文件中獲得主設(shè)備號(hào),或者使用命令:#cat
/proc/modules|awk”\\$2==\”moduledev\”{print\\$1}”獲得主設(shè)備號(hào))
#include#include#include#includemain(){inti,testmoduledev;
charbuf;
testmoduledev=open(“/dev/moduledev”,O_RDWR);
if(testmoduledev==-1){printf(“Can’topenthefile!\n”);
exit(0);
}read(testmoduledev,buf,10);
for(i=0;i<10;i++)printf(“%d\n”,buf);
close(testmoduledev);
return0;
}
試驗(yàn)三、定時(shí)器試驗(yàn)
1、把握Linux下的定時(shí)器編程方法;
2、把握Linux下的常用時(shí)間函數(shù)編程方法。
1、編寫定時(shí)器程序timer;
2、編寫Makefile文件;
3、下載并調(diào)試timer。
1、C語言的基礎(chǔ)學(xué)問;
2、程序調(diào)試的基礎(chǔ)學(xué)問和方法;
3、Linux的基本操作;
4、把握Linux下的程序編譯與交叉編譯過程;
5、把握Linux下基本的應(yīng)用程序編寫方法。
操作系統(tǒng)應(yīng)當(dāng)能夠在將來某個(gè)時(shí)刻準(zhǔn)時(shí)調(diào)度某個(gè)任務(wù)。所以需要一種能保證任務(wù)較準(zhǔn)時(shí)調(diào)度運(yùn)行的機(jī)制。盼望支持每種操作系統(tǒng)的微處理器必需包含一個(gè)可周期性中斷它的可編程間隔定時(shí)器。這個(gè)周期性中斷被稱為系統(tǒng)時(shí)鐘滴答,它象節(jié)拍器一樣來組織系統(tǒng)任務(wù)。Linux的時(shí)鐘觀念很簡潔:它表示系統(tǒng)啟動(dòng)后的以時(shí)鐘滴答記數(shù)的時(shí)間。全部的系統(tǒng)時(shí)鐘都基于這種量度,在系統(tǒng)中的名稱和一個(gè)全局變量相同-jiffies。
Linux包含兩種類型的系統(tǒng)定時(shí)器,它們都可以在某個(gè)系統(tǒng)時(shí)間上被隊(duì)列例程使用,但是它們的實(shí)現(xiàn)稍有區(qū)分。
第一個(gè)是老的定時(shí)器機(jī)制,它包含指向timer_struct結(jié)構(gòu)的32位指針的靜態(tài)數(shù)組以當(dāng)前活動(dòng)定時(shí)器的屏蔽碼:time_active。
此定時(shí)器表中的位置是靜態(tài)定義的(類似底層部分處理表bh_base)。其入口在系統(tǒng)初始化時(shí)被加入到表中。其次種是相對(duì)較新的定時(shí)器,它使用一個(gè)到期時(shí)間以升序排列的timer_list結(jié)構(gòu)鏈表。
這兩種方法都使用jiffies作為終結(jié)時(shí)間,這樣盼望運(yùn)行5秒的定時(shí)器將不得不將5秒時(shí)間轉(zhuǎn)換成jiffies的單位并且將它和以jiffies記數(shù)的當(dāng)前系統(tǒng)時(shí)間相加從而得到定時(shí)器的終結(jié)時(shí)間。在每個(gè)系統(tǒng)時(shí)鐘滴答時(shí),定時(shí)器的底層部分處理過程被標(biāo)記成活動(dòng)狀態(tài)以便調(diào)度管理器下次運(yùn)行時(shí)能進(jìn)行定時(shí)器隊(duì)列的處理。定時(shí)器底層部分處理過程包含兩種類型的系統(tǒng)定時(shí)器。老的系統(tǒng)定時(shí)器將檢查timer_active位是否置位。假如活動(dòng)定時(shí)器已經(jīng)到期則其定時(shí)器例程將被調(diào)用同時(shí)
它的活動(dòng)位也被清除。新定時(shí)器位于timer_list結(jié)構(gòu)鏈表中的入口也將受到檢查。每個(gè)過期定時(shí)器將從鏈表中清除,同時(shí)它的例程將被調(diào)用。新定時(shí)器機(jī)制的優(yōu)點(diǎn)之一是能傳遞一個(gè)參數(shù)給定時(shí)器例程。
在本試驗(yàn)應(yīng)用程序中,需要進(jìn)行時(shí)間相關(guān)的編程動(dòng)作,如獵取當(dāng)前時(shí)間,對(duì)某一段工作進(jìn)行計(jì)時(shí)處理以及定時(shí)執(zhí)行某一動(dòng)作等。本試驗(yàn)將介紹如何在Linux調(diào)用時(shí)間相關(guān)函數(shù)完成上述功能。
1、獵取當(dāng)前時(shí)間在程序當(dāng)中,可以使用下面兩個(gè)函數(shù)輸出系統(tǒng)當(dāng)前的時(shí)間:
time_ttime(time_t*tloc);
char*ctime(consttime_t*clock);
time函數(shù)返回從1970年1月1日0點(diǎn)以來的秒數(shù).存儲(chǔ)在time_t結(jié)構(gòu)之中.這個(gè)函數(shù)的返回值由于不夠直觀,以人類的理解方式,這組抽象的數(shù)字好像缺乏實(shí)際意義。所以我們可以另一個(gè)函數(shù)ctime(consttime_t*clock)將抽象的時(shí)間記錄轉(zhuǎn)化為直觀的字符串,以便顯示。
2、計(jì)時(shí)處理
有時(shí)候我們要計(jì)算程序執(zhí)行的時(shí)間。比如我們要對(duì)算法進(jìn)行時(shí)間分析。這個(gè)時(shí)候可以使用下面這個(gè)函數(shù),加在需要計(jì)算時(shí)間的程序的兩端:
intgettimeofday(structtimeval*tv,structtimezone*tz)
第一個(gè)參數(shù)為timeval類型的結(jié)構(gòu),該結(jié)構(gòu)聲明如下:
Struttimeval{
Longtv_sec;//秒數(shù)
Longtv_usec;//微秒數(shù)
}
gettimeofday將時(shí)間保存在結(jié)構(gòu)tv之中。
3、定時(shí)器
Linux操作系統(tǒng)為每一個(gè)進(jìn)程供應(yīng)了3個(gè)內(nèi)部間隔計(jì)時(shí)器。ITIMER_REAL:削減實(shí)際時(shí)間。到時(shí)的時(shí)候發(fā)出SIGALRM信號(hào)。TIMER_VIRTUAL:削減有效時(shí)間(進(jìn)程執(zhí)行的時(shí)間)。到時(shí)的時(shí)候產(chǎn)生SIGVTALRM信號(hào)。
ITIME_PROF:削減進(jìn)程的有效時(shí)間和系統(tǒng)時(shí)間(為進(jìn)程調(diào)度用的時(shí)間)。到時(shí)的時(shí)候產(chǎn)生SIGPROF信號(hào)。
詳細(xì)的操作函數(shù)是:
intgetitimer(intwhich,structitimerval*value);
intsetitimer(intwhich,structitimerval*newval,structitimerval*oldval)
相關(guān)結(jié)構(gòu)類型聲明如下:
structitimerval{
structtimevalit_interval;
structtimevalitvalue;
}
getitimer函數(shù)得到間隔計(jì)時(shí)器的時(shí)間值并保存在value中。setitimer函數(shù)設(shè)置間隔計(jì)時(shí)器的時(shí)間值為newval,并將舊值保存在oldval中。which表示使用三個(gè)計(jì)時(shí)器中的哪一個(gè)。itimerval結(jié)構(gòu)中的it_value是削減的時(shí)間,當(dāng)這個(gè)值為0的時(shí)候就發(fā)出相應(yīng)的信號(hào)了,然后設(shè)置為it_interval值。
編寫timer.c程序源代碼
#include
#include
#include
structtimevaltpstart,tpend;
floattimeuse;
statictimer_count=0;
voidprompt_info(intsigno)
{
time_tt=time(NULL);
/*2secondsturned,printsomething*/
printf("prompt_infocalled\n",++timer_count);
/*getcurrenttimeandprintit*/
ctime(
printf("currenttime%s",ctime(
/*stopgettime,andprintit*/
gettimeofday(
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("UsedTime:%f\n",timeuse);
}
voidinit_sigaction(void)
{
structsigactionact;act.sa_handler=prompt_info;act.sa_flags=0;sigemptyset(sigaction(SIGPROF,
/*begingetthetime*/gettimeofday(printf("begintime\n");
}
voidinit_time()
{
structitimervalvalue;value.it_value.tv_sec=2;value.it_value.tv_usec=0;value.it_interval=value.it_value;setitimer(ITIMER_PROF,
}
/*
*timerapplicationcode
*/
intmain(intargc,char**argv)
{
init_sigaction();init_time();while(1);exit(0);
}
3、編寫Makefile文件,Makefile內(nèi)容如下:
CC=gcc
LD=ld
EXEC=timer
OBJS=timer.o
CFLAGS+=LDFLAGS+=
all:$(EXEC)
$(EXEC):$(OBJS)
$(CC)$(LDFLAGS)-o$@$(OBJS)$(LDLIBS$(LDLIBS_$@))
clean:
-rm-f$(EXEC)*.elf*.gdb*.o
4、編譯timer,在timer名目下,終端輸入如下命令:
#makeclean
#make
#./timer
輸出結(jié)果如下:
prompt_infocalled
currenttimeSatMar3015:58:232024
UsedTime:2.003054
prompt_infocalled
currenttimeSatMar3015:58:252024
UsedTime:4.001216
prompt_infocalled
currenttimeSatMar3015:58:272024
UsedTime:6.001144
prompt_infocalled
currenttimeSatMar3015:58:292024
UsedTime:8.001138
該程序正確執(zhí)行時(shí)將每隔兩秒鐘打印一次上述信息,“prompt_infocalled”字符串是在定時(shí)器處理函數(shù)中打印的,還打印了當(dāng)前系統(tǒng)時(shí)間和從第1次啟動(dòng)定時(shí)器開頭獵取的時(shí)間間隔。
試驗(yàn)四、設(shè)備驅(qū)動(dòng)試驗(yàn)
通過本試驗(yàn)的學(xué)習(xí),了解Linux操作系統(tǒng)中的設(shè)備驅(qū)動(dòng)程序包括哪些組成部分,并能編寫簡潔的字符設(shè)備(scull,SimpleCharacterUtilityforLoadingLocalities)和塊設(shè)備(sbull,SimpleBlockUtilityforLoadingLocalities)的驅(qū)動(dòng)程序以及對(duì)所編寫設(shè)備驅(qū)動(dòng)程序的測試,最終了解Linux操作系統(tǒng)是如何管理設(shè)備的。
一.設(shè)備驅(qū)動(dòng)程序的簡潔介紹
Linux設(shè)備驅(qū)動(dòng)程序集成在內(nèi)核中,實(shí)際上是處理或操作硬件掌握器的軟件。從本質(zhì)上講,驅(qū)動(dòng)程序是常駐內(nèi)存的低級(jí)硬件處理程序的共享庫,設(shè)備驅(qū)動(dòng)程序就是對(duì)設(shè)備的抽象處理;也即是說,設(shè)備驅(qū)動(dòng)程序是內(nèi)核中具有高特權(quán)級(jí)的、常駐內(nèi)存的、可共享的下層硬件處理例程。
設(shè)備驅(qū)動(dòng)程序軟件封裝了如何掌握這些設(shè)備的技術(shù)細(xì)節(jié),并通過特定的接口導(dǎo)出一個(gè)規(guī)范的操作集合(見圖1);內(nèi)核使用規(guī)范的設(shè)備接口(字符設(shè)備接口和塊設(shè)備接口)通過文件系統(tǒng)接口把設(shè)備操作導(dǎo)出到用戶空間程序中。(由于本試驗(yàn)不涉及網(wǎng)絡(luò)設(shè)備,故在此就不作爭論)
圖1字符(塊)設(shè)備、驅(qū)動(dòng)
在Linux中,字符設(shè)備和塊設(shè)備的I/O操作是有區(qū)分的。塊設(shè)備在每次硬件操作時(shí)把多個(gè)字節(jié)傳送到主存緩存中或從主存緩存中把多個(gè)字節(jié)信息傳送到設(shè)備中;而字符設(shè)備并不使用緩存,信息傳送是一個(gè)字節(jié)一個(gè)字節(jié)地進(jìn)行的。
Linux操作系統(tǒng)允許設(shè)備驅(qū)動(dòng)程序作為可裝載內(nèi)核模塊實(shí)現(xiàn),這也就是說,設(shè)備的接口實(shí)現(xiàn)不僅可以在Linux操作系統(tǒng)啟動(dòng)時(shí)進(jìn)行注冊(cè),而且還可以在Linux操作系統(tǒng)啟動(dòng)后裝載模塊時(shí)進(jìn)行注冊(cè)。
總之,Linux操作系統(tǒng)支持多種設(shè)備,這些設(shè)備的驅(qū)動(dòng)程序有如下一些特點(diǎn):
(1)內(nèi)核代碼:設(shè)備驅(qū)動(dòng)程序是內(nèi)核的一部分,假如驅(qū)動(dòng)程序出錯(cuò),則可能導(dǎo)致系統(tǒng)崩潰。
(2)內(nèi)核接口:設(shè)備驅(qū)動(dòng)程序必需為內(nèi)核或者其子系統(tǒng)供應(yīng)一個(gè)標(biāo)準(zhǔn)接口。比如,一個(gè)終端驅(qū)動(dòng)程序必需為內(nèi)核供應(yīng)一個(gè)文件I/O接口;一個(gè)SCSI設(shè)備驅(qū)動(dòng)程序應(yīng)當(dāng)為SCSI子系統(tǒng)供應(yīng)一個(gè)SCSI設(shè)備接口,同時(shí)SCSI子系統(tǒng)也必需為內(nèi)核供應(yīng)文件的I/O接口及緩沖區(qū)。
(3)內(nèi)核機(jī)制和服務(wù):設(shè)備驅(qū)動(dòng)程序使用一些標(biāo)準(zhǔn)的內(nèi)核服務(wù),如內(nèi)存安排等。
(4)可裝載:大多數(shù)的Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序都可以在需要時(shí)裝載進(jìn)內(nèi)核,在不需要時(shí)從內(nèi)核中卸載。
(5)可設(shè)置:Linux操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序可以集成為內(nèi)核的一部分,并可以依據(jù)需要把其中的某一部分集成到內(nèi)核中,這只需要在系統(tǒng)編譯時(shí)進(jìn)行相應(yīng)的設(shè)置即可。
(6)動(dòng)態(tài)性:當(dāng)系統(tǒng)啟動(dòng)且各個(gè)設(shè)備驅(qū)動(dòng)程序初始化后,驅(qū)動(dòng)程序?qū)⒕S護(hù)其掌握的設(shè)備。假如該設(shè)備驅(qū)動(dòng)程序掌握的設(shè)備不存在也不影響系統(tǒng)的運(yùn)行,此時(shí)的設(shè)備驅(qū)動(dòng)程序只是多占用了一點(diǎn)系統(tǒng)內(nèi)存罷了。
二.設(shè)備驅(qū)動(dòng)程序與外界的接口
每種類型的驅(qū)動(dòng)程序,不管是字符設(shè)備還是塊設(shè)備都為內(nèi)核供應(yīng)相同的調(diào)用接口,故內(nèi)核能以相同的方式處理不同的設(shè)備。Linux為每種不同類型的設(shè)備驅(qū)動(dòng)程序維護(hù)相應(yīng)的數(shù)據(jù)結(jié)構(gòu),以便定義統(tǒng)一的接口并實(shí)現(xiàn)驅(qū)動(dòng)程序的可裝載性和動(dòng)態(tài)性。
Linux設(shè)備驅(qū)動(dòng)程序與外界的接口可以分為如下三個(gè)部分:
(1)驅(qū)動(dòng)程序與操作系統(tǒng)內(nèi)核的接口:這是通過數(shù)據(jù)結(jié)構(gòu)file_operations來完成的。
(2)驅(qū)動(dòng)程序與系統(tǒng)引導(dǎo)的接口:這部分利用驅(qū)動(dòng)程序?qū)υO(shè)備進(jìn)行初始化。
(3)驅(qū)動(dòng)程序與設(shè)備的接口:這部分描述了驅(qū)動(dòng)程序如何與設(shè)備進(jìn)行交互,這與詳細(xì)設(shè)備親密相關(guān)。
可歸結(jié)為如下圖2:
圖2設(shè)備驅(qū)動(dòng)程序與
三.設(shè)備驅(qū)動(dòng)程序的組織結(jié)構(gòu)
設(shè)備驅(qū)動(dòng)程序有一個(gè)比較標(biāo)準(zhǔn)的組織結(jié)構(gòu),一般可以分為下面三個(gè)主要組成部分:
(1)自動(dòng)配置和初始化子程序
這部分程序負(fù)責(zé)檢測所要驅(qū)動(dòng)的硬件設(shè)備是否存在以及是否能正常工作。假如該設(shè)備正常,則對(duì)設(shè)備及其驅(qū)動(dòng)程序所需要的相關(guān)軟件狀態(tài)進(jìn)行初始化。這部分程序僅在初始化時(shí)被調(diào)用一次。
(2)服務(wù)于I/O懇求的子程序
該部分又可稱為驅(qū)動(dòng)程序的上半部分。系統(tǒng)調(diào)用對(duì)這部分進(jìn)行調(diào)用。系統(tǒng)認(rèn)為這部分程序在執(zhí)行時(shí)和進(jìn)行調(diào)用的進(jìn)程屬于同一個(gè)進(jìn)程,只是由用戶態(tài)變成了內(nèi)核態(tài),而且具有進(jìn)行此系統(tǒng)調(diào)用的用戶程序的運(yùn)行環(huán)境。故可以在其中調(diào)用與進(jìn)程運(yùn)行環(huán)境有關(guān)的函數(shù)。
(3)中斷服務(wù)子程序
該部分又可稱為驅(qū)動(dòng)程序的下半部分。設(shè)備在I/O懇求結(jié)束時(shí)或其它狀態(tài)轉(zhuǎn)變時(shí)產(chǎn)生中斷。中斷可以產(chǎn)生在任何一個(gè)進(jìn)程運(yùn)行時(shí),因此中斷服務(wù)子程序被調(diào)用時(shí)不能依靠于任何進(jìn)程的狀態(tài),因而也就不能調(diào)用與進(jìn)程運(yùn)行環(huán)境有關(guān)的函數(shù)。由于設(shè)備驅(qū)動(dòng)程序一般支持同一類型的若干設(shè)備,所以一般在系統(tǒng)調(diào)用中斷服務(wù)子程序時(shí)都帶有一個(gè)或多個(gè)參數(shù),以唯一標(biāo)識(shí)懇求服務(wù)的設(shè)備。
四.設(shè)備驅(qū)動(dòng)程序的代碼
設(shè)備驅(qū)動(dòng)程序是一些函數(shù)和數(shù)據(jù)結(jié)構(gòu)的集合,這些函數(shù)和數(shù)據(jù)結(jié)構(gòu)是為實(shí)現(xiàn)管理設(shè)備的一個(gè)簡潔接口。操作系統(tǒng)內(nèi)核使用這個(gè)接口來懇求驅(qū)動(dòng)程序?qū)υO(shè)備進(jìn)行I/O操作。甚至,我們可以把設(shè)備驅(qū)動(dòng)程序看成是一個(gè)抽象數(shù)據(jù)類型,它為計(jì)算機(jī)中的每個(gè)硬件設(shè)備都建立了一個(gè)通用函數(shù)接口。由于一個(gè)設(shè)備驅(qū)動(dòng)程序就是一個(gè)模塊,所以在內(nèi)核內(nèi)部用一個(gè)file結(jié)構(gòu)來識(shí)別設(shè)備驅(qū)動(dòng)程序,而且內(nèi)核使用file_operatuions結(jié)構(gòu)來訪問設(shè)備驅(qū)動(dòng)程序中的函數(shù)。
了解設(shè)備驅(qū)動(dòng)程序代碼的如下幾個(gè)部分:
◆驅(qū)動(dòng)程序的注冊(cè)與注銷。◆設(shè)備的打開與釋放。◆設(shè)備的讀寫操作。
◆設(shè)備的掌握操作。◆設(shè)備的中斷和輪詢處理。
五、字符設(shè)備驅(qū)動(dòng)程序的代碼
1、了解什么是字符設(shè)備
2、了解字符設(shè)備的基本入口點(diǎn)
字符設(shè)備的基本入口點(diǎn)也可稱為子程序,它們被包含在驅(qū)動(dòng)程序的file_operations結(jié)構(gòu)中。
①open()函數(shù);②release()函數(shù);③read()函數(shù);④write()函數(shù);
⑤ioctl()函數(shù);⑥select()函數(shù)。
3、字符設(shè)備的注冊(cè)
設(shè)備驅(qū)動(dòng)程序供應(yīng)的入口點(diǎn)在設(shè)備驅(qū)動(dòng)程序初始化時(shí)向系統(tǒng)登記,以便系統(tǒng)調(diào)
用。Linux系統(tǒng)通過調(diào)用register_chrdev()向系統(tǒng)注冊(cè)字符型設(shè)備驅(qū)動(dòng)程序。
register_chrdev()定義如下:
#include#include
intregister_chrdev(unsignedintmajor,constchar*name,struct
file_operations*ops);
其中major時(shí)設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào)。假如它為0,則系統(tǒng)為該驅(qū)
動(dòng)程序動(dòng)態(tài)地安排第一個(gè)空閑的主設(shè)備號(hào),并把設(shè)備名和文件操作表的指針置于
chrdevs表的相應(yīng)位置。name是設(shè)備名,ops是對(duì)各個(gè)調(diào)用入口點(diǎn)的說明。
register_chrdev()函數(shù)返回0表示注冊(cè)勝利;返回-EINVAL表示申請(qǐng)的主設(shè)備號(hào)非法,
一般主設(shè)備號(hào)大于系統(tǒng)所允許的最大設(shè)備號(hào);返回-EBUSY表示所申請(qǐng)的主設(shè)備號(hào)正被
其它設(shè)備驅(qū)動(dòng)程序使用。假如動(dòng)態(tài)安排主設(shè)備號(hào)勝利,則該函數(shù)將返回所安排的主設(shè)
備號(hào)。假如register_chrdev()操作勝利,則設(shè)備名就會(huì)消失在/proc/devices文件
中。
字符設(shè)備注冊(cè)以后,還必需在文件系統(tǒng)中為其創(chuàng)建一個(gè)代表節(jié)點(diǎn)。該節(jié)點(diǎn)可以是
在/dev名目中的一個(gè)節(jié)點(diǎn),這種節(jié)點(diǎn)都是文件節(jié)點(diǎn),且每個(gè)節(jié)點(diǎn)代表一個(gè)詳細(xì)的設(shè)備。
不過要有主設(shè)備號(hào)和從設(shè)備號(hào)兩個(gè)參數(shù)才能創(chuàng)建一個(gè)節(jié)點(diǎn)。還可以是在devfs設(shè)備文
件名目下的一個(gè)節(jié)點(diǎn),對(duì)于這種節(jié)點(diǎn)應(yīng)依據(jù)主設(shè)備號(hào)給每一種設(shè)備都創(chuàng)建一個(gè)名目節(jié)
點(diǎn),在這個(gè)名目下才是代表詳細(xì)設(shè)備的文件節(jié)點(diǎn)。
編寫一個(gè)簡潔的字符設(shè)備驅(qū)動(dòng)程序。要求該字符設(shè)備包括scull_open()、
scull_write()、scull_read()、scull_ioctl()和scull_release()五個(gè)基本操作,
并編寫一個(gè)測試程序來測試你所編寫的字符設(shè)備驅(qū)動(dòng)程序。
先給出字符設(shè)備驅(qū)動(dòng)程序要用到的數(shù)據(jù)結(jié)構(gòu)定義:
structdevice_struct{constchar*name;
structfile_operations*chops;
};
staticstructdevice_structchrdevs;
typedefstructScull_Dev{
void**data;
intquantum;//thecurrentquantumsizeintqset;//thecurrentarraysizeunsignedlongsize;
unsignedintaccess_key;//usedbysculluidandscullprivunsignedintusage;//lockthedevicewhileusingitstructScull_Dev*next;//nextlistitem}scull;
1、字符設(shè)備的結(jié)構(gòu)
字符設(shè)備的結(jié)構(gòu)即字符設(shè)備的開關(guān)表。當(dāng)字符設(shè)備注冊(cè)到內(nèi)核后,字符設(shè)備的名
字和相關(guān)操作被添加到device_struct結(jié)構(gòu)類型的chrdevs全局?jǐn)?shù)組中,稱chrdevs
為字符設(shè)備的開關(guān)表。下面以一個(gè)簡潔的例子說明字符設(shè)備驅(qū)動(dòng)程序中字符設(shè)備結(jié)構(gòu)
的定義:(假設(shè)設(shè)備名為scull)
****file_operation結(jié)構(gòu)定義如下,即定義chr設(shè)備的_fops****
staticintscull_open(structinode*inode,structfile*filp);
staticintscull_release(structinode*inode,structfile*filp);
staticssize_tscull_write(structinode*inode,structfile*filp,const
char*buffer,intcount);
staticssize_tscull_read(structinode*inode,structfile*filp,char
*buffer,intcount);
staticintscull_ioctl(structinode*inode,structfile*filp,unsigned
longintcmd,unsignedlongarg);
structfile_operationchr_fops={
NULL,//seek
scull_read,//read
scull_write,//write
NULL,//readdir
NULL,//poll
scull_ioctl,//ioctl
NULL,//mmap
scull_open,//open
NULL,//flush
scull_release,//release
NULL,//fsync
NULL,//fasync
NULL,//checkmediachange
NULL,//revalidate
NULL//lock
};
2、字符設(shè)備驅(qū)動(dòng)程序入口點(diǎn)
字符設(shè)備驅(qū)動(dòng)程序入口點(diǎn)主要包括初始化字符設(shè)備、字符設(shè)備的I/O調(diào)用和中斷。在引導(dǎo)系統(tǒng)時(shí),每個(gè)設(shè)備驅(qū)動(dòng)程序通過其內(nèi)部的初始化函數(shù)init()對(duì)其掌握的設(shè)備及其自身初始化。字符設(shè)備初始化函數(shù)為chr_dev_init(),包含在/linux/drivers/char/mem.c中,它的主要功能之一是在內(nèi)核中登記設(shè)備驅(qū)動(dòng)程序。詳細(xì)調(diào)用是通過register_chrdev()函數(shù)。register_chrdev()函數(shù)定義如下:
#include
#include
intregister_chrdev(unsignedintmajor,constchar*name,structfile_operation*fops);
其中major是為設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào)。假如為0,則系統(tǒng)為此驅(qū)動(dòng)程序動(dòng)態(tài)地安排一個(gè)主設(shè)備號(hào)。name是設(shè)備名。fops是前面定義的file_operation結(jié)構(gòu)的指針。在登記勝利的狀況下,假如指定了major,則register_chrdev()函數(shù)返回值為0;假如major值為0,則返回內(nèi)核安排的主設(shè)備號(hào)。并且register_chrdev()函數(shù)操作勝利,設(shè)備名就會(huì)消失在/proc/devices文件里;在登記失敗的狀況下,register_chrdev()函數(shù)返回值為負(fù)。
初始化部分一般還負(fù)責(zé)給設(shè)備驅(qū)動(dòng)程
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025電子產(chǎn)品生產(chǎn)合同范本
- 2025年企業(yè)辦公租賃合同簡化范本
- 2025電力系統(tǒng)經(jīng)營管理責(zé)任制的合同范文
- 2025授權(quán)財(cái)務(wù)合同
- 2025合同管理要點(diǎn)全面解析
- 2025私人股權(quán)投資合同協(xié)議書范本
- 2025(文檔)工程建設(shè)項(xiàng)目勞務(wù)分包合同范本
- 2025關(guān)于廣告設(shè)計(jì)服務(wù)的合同范本
- 2025辦公室租賃合同樣本范本
- 2025企業(yè)清潔工勞動(dòng)合同模板
- 2025年北京市海淀區(qū)高三一模生物試卷(含答案)
- 幼兒教育政策法規(guī)
- 農(nóng)作物高產(chǎn)栽培技術(shù)的試題及答案
- 2025-2030飛機(jī)檢測產(chǎn)業(yè)規(guī)劃專項(xiàng)研究報(bào)告
- 寧夏回族自治區(qū)銀川市一中2025屆高三下學(xué)期模擬訓(xùn)練數(shù)學(xué)試題
- 湘豫名校聯(lián)考2024-2025學(xué)年高三春季學(xué)期第二次模擬考試物理試題及答案
- 智能駕駛算法優(yōu)化研究-全面剖析
- 熱點(diǎn)主題作文寫作指導(dǎo):數(shù)字工具(審題指導(dǎo)與例文)
- 餐飲接待流程培訓(xùn)
- 建筑工程技術(shù)專業(yè)實(shí)習(xí)報(bào)告
- 第11章 一元一次不等式(學(xué)生版)-2023-2024學(xué)年蘇科版七年級(jí)數(shù)學(xué)下冊(cè)
評(píng)論
0/150
提交評(píng)論