![linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子_第1頁](http://file4.renrendoc.com/view/3f89f0738a8c8b1d83556d64d1a677a7/3f89f0738a8c8b1d83556d64d1a677a71.gif)
![linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子_第2頁](http://file4.renrendoc.com/view/3f89f0738a8c8b1d83556d64d1a677a7/3f89f0738a8c8b1d83556d64d1a677a72.gif)
![linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子_第3頁](http://file4.renrendoc.com/view/3f89f0738a8c8b1d83556d64d1a677a7/3f89f0738a8c8b1d83556d64d1a677a73.gif)
![linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子_第4頁](http://file4.renrendoc.com/view/3f89f0738a8c8b1d83556d64d1a677a7/3f89f0738a8c8b1d83556d64d1a677a74.gif)
![linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子_第5頁](http://file4.renrendoc.com/view/3f89f0738a8c8b1d83556d64d1a677a7/3f89f0738a8c8b1d83556d64d1a677a75.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
精品文檔-下載后可編輯linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作-基礎(chǔ)電子1.前言本文介紹linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作。2.雙向鏈表(list)linux內(nèi)核中的雙向鏈表通過結(jié)構(gòu)structlist_head來將各個(gè)節(jié)點(diǎn)連接起來,此結(jié)構(gòu)會(huì)作為鏈表元素結(jié)構(gòu)中的一個(gè)參數(shù):structlist_head{
structlist_head*next,*prev;
};鏈表頭的初始化,注意,結(jié)構(gòu)中的指針為NULL并不是初始化,而是指向自身才是初始化,如果只是按普通情況下的置為NULL,而不是指向自身,系統(tǒng)會(huì)崩潰,這是一個(gè)容易犯的錯(cuò)誤:#defineLIST_HEAD_INIT(name){(name),(name)}#defineLIST_HEAD(name)\
structlist_headname=LIST_HEAD_INIT(name)#defineINIT_LIST_HEAD(ptr)do{\
(ptr)-next=(ptr);(ptr)-prev=(ptr);\
}while(0)常用的鏈表操作:插入到鏈表頭:
voidlist_add(structlist_head*new,structlist_head*head);插入到鏈表尾:
voidlist_add_tail(structlist_head*new,structlist_head*head);刪除鏈表節(jié)點(diǎn):
voidlist_del(structlist_head*entry);將節(jié)點(diǎn)移動(dòng)到另一鏈表:
voidlist_move(structlist_head*list,structlist_head*head);將節(jié)點(diǎn)移動(dòng)到鏈表尾:
voidlist_move_tail(structlist_head*list,structlist_head*head);判斷鏈表是否為空,返回1為空,0非空
intlist_empty(structlist_head*head);把兩個(gè)鏈表拼接起來:
voidlist_splice(structlist_head*list,structlist_head*head);取得節(jié)點(diǎn)指針:
#definelist_entry(ptr,type,member)\
((type*)((char*)(ptr)-(unsignedlong)(((type*)0)-member)))遍歷鏈表中每個(gè)節(jié)點(diǎn):
#definelist_for_each(pos,head)\
for(pos=(head)-next,prefetch(pos-next);pos!=(head);\
pos=pos-next,prefetch(pos-next))逆向循環(huán)鏈表中每個(gè)節(jié)點(diǎn):
#definelist_for_each_prev(pos,head)\
for(pos=(head)-prev,prefetch(pos-prev);pos!=(head);\
pos=pos-prev,prefetch(pos-prev))舉例:LISH_HEAD(mylist);structmy_list{
structlist_headlist;
intdata;
};staticintini_list(void)
{
structmy_list*p;
inti;
for(i=0;i100;i++){
p=kmalloc(sizeof(structmy_list),GFP_KERNEL);
list_add(p-list,mylist);
}
}
在內(nèi)存中形成如下結(jié)構(gòu)的一個(gè)雙向鏈表:++
||
|mylist99980|
|++++++++|
+-|next||list.next||list.next|...|list.next|+
||||||||
+--|prev||list.prev||list.prev|...|list.prev|--+
|++|||||||
||data||data||data||
|++++++|
||
++知道了鏈表頭就能遍歷整個(gè)鏈表,如果是用list_add()插入新節(jié)點(diǎn)的話,從鏈表頭的next方向看是一個(gè)堆棧型。從鏈表中刪除節(jié)點(diǎn)很容易:staticvoiddel_item(structmy_list*p)
{
list_del(p-list,mylist);
kfree(p);
}重要的宏是list_entry,這個(gè)宏的思路是根據(jù)鏈表元素結(jié)構(gòu)中鏈表頭結(jié)構(gòu)list_head的地址推算出鏈表元素結(jié)構(gòu)的實(shí)際地址:#definelist_entry(ptr,type,member)\
((type*)((char*)(ptr)-(unsignedlong)(((type*)0)-member)))ptr是鏈表元素結(jié)構(gòu)(如structmy_list)中鏈表頭結(jié)構(gòu)list_head的地址
member是鏈表元素結(jié)構(gòu)(如structmy_list)中鏈表頭結(jié)構(gòu)list_head參數(shù)的名稱
type是鏈表元素結(jié)構(gòu)類型(如structmy_list)計(jì)算原理是根據(jù)鏈表頭結(jié)構(gòu)list_head的地址減去其在鏈表元素結(jié)構(gòu)中的偏移位置而得到鏈表元素結(jié)構(gòu)的地址。例如:staticvoidprint_list(void)
{
structlist_head*cur;
structmy_list*p;list_for_each(cur,mylist){
p=list_entry(cur,structmy_list,list);
printk("data=%d\n",p-data);
}
}優(yōu)點(diǎn):這樣就可以用相同的數(shù)據(jù)處理方式來描述所有雙向鏈表,不用再單獨(dú)為各個(gè)鏈表編寫各種編輯函數(shù)。缺點(diǎn):
1)鏈表頭中元素置為NULL不是初始化,與普通習(xí)慣不同;
2)仍然需要單獨(dú)編寫各自的刪除整個(gè)鏈表的函數(shù),不能統(tǒng)一處理,因?yàn)椴荒鼙WC所有鏈表元素結(jié)構(gòu)中鏈表頭結(jié)構(gòu)list_head的偏移地址都是相同的,當(dāng)然如果把鏈表頭結(jié)構(gòu)list_head都作為鏈表元素結(jié)構(gòu)的個(gè)參數(shù),就可以用統(tǒng)一的刪除整個(gè)鏈表的函數(shù)。
3.HASH表HASH表適用于不需要對(duì)整個(gè)空間元素進(jìn)行排序,而是只需要能快速找到某個(gè)元素的場合,是一種以空間換時(shí)間的方法,本質(zhì)也是線性表,但由一個(gè)大的線性表拆分為了多個(gè)小線性表,由于只需要查找小表,因此搜索速度就會(huì)線性查整個(gè)大表提高很多,理想情況下,有多少個(gè)小線性表,搜索速度就提高了多少倍,通常把小線性表的表頭綜合為一個(gè)數(shù)組,大小就是HASH表的數(shù)量。HASH表速度的關(guān)鍵是HASH函數(shù)的設(shè)計(jì),HASH函數(shù)根據(jù)每個(gè)元素中固定的參數(shù)進(jìn)行計(jì)算,算出一個(gè)不大于HASH表數(shù)量的索引值,表示該元素需要放在該索引號(hào)對(duì)應(yīng)的那個(gè)表中,對(duì)于固定的參數(shù),計(jì)算結(jié)果始終是固定的,但對(duì)于不同的參數(shù)值,希望計(jì)算出來的結(jié)果能盡可能地平均到每個(gè)索引值,HASH函數(shù)計(jì)算得越平均,表示每個(gè)小表中元素的數(shù)量都會(huì)差不多,這樣搜索性能將越好。HASH函數(shù)也要盡可能的簡單,以減少計(jì)算時(shí)間,常用的算法是將參數(shù)累加求模,在include/linux/jhash.h中已經(jīng)定義了一些HASH計(jì)算函數(shù),可直接使用。HASH表在路由cache表,狀態(tài)連接表等處用得很多。舉例,連接跟蹤中根據(jù)tuple值計(jì)算HASH://net/ipv4/netfilter/ip_conntrack_core.cu_int32_t
hash_conntrack(conststructip_conntrack_tuple*tuple)
{
#if0
dump_tuple(tuple);
#endif
return(jhash_3words(tuple-src.ip,
(tuple-dst.ip^tonum),
(tuple-src.u.all|(tuple-dst.u.all16)),
ip_conntrack_hash_rnd)%ip_conntrack_htable_size);
}//include/linux/jhash.h
staticinlineu32jhash_3words(u32a,u32b,u32c,u32initval)
{
a+=JHASH_GOLDEN_RATIO;
b+=JHASH_GOLDEN_RATIO;
c+=initval;__jhash_mix(a,b,c);returnc;
}4.定時(shí)器(timer)linux內(nèi)核定時(shí)器由以下結(jié)構(gòu)描述:/*include/linux/timer.h*/
structtimer_list{
structlist_headlist;
unsignedlongexpires;
unsignedlongdata;
void(*function)(unsignedlong);
};list:timer鏈表
expires:到期時(shí)間
function:到期函數(shù),時(shí)間到期時(shí)調(diào)用的函數(shù)
data:傳給到期函數(shù)的數(shù)據(jù),實(shí)際應(yīng)用中通常是一個(gè)指針轉(zhuǎn)化而來,該指針指向一個(gè)結(jié)構(gòu)
timer的操作:增加timer,將timer掛接到系統(tǒng)的timer鏈表:
externvoidadd_timer(structtimer_list*timer);刪除timer,將timer從系統(tǒng)timer鏈表中拆除:
externintdel_timer(structtimer_list*timer);
(del_timer()函數(shù)可能會(huì)失敗,這是因?yàn)樵搕imer本來已經(jīng)不在系統(tǒng)timer鏈表中了,也就是已經(jīng)刪除過了)對(duì)于SMP系統(tǒng),刪除timer使用下面的函數(shù)來防止沖突:
externintdel_timer_sync(structtimer_list*timer);修改timer,修改timer的到期時(shí)間:
intmod_timer(structtimer_list*timer,unsignedlongexpires);通常用法:
structtimer_list通常作為數(shù)據(jù)結(jié)構(gòu)中的一個(gè)參數(shù),在初始化結(jié)構(gòu)的時(shí)候初始化timer,表示到期時(shí)要進(jìn)行的操作,實(shí)現(xiàn)定時(shí)動(dòng)作,通常更多的是作為超時(shí)處理的,timer函數(shù)作為超時(shí)時(shí)的資源釋放函數(shù)。注意:如果超時(shí)了運(yùn)行超時(shí)函數(shù),此時(shí)系統(tǒng)是處在時(shí)鐘中斷的bottomhalf里的,不能進(jìn)行很復(fù)雜的操作,如果要完成一些復(fù)雜操作,如到期后的數(shù)據(jù)發(fā)送,不能直接在到期函數(shù)中處理,而是應(yīng)該在到期函數(shù)中發(fā)個(gè)信號(hào)給特定內(nèi)核線程轉(zhuǎn)到tophalf進(jìn)行處理。為判斷時(shí)間的先后,內(nèi)核中定義了以下宏來判斷:#definetime_after(a,b)((long)(b)-(long)(a)0)
#definetime_before(a,b)time_after(b,a)#definetime_after_eq(a,b)((long)(a)-(long)(b)=0)
#definetime_before_eq(a,b)time_after_eq(b,a)這里用到了一個(gè)技巧,由于linux中的時(shí)間是無符號(hào)數(shù),這里先將其轉(zhuǎn)換為有符號(hào)數(shù)后再判斷,就能解決時(shí)間回繞問題,當(dāng)然只是回繞,回繞兩次當(dāng)然是判斷不出來的,具體可自己實(shí)驗(yàn)體會(huì)。5.內(nèi)核線程(kernel_thread)內(nèi)核中新線程的建立可以用kernel_thread函數(shù)實(shí)現(xiàn),該函數(shù)在kernel/fork.c中定義:longkernel_thread(int(*fn)(void*),void*arg,unsignedlongflags)fn:內(nèi)核線程主函數(shù);
arg:線程主函數(shù)的參數(shù);
flags:建立線程的標(biāo)志;內(nèi)核線程函數(shù)通常都調(diào)用daemonize()進(jìn)行后臺(tái)化作為一個(gè)獨(dú)立的線程運(yùn)行,然后設(shè)置線程的一些參數(shù),如名稱,信號(hào)處理等,這也不是必須的,然后就進(jìn)入一個(gè)死循環(huán),這是線程的主體部分,這個(gè)循環(huán)不能一直在運(yùn)行,否則系統(tǒng)就死在這了,或者是某種事件驅(qū)動(dòng)的,在事件到來前是睡眠的,事件到來后喚醒進(jìn)行操作,操作完后繼續(xù)睡眠;或者是定時(shí)睡眠,醒后操作完再睡眠;或者加入等待隊(duì)列通過schedule()調(diào)度獲得執(zhí)行時(shí)間??傊遣荒芤恢闭贾鳦PU。以下是內(nèi)核線程的一個(gè)實(shí)例,取自kernel/context.c:intstart_context_thread(void)
{
staticstructcompletionstartup__initdata=COMPLETION_INITIALIZER(startup);kernel_thread(context_thread,startup,CLONE_FS|CLONE_FILES);
wait_for_completion(startup);
return0;
}staticintcontext_thread(void*startup)
{
structtask_struct*curtask=current;
DECLARE_WAITQUEUE(wait,curtask);
structk_sigactionsa;daemonize();
strcpy(curtask-comm,"keventd");
keventd_running=1;
keventd_task=curtask;spin_lock_irq(curtask-sigmask_lock);
siginitsetinv(curtask-blocked,sigmask(SIGCHLD));
recalc_sigpending(curtask);
spin_unlock_irq(curtask-sigmask_lock);complete((structcompletion*)startup);/*InstallahandlersoSIGCLDisdelivered*/
sa.sa.sa_handler=SIG_IGN;
sa.sa.sa_flags=0;
siginitset(sa.sa.sa_mask,sigmask(SIGCHLD));
do_sigaction(SIGCHLD,sa,(structk_sigaction*)0);/*
*Ifoneofthefunctionsonataskqueuere-addsitself
*tothetaskqueuewecallschedule()instateTASK_RUNNING
*/
for(;;){
set_task_state(curtask,T
溫馨提示
- 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至2031年中國茶制床墊行業(yè)投資前景及策略咨詢研究報(bào)告
- 2025至2031年中國石榴干紅葡萄酒行業(yè)投資前景及策略咨詢研究報(bào)告
- 2025年油壓壓彎床項(xiàng)目可行性研究報(bào)告
- 2025年有色金屬連桿項(xiàng)目可行性研究報(bào)告
- 2025年攪拌機(jī)攪拌臂項(xiàng)目可行性研究報(bào)告
- 2025年小體視棱鏡項(xiàng)目可行性研究報(bào)告
- 2025至2031年中國內(nèi)置式伺服放大器模塊行業(yè)投資前景及策略咨詢研究報(bào)告
- 2025年沖裁拉伸模具項(xiàng)目可行性研究報(bào)告
- 2025至2030年中國雞藥數(shù)據(jù)監(jiān)測研究報(bào)告
- 2025至2030年香油紅尖椒項(xiàng)目投資價(jià)值分析報(bào)告
- 駕照考試題庫及答案(完整版)
- 2025年1月日歷表(含農(nóng)歷-周數(shù)-方便記事備忘)
- 2025中國鐵塔公司社會(huì)招聘85人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 專題06 現(xiàn)代文閱讀(解析版)2015-2024單招考試語文(四川真題)
- 《固體食品罐用冷軋電鍍錫鋼板及鋼帶》編制說明
- 人教版數(shù)學(xué)三年級(jí)下冊 期末測試卷帶答案(能力提升)
- 《人工智能發(fā)展史》課件
- 2024年同等學(xué)力人員申請(qǐng)碩士學(xué)位英語試卷與參考答案
- 臨床用血管理培訓(xùn)
- 介入手術(shù)室護(hù)理風(fēng)險(xiǎn)
- 春季安全行車教育培訓(xùn)
評(píng)論
0/150
提交評(píng)論