女人被狂躁到高潮视频免费无遮挡,内射人妻骚骚骚,免费人成小说在线观看网站,九九影院午夜理论片少妇,免费av永久免费网址

當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作

1. 前言 本文介紹linux內(nèi)核中一些常用的數(shù)據(jù)結(jié)構(gòu)和操作。2. 雙向鏈表(liST)linux內(nèi)核中的雙向鏈表通過(guò)結(jié)構(gòu) struct list_head來(lái)將各個(gè)節(jié)點(diǎn)連接起來(lái),此結(jié)構(gòu)會(huì)作為鏈表元素結(jié)構(gòu)中的一個(gè)參數(shù):struct list_head {

struct list_head *next, *prev;

};鏈表頭的初始化,注意,結(jié)構(gòu)中的指針為NULL并不是初始化,而是指向自身才是初始化,如果只是按普通情況下的置為NULL,而不是指向自身,系統(tǒng)會(huì)崩潰,這是一個(gè)容易犯的錯(cuò)誤:#define LIST_HEAD_INIT(name) { &(nAME), &(name) }#define LIST_HEAD(name)

struct list_head name = LIST_HEAD_INIT(name)#define INIT_LIST_HEAD(ptr) do {

(ptr)->next = (ptr); (ptr)->prev = (ptr);

} while (0)最常用的鏈表操作:插入到鏈表頭:

void list_add(struct list_head *new, struct list_head *head);插入到鏈表尾:

void list_add_tail(struct list_head *new, struct list_head *head);刪除鏈表節(jié)點(diǎn):

void list_del(struct list_head *entry);將節(jié)點(diǎn)移動(dòng)到另一鏈表:

void list_move(struct list_head *list, struct list_head *head);將節(jié)點(diǎn)移動(dòng)到鏈表尾:

void list_move_tail(struct list_head *list,struct list_head *head);判斷鏈表是否為空,返回1為空,0非空

int list_empty(struct list_head *head);把兩個(gè)鏈表拼接起來(lái):

void list_splice(struct list_head *list, struct list_head *head);取得節(jié)點(diǎn)指針:

#define list_entry(ptr, type, member)

((type *)((char *)(ptr)-(unsigned lONg)(&((type *)0)->member)))遍歷鏈表中每個(gè)節(jié)點(diǎn):

#define list_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):

#define list_for_each_prev(pos, head)

for (pos = (head)->prev, prefetch(pos->prev); pos != (head);

pos = pos->prev, prefetch(pos->prev))舉例:LISH_HEAD(mylist);struct my_list{

struct list_head list;

int data;

};stATIc int ini_list(void)

{

struct my_list *p;

int i;

for(i=0; i<100; i++){

p=kmalloc(sizeof(struct my_list), GFP_KERNEL);

list_add(&p->list, &mylist);

}

}

在內(nèi)存中形成如下結(jié)構(gòu)的一個(gè)雙向鏈表:+---------------------------------------------------------------+

| |

| mylist 99 98 0 |

| +----+ +---------+ +---------+ +---------+ |

+->|next|--->|list.next|--->|list.next|--->...--->|list.next|---+

|----| |---------| |---------| |---------|

+--|prev|<---|list.prev|<---|list.prev|<---...<---|list.prev|<--+

| +----+ |---------| |---------| |---------| |

| | data | | data | | data | |

| +---------+ +---------+ +---------+ |

| |

+---------------------------------------------------------------+知道了鏈表頭就能遍歷整個(gè)鏈表,如果是用list_add()插入新節(jié)點(diǎn)的話(huà),從鏈表頭的next方向看是一個(gè)堆棧型。從鏈表中刪除節(jié)點(diǎn)很容易:staTIc void del_item(struct my_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í)際地址:#define list_entry(ptr, type, member)

((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))ptr是鏈表元素結(jié)構(gòu)(如struct my_list)中鏈表頭結(jié)構(gòu)list_head的地址

member是鏈表元素結(jié)構(gòu)(如struct my_list)中鏈表頭結(jié)構(gòu)list_head參數(shù)的名稱(chēng)

type是鏈表元素結(jié)構(gòu)類(lèi)型(如struct my_list)計(jì)算原理是根據(jù)鏈表頭結(jié)構(gòu)list_head的地址減去其在鏈表元素結(jié)構(gòu)中的偏移位置而得到鏈表元素結(jié)構(gòu)的地址。例如:static void print_list(void)

{

struct list_head *cur;

struct my_list *p;list_for_each(cur, &mylist){

p=list_entry(cur, struct my_list, list);

printk("data=%dn", p->data);

}

}優(yōu)點(diǎn):這樣就可以用相同的數(shù)據(jù)處理方式來(lái)描述所有雙向鏈表,不用再單獨(dú)為各個(gè)鏈表編寫(xiě)各種編輯函數(shù)。缺點(diǎn):

1) 鏈表頭中元素置為NULL不是初始化,與普通習(xí)慣不同;

2) 仍然需要單獨(dú)編寫(xiě)各自的刪除整個(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è)元素的場(chǎng)合,是一種以空間換時(shí)間的方法,本質(zhì)也是線(xiàn)性表,但由一個(gè)大 的線(xiàn)性表拆分為了多個(gè)小線(xiàn)性表,由于只需要查找小表,因此搜索速度就會(huì)線(xiàn)性查整個(gè)大表提高很多,理想情況下,有多少個(gè)小線(xiàn)性表,搜索速度就提高了多少倍, 通常把小線(xiàn)性表的表頭綜合為一個(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ì)算出來(lái)的結(jié)果能盡可能地平均到每個(gè)索引值, HASH函數(shù)計(jì)算得越平均,表示每個(gè)小表中元素的數(shù)量都會(huì)差不多,這樣搜索性能將越好。HASH函數(shù)也要盡可能的簡(jiǎn)單,以減少計(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(const struct ip_conntrack_tuple *tuple)

{

#if 0

dump_tuple(tuple);

#endif

return (jhash_3words(tuple->src.ip,

(tuple->dst.ip ^ tuple->dst.protonum),

(tuple->src.u.all | (tuple->dst.u.all << 16)),

ip_conntrack_hash_rnd) % ip_conntrack_htable_size);

}// include/linux/jhash.h

static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)

{

a += JHASH_GOLDEN_RATIO;

b += JHASH_GOLDEN_RATIO;

c += initval;__jhash_mix(a, b, c);return c;

}4. 定時(shí)器(timer)linux內(nèi)核定時(shí)器由以下結(jié)構(gòu)描述:/* include/linux/timer.h */

struct timer_list {

struct list_head list;

unsigned long expires;

unsigned long data;

void (*function)(unsigned long);

};list:timer鏈表

expires:到期時(shí)間

function:到期函數(shù),時(shí)間到期時(shí)調(diào)用的函數(shù)

data:傳給到期函數(shù)的數(shù)據(jù),實(shí)際應(yīng)用中通常是一個(gè)指針轉(zhuǎn)化而來(lái),該指針指向一個(gè)結(jié)構(gòu)

timer的操作:增加timer,將timer掛接到系統(tǒng)的timer鏈表:

extern void add_timer(struct timer_list * timer);刪除timer,將timer從系統(tǒng)timer鏈表中拆除:

extern int del_timer(struct timer_list * timer);

(del_timer()函數(shù)可能會(huì)失敗,這是因?yàn)樵搕imer本來(lái)已經(jīng)不在系統(tǒng)timer鏈表中了,也就是已經(jīng)刪除過(guò)了)對(duì)于SMP系統(tǒng),刪除timer最好使用下面的函數(shù)來(lái)防止沖突:

extern int del_timer_sync(struct timer_list * timer);修改timer,修改timer的到期時(shí)間:

int mod_timer(struct timer_list *timer, unsigned long expires);通常用法:

struct timer_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í)鐘中斷的bottom half里的,不能進(jìn)行很復(fù)雜的操作,如果要完成一些復(fù)雜操作,如到期后的數(shù)據(jù)發(fā)送,不能直接在到期函數(shù)中處理,而是應(yīng)該在到期函數(shù)中發(fā)個(gè)信號(hào)給特定內(nèi)核 線(xiàn)程轉(zhuǎn)到top half進(jìn)行處理。為判斷時(shí)間的先后,內(nèi)核中定義了以下宏來(lái)判斷:#define time_after(a,b) ((long)(b) - (long)(a) < 0)

#define time_before(a,b) time_after(b,a)#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)

#define time_before_eq(a,b) time_after_eq(b,a)這里用到了一個(gè)技巧,由于linux中的時(shí)間是無(wú)符號(hào)數(shù),這里先將其轉(zhuǎn)換為有符號(hào)數(shù)后再判斷,就能解決時(shí)間回繞問(wèn)題,當(dāng)然只是一次回繞,回繞兩次當(dāng)然是判斷不出來(lái)的,具體可自己實(shí)驗(yàn)體會(huì)。5. 內(nèi)核線(xiàn)程(kernel_thread)內(nèi)核中新線(xiàn)程的建立可以用kernel_thread函數(shù)實(shí)現(xiàn),該函數(shù)在kernel/fork.c中定義:long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)fn:內(nèi)核線(xiàn)程主函數(shù);

arg:線(xiàn)程主函數(shù)的參數(shù);

flags:建立線(xiàn)程的標(biāo)志;內(nèi)核線(xiàn)程函數(shù)通常都調(diào)用daemonize()進(jìn)行后臺(tái)化作為一個(gè)獨(dú)立的線(xiàn)程運(yùn)行,然后設(shè)置線(xiàn)程的一些參數(shù),如名稱(chēng),信號(hào)處理等,這也不是必須 的,然后就進(jìn)入一個(gè)死循環(huán),這是線(xiàn)程的主體部分,這個(gè)循環(huán)不能一直在運(yùn)行,否則系統(tǒng)就死在這了,或者是某種事件驅(qū)動(dòng)的,在事件到來(lái)前是睡眠的,事件到來(lái)后 喚醒進(jìn)行操作,操作完后繼續(xù)睡眠;或者是定時(shí)睡眠,醒后操作完再睡眠;或者加入等待隊(duì)列通過(guò)schedule()調(diào)度獲得執(zhí)行時(shí)間。總之是不能一直占著 CPU。以下是內(nèi)核線(xiàn)程的一個(gè)實(shí)例,取自kernel/context.c:int start_context_thread(void)

{

static struct completion startup __initdata = COMPLETION_INITIALIZER(startup);kernel_thread(context_thread, &startup, CLONE_FS | CLONE_FILES);

wait_for_completion(&startup);

return 0;

}static int context_thread(void *startup)

{

struct task_struct *curtask = current;

DECLARE_WAITQUEUE(wait, curtask);

struct k_sigaction sa;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((struct completion *)startup);/* Install a handler so SIGCLD is delivered */

sa.sa.sa_handler = SIG_IGN;

sa.sa.sa_flags = 0;

siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));

do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);/*

* If one of the functions on a task queue re-adds itself

* to the task queue we call schedule() in state TASK_RUNNING

*/

for (;;) {

set_task_state(curtask, TASK_INTERRUPTIBLE);

add_wait_queue(&context_task_wq, &wait);

if (TQ_ACTIVE(tq_context))

set_task_state(curtask, TASK_RUNNING);

schedule();

remove_wait_queue(&context_task_wq, &wait);

run_task_queue(&tq_context);

wake_up(&context_task_done);

if (signal_pending(curtask)) {

while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)

;

spin_lock_irq(&curtask->sigmask_lock);

flush_signals(curtask);

recalc_sigpending(curtask);

spin_unlock_irq(&curtask->sigmask_lock);

}

}

}6. 結(jié)構(gòu)地址在C中,結(jié)構(gòu)地址和結(jié)構(gòu)中第一個(gè)元素的地址是相同的,因此在linux內(nèi)核中經(jīng)常出現(xiàn)使用結(jié)構(gòu)第一個(gè)元素的地址來(lái)表示結(jié)構(gòu)地址的情況,在讀代碼時(shí)要注意這一點(diǎn),這和list_entry宏的意思一樣。如:

struct my_struct{

int a;

int b;

}c;if(&c == &c.a){ // always true

...

}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀(guān)點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

上海2025年1月22日 /美通社/ -- 瀾起科技今日宣布推出其最新研發(fā)的PCIe? 6.x/CXL? 3.x Retimer芯片M88RT61632,并已向客戶(hù)成功送樣,旨在為人工智能和云計(jì)算等應(yīng)用場(chǎng)景提供性能更卓越...

關(guān)鍵字: PCIE TIMER 芯片 AI

在本節(jié)中,我們將探究集成模式的數(shù)組,每個(gè)模式都是為了提供無(wú)縫集成解決方案而定制的。這些模式作為結(jié)構(gòu)化的框架,促進(jìn)了不同系統(tǒng)之間的聯(lián)系和數(shù)據(jù)交換。它們大致分為三類(lèi):

關(guān)鍵字: 數(shù)據(jù)整合 數(shù)據(jù)結(jié)構(gòu)

學(xué)習(xí)C語(yǔ)言是程序員的入門(mén)教育,但是在學(xué)習(xí)過(guò)程中,常常會(huì)遇到一些常見(jiàn)的誤區(qū)。這些誤區(qū)可能會(huì)讓學(xué)習(xí)者的學(xué)習(xí)經(jīng)驗(yàn)不佳,影響到他們掌握該語(yǔ)言的能力。

關(guān)鍵字: C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)

常用的數(shù)據(jù)結(jié)構(gòu)可根據(jù)數(shù)據(jù)訪(fǎng)問(wèn)的特點(diǎn)分為線(xiàn)性結(jié)構(gòu)和非線(xiàn)性結(jié)構(gòu)。線(xiàn)性結(jié)構(gòu)包括常見(jiàn)的鏈表、棧、隊(duì)列等,非線(xiàn)性結(jié)構(gòu)包括樹(shù)、圖等。

關(guān)鍵字: 數(shù)據(jù)結(jié)構(gòu) 非線(xiàn)性結(jié)構(gòu)

堆(heap)和棧(stack)是在計(jì)算機(jī)中常用的兩種數(shù)據(jù)結(jié)構(gòu)。它們具有不同的特點(diǎn)和用途,對(duì)于程序員來(lái)說(shuō),了解堆和棧的區(qū)別是非常重要的。

關(guān)鍵字: 內(nèi)存 數(shù)據(jù)結(jié)構(gòu)

上海2023年1月6日 /美通社/ -- 國(guó)際領(lǐng)先的數(shù)據(jù)處理及互連芯片設(shè)計(jì)公司瀾起科技今天宣布,其PCIe 5.0/CXL 2.0 Retimer芯片成功實(shí)現(xiàn)量產(chǎn)。該芯片是瀾起科技現(xiàn)有PCIe 4.0 Retimer產(chǎn)品...

關(guān)鍵字: PCIE TIMER 芯片 AI

南京2022年10月27日 /美通社/ -- 10月18日,由南瑞集團(tuán)主導(dǎo)編制的IEC國(guó)際標(biāo)準(zhǔn)《電動(dòng)汽車(chē)充電漫游服務(wù)信息交互 第2部分:用例》(IEC 63119-2:2022)正式發(fā)布。該標(biāo)準(zhǔn)的發(fā)布是南瑞集團(tuán)在國(guó)際電動(dòng)...

關(guān)鍵字: 電動(dòng)汽車(chē)充電 充電站 數(shù)據(jù)結(jié)構(gòu) 電動(dòng)汽車(chē)電池

大家都聽(tīng)說(shuō)過(guò)紅黑樹(shù),也都知道紅黑樹(shù)很厲害,是計(jì)算機(jī)里面評(píng)價(jià)非常高的數(shù)據(jù)結(jié)構(gòu)。但是每當(dāng)想學(xué)習(xí)紅黑樹(shù)的時(shí)候,卻總是找不到通俗易懂很好理解的學(xué)習(xí)資料。很多書(shū)上上來(lái)就是紅黑樹(shù)的定義,然后就是紅黑樹(shù)的實(shí)現(xiàn),直接就把人給整暈了。光看...

關(guān)鍵字: 計(jì)算機(jī) 數(shù)據(jù)結(jié)構(gòu) 紅黑樹(shù)

(全球TMT2022年7月11日訊)7月7日,由徑碩科技(JINGdigital)主辦、MEC睿達(dá)會(huì)承辦的“萬(wàn)數(shù)有靈·2022中國(guó)數(shù)字營(yíng)銷(xiāo)創(chuàng)新增長(zhǎng)峰會(huì)”在深圳舉行。作為一家營(yíng)銷(xiāo)科技公司,徑碩科技提供的是一流的營(yíng)銷(xiāo)軟件產(chǎn)...

關(guān)鍵字: CE DIGITAL 數(shù)字化 數(shù)據(jù)結(jié)構(gòu)

Redis為什么那么快?除了它是內(nèi)存數(shù)據(jù)庫(kù),使得所有的操作都在內(nèi)存上進(jìn)行之外,還有一個(gè)重要因素,它實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu),使得我們對(duì)數(shù)據(jù)進(jìn)行增刪查改操作時(shí),Redis能高效的處理。因此,這次我們就來(lái)好好聊一下Redis數(shù)據(jù)結(jié)構(gòu),...

關(guān)鍵字: 數(shù)據(jù)結(jié)構(gòu) REDIS 字符串 節(jié)點(diǎn)
關(guān)閉