中断处理的tasklet(小任务)机制-不过如此
生活随笔
收集整理的這篇文章主要介紹了
中断处理的tasklet(小任务)机制-不过如此
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
中斷服務(wù)程序一般都是在中斷請(qǐng)求關(guān)閉的條件下執(zhí)行的,以避免嵌套而使中斷控制復(fù)雜化。但是,中斷是一個(gè)隨機(jī)事件,它隨時(shí)會(huì)到來,如果關(guān)中斷的時(shí)間太長(zhǎng),CPU就不能及時(shí)響應(yīng)其他的中斷請(qǐng)求,從而造成中斷的丟失。因此,內(nèi)核的目標(biāo)就是盡可能快的處理完中斷請(qǐng)求,盡其所能把更多的處理向后推遲。例如,假設(shè)一個(gè)數(shù)據(jù)塊已經(jīng)達(dá)到了網(wǎng)線,當(dāng)中斷控制器接受到這個(gè)中斷請(qǐng)求信號(hào)時(shí),Linux內(nèi)核只是簡(jiǎn)單地標(biāo)志數(shù)據(jù)到來了,然后讓處理器恢復(fù)到它以前運(yùn)行的狀態(tài),其余的處理稍后再進(jìn)行(如把數(shù)據(jù)移入一個(gè)緩沖區(qū),接受數(shù)據(jù)的進(jìn)程就可以在緩沖區(qū)找到數(shù)據(jù))。因此,內(nèi)核把中斷處理分為兩部分:上半部(top half)和下半部(bottom half),上半部(就是中斷服務(wù)程序)內(nèi)核立即執(zhí)行,而下半部(就是一些內(nèi)核函數(shù))留著稍后處理。
??????? 首先,一個(gè)快速的“上半部”來處理硬件發(fā)出的請(qǐng)求,它必須在一個(gè)新的中斷產(chǎn)生之前終止。通常,除了在設(shè)備和一些內(nèi)存緩沖區(qū)(如果你的設(shè)備用到了DMA,就不止這些)之間移動(dòng)或傳送數(shù)據(jù),確定硬件是否處于健全的狀態(tài)之外,這一部分做的工作很少。
??????? 下半部運(yùn)行時(shí)是允許中斷請(qǐng)求的,而上半部運(yùn)行時(shí)是關(guān)中斷的,這是二者之間的主要區(qū)別。
??????? 但是,內(nèi)核到底什時(shí)候執(zhí)行下半部,以何種方式組織下半部?這就是我們要討論的下半部實(shí)現(xiàn)機(jī)制,這種機(jī)制在內(nèi)核的演變過程中不斷得到改進(jìn),在以前的內(nèi)核中,這個(gè)機(jī)制叫做bottom half(簡(jiǎn)稱bh),在2.4以后的版本中有了新的發(fā)展和改進(jìn),改進(jìn)的目標(biāo)使下半部可以在多處理機(jī)上并行執(zhí)行,并有助于驅(qū)動(dòng)程序的開發(fā)者進(jìn)行驅(qū)動(dòng)程序的開發(fā)。下面主要介紹常用的小任務(wù)(Tasklet)機(jī)制及2.6內(nèi)核中的工作隊(duì)列機(jī)制。除此之外,還簡(jiǎn)要介紹2.4以前內(nèi)核中的下半部和任務(wù)隊(duì)列機(jī)制。
1. 小任務(wù)機(jī)制??
??????? 這里的小任務(wù)是指對(duì)要推遲執(zhí)行的函數(shù)進(jìn)行組織的一種機(jī)制。其數(shù)據(jù)結(jié)構(gòu)為tasklet_struct,每個(gè)結(jié)構(gòu)代表一個(gè)獨(dú)立的小任務(wù),其定義如下:
??????? 結(jié)構(gòu)中的func域就是下半部中要推遲執(zhí)行的函數(shù) ,data是它唯一的參數(shù)。
??????? State域的取值為TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任務(wù)已被調(diào)度,正準(zhǔn)備投入運(yùn)行,TASKLET_STATE_RUN表示小任務(wù)正在運(yùn)行。TASKLET_STATE_RUN只有在多處理器系統(tǒng)上才使用,單處理器系統(tǒng)什么時(shí)候都清楚一個(gè)小任務(wù)是不是正在運(yùn)行(它要么就是當(dāng)前正在執(zhí)行的代碼,要么不是)。
??????? Count域是小任務(wù)的引用計(jì)數(shù)器。如果它不為0,則小任務(wù)被禁止,不允許執(zhí)行;只有當(dāng)它為零,小任務(wù)才被激活,并且在被設(shè)置為掛起時(shí),小任務(wù)才能夠執(zhí)行。
2. 聲明和使用小任務(wù)
??????? 大多數(shù)情況下,為了控制一個(gè)尋常的硬件設(shè)備,小任務(wù)機(jī)制是實(shí)現(xiàn)下半部的最佳選擇。小任務(wù)可以動(dòng)態(tài)創(chuàng)建,使用方便,執(zhí)行起來也比較快。
??????? 我們既可以靜態(tài)地創(chuàng)建小任務(wù),也可以動(dòng)態(tài)地創(chuàng)建它。選擇那種方式取決于到底是想要對(duì)小任務(wù)進(jìn)行直接引用還是一個(gè)間接引用。如果準(zhǔn)備靜態(tài)地創(chuàng)建一個(gè)小任務(wù)(也就是對(duì)它直接引用),使用下面兩個(gè)宏中的一個(gè):
??????? 這兩個(gè)宏都能根據(jù)給定的名字靜態(tài)地創(chuàng)建一個(gè)tasklet_struct結(jié)構(gòu)。當(dāng)該小任務(wù)被調(diào)度以后,給定的函數(shù)func會(huì)被執(zhí)行,它的參數(shù)由data給出。這兩個(gè)宏之間的區(qū)別在于引用計(jì)數(shù)器的初始值設(shè)置不同。第一個(gè)宏把創(chuàng)建的小任務(wù)的引用計(jì)數(shù)器設(shè)置為0,因此,該小任務(wù)處于激活狀態(tài)。另一個(gè)把引用計(jì)數(shù)器設(shè)置為1,所以該小任務(wù)處于禁止?fàn)顟B(tài)。例如:
??????? 這行代碼其實(shí)等價(jià)于
??????? 這樣就創(chuàng)建了一個(gè)名為my_tasklet的小任務(wù),其處理程序?yàn)閠asklet_handler,并且已被激活。當(dāng)處理程序被調(diào)用的時(shí)候,dev就會(huì)被傳遞給它。
3. 編寫自己的小任務(wù)處理程序
??????? 小任務(wù)處理程序必須符合如下的函數(shù)類型:
??????? 由于小任務(wù)不能睡眠,因此不能在小任務(wù)中使用信號(hào)量或者其它產(chǎn)生阻塞的函數(shù)。但是小任務(wù)運(yùn)行時(shí)可以響應(yīng)中斷。
4. 調(diào)度自己的小任務(wù)
??????? 通過調(diào)用tasklet_schedule()函數(shù)并傳遞給它相應(yīng)的tasklt_struct指針,該小任務(wù)就會(huì)被調(diào)度以便適當(dāng)?shù)臅r(shí)候執(zhí)行:
??????? 在小任務(wù)被調(diào)度以后,只要有機(jī)會(huì)它就會(huì)盡可能早的運(yùn)行。在它還沒有得到運(yùn)行機(jī)會(huì)之前,如果一個(gè)相同的小任務(wù)又被調(diào)度了,那么它仍然只會(huì)運(yùn)行一次。
??????? 可以調(diào)用tasklet_disable()函數(shù)來禁止某個(gè)指定的小任務(wù)。如果該小任務(wù)當(dāng)前正在執(zhí)行,這個(gè)函數(shù)會(huì)等到它執(zhí)行完畢再返回。調(diào)用tasklet_enable()函數(shù)可以激活一個(gè)小任務(wù),如果希望把以DECLARE_TASKLET_DISABLED()創(chuàng)建的小任務(wù)激活,也得調(diào)用這個(gè)函數(shù),如:
??????? 也可以調(diào)用tasklet_kill()函數(shù)從掛起的隊(duì)列中去掉一個(gè)小任務(wù)。該函數(shù)的參數(shù)是一個(gè)指向某個(gè)小任務(wù)的tasklet_struct的長(zhǎng)指針。在小任務(wù)重新調(diào)度它自身的時(shí)候,從掛起的隊(duì)列中移去已調(diào)度的小任務(wù)會(huì)很有用。這個(gè)函數(shù)首先等待該小任務(wù)執(zhí)行完畢,然后再將它移去。
5. tasklet的簡(jiǎn)單用法
??????? 下面是tasklet的一個(gè)簡(jiǎn)單應(yīng)用, 以模塊的形成加載。
??????? 從這個(gè)例子可以看出,所謂的小任務(wù)機(jī)制是為下半部函數(shù)的執(zhí)行提供了一種執(zhí)行機(jī)制,也就是說,推遲處理的事情是由tasklet_handler實(shí)現(xiàn),何時(shí)執(zhí)行,經(jīng)由小任務(wù)機(jī)制封裝后交給內(nèi)核去處理。
??????? 首先,一個(gè)快速的“上半部”來處理硬件發(fā)出的請(qǐng)求,它必須在一個(gè)新的中斷產(chǎn)生之前終止。通常,除了在設(shè)備和一些內(nèi)存緩沖區(qū)(如果你的設(shè)備用到了DMA,就不止這些)之間移動(dòng)或傳送數(shù)據(jù),確定硬件是否處于健全的狀態(tài)之外,這一部分做的工作很少。
??????? 下半部運(yùn)行時(shí)是允許中斷請(qǐng)求的,而上半部運(yùn)行時(shí)是關(guān)中斷的,這是二者之間的主要區(qū)別。
??????? 但是,內(nèi)核到底什時(shí)候執(zhí)行下半部,以何種方式組織下半部?這就是我們要討論的下半部實(shí)現(xiàn)機(jī)制,這種機(jī)制在內(nèi)核的演變過程中不斷得到改進(jìn),在以前的內(nèi)核中,這個(gè)機(jī)制叫做bottom half(簡(jiǎn)稱bh),在2.4以后的版本中有了新的發(fā)展和改進(jìn),改進(jìn)的目標(biāo)使下半部可以在多處理機(jī)上并行執(zhí)行,并有助于驅(qū)動(dòng)程序的開發(fā)者進(jìn)行驅(qū)動(dòng)程序的開發(fā)。下面主要介紹常用的小任務(wù)(Tasklet)機(jī)制及2.6內(nèi)核中的工作隊(duì)列機(jī)制。除此之外,還簡(jiǎn)要介紹2.4以前內(nèi)核中的下半部和任務(wù)隊(duì)列機(jī)制。
1. 小任務(wù)機(jī)制??
??????? 這里的小任務(wù)是指對(duì)要推遲執(zhí)行的函數(shù)進(jìn)行組織的一種機(jī)制。其數(shù)據(jù)結(jié)構(gòu)為tasklet_struct,每個(gè)結(jié)構(gòu)代表一個(gè)獨(dú)立的小任務(wù),其定義如下:
| struct tasklet_struct { struct tasklet_struct *next;??????? /*指向鏈表中的下一個(gè)結(jié)構(gòu)*/ ???? unsigned long state;??????????? /* 小任務(wù)的狀態(tài) */ ???? atomic_t count;??? /* 引用計(jì)數(shù)器 */ ???? void (*func) (unsigned long);??????????? /* 要調(diào)用的函數(shù) */ ???? unsigned long data;?????????? /* 傳遞給函數(shù)的參數(shù) */ }; |
??????? State域的取值為TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任務(wù)已被調(diào)度,正準(zhǔn)備投入運(yùn)行,TASKLET_STATE_RUN表示小任務(wù)正在運(yùn)行。TASKLET_STATE_RUN只有在多處理器系統(tǒng)上才使用,單處理器系統(tǒng)什么時(shí)候都清楚一個(gè)小任務(wù)是不是正在運(yùn)行(它要么就是當(dāng)前正在執(zhí)行的代碼,要么不是)。
??????? Count域是小任務(wù)的引用計(jì)數(shù)器。如果它不為0,則小任務(wù)被禁止,不允許執(zhí)行;只有當(dāng)它為零,小任務(wù)才被激活,并且在被設(shè)置為掛起時(shí),小任務(wù)才能夠執(zhí)行。
2. 聲明和使用小任務(wù)
??????? 大多數(shù)情況下,為了控制一個(gè)尋常的硬件設(shè)備,小任務(wù)機(jī)制是實(shí)現(xiàn)下半部的最佳選擇。小任務(wù)可以動(dòng)態(tài)創(chuàng)建,使用方便,執(zhí)行起來也比較快。
??????? 我們既可以靜態(tài)地創(chuàng)建小任務(wù),也可以動(dòng)態(tài)地創(chuàng)建它。選擇那種方式取決于到底是想要對(duì)小任務(wù)進(jìn)行直接引用還是一個(gè)間接引用。如果準(zhǔn)備靜態(tài)地創(chuàng)建一個(gè)小任務(wù)(也就是對(duì)它直接引用),使用下面兩個(gè)宏中的一個(gè):
| DECLARE_TASKLET(name, func, data) DECLARE_TASKLET_DISABLED(name, func, data) |
??????? 這兩個(gè)宏都能根據(jù)給定的名字靜態(tài)地創(chuàng)建一個(gè)tasklet_struct結(jié)構(gòu)。當(dāng)該小任務(wù)被調(diào)度以后,給定的函數(shù)func會(huì)被執(zhí)行,它的參數(shù)由data給出。這兩個(gè)宏之間的區(qū)別在于引用計(jì)數(shù)器的初始值設(shè)置不同。第一個(gè)宏把創(chuàng)建的小任務(wù)的引用計(jì)數(shù)器設(shè)置為0,因此,該小任務(wù)處于激活狀態(tài)。另一個(gè)把引用計(jì)數(shù)器設(shè)置為1,所以該小任務(wù)處于禁止?fàn)顟B(tài)。例如:
| DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev); |
??????? 這行代碼其實(shí)等價(jià)于
| struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler, dev}; |
??????? 這樣就創(chuàng)建了一個(gè)名為my_tasklet的小任務(wù),其處理程序?yàn)閠asklet_handler,并且已被激活。當(dāng)處理程序被調(diào)用的時(shí)候,dev就會(huì)被傳遞給它。
3. 編寫自己的小任務(wù)處理程序
??????? 小任務(wù)處理程序必須符合如下的函數(shù)類型:
| void tasklet_handler(unsigned long data) |
??????? 由于小任務(wù)不能睡眠,因此不能在小任務(wù)中使用信號(hào)量或者其它產(chǎn)生阻塞的函數(shù)。但是小任務(wù)運(yùn)行時(shí)可以響應(yīng)中斷。
4. 調(diào)度自己的小任務(wù)
??????? 通過調(diào)用tasklet_schedule()函數(shù)并傳遞給它相應(yīng)的tasklt_struct指針,該小任務(wù)就會(huì)被調(diào)度以便適當(dāng)?shù)臅r(shí)候執(zhí)行:
| tasklet_schedule(&my_tasklet);? /*把 my_tasklet 標(biāo)記為掛起 */ |
??????? 在小任務(wù)被調(diào)度以后,只要有機(jī)會(huì)它就會(huì)盡可能早的運(yùn)行。在它還沒有得到運(yùn)行機(jī)會(huì)之前,如果一個(gè)相同的小任務(wù)又被調(diào)度了,那么它仍然只會(huì)運(yùn)行一次。
??????? 可以調(diào)用tasklet_disable()函數(shù)來禁止某個(gè)指定的小任務(wù)。如果該小任務(wù)當(dāng)前正在執(zhí)行,這個(gè)函數(shù)會(huì)等到它執(zhí)行完畢再返回。調(diào)用tasklet_enable()函數(shù)可以激活一個(gè)小任務(wù),如果希望把以DECLARE_TASKLET_DISABLED()創(chuàng)建的小任務(wù)激活,也得調(diào)用這個(gè)函數(shù),如:
| tasklet_disable(&my_tasklet);???? /* 小任務(wù)現(xiàn)在被禁止,這個(gè)小任務(wù)不能運(yùn)行 */ tasklet_enable(&my_tasklet);??? /*? 小任務(wù)現(xiàn)在被激活 */ |
??????? 也可以調(diào)用tasklet_kill()函數(shù)從掛起的隊(duì)列中去掉一個(gè)小任務(wù)。該函數(shù)的參數(shù)是一個(gè)指向某個(gè)小任務(wù)的tasklet_struct的長(zhǎng)指針。在小任務(wù)重新調(diào)度它自身的時(shí)候,從掛起的隊(duì)列中移去已調(diào)度的小任務(wù)會(huì)很有用。這個(gè)函數(shù)首先等待該小任務(wù)執(zhí)行完畢,然后再將它移去。
5. tasklet的簡(jiǎn)單用法
??????? 下面是tasklet的一個(gè)簡(jiǎn)單應(yīng)用, 以模塊的形成加載。
| #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/kernel.h> #include <linux/interrupt.h> static struct tasklet_struct my_tasklet; static void tasklet_handler (unsigned long data) { ??????? printk(KERN_ALERT “tasklet_handler is running.n”); } static int __init test_init(void) { ??????? tasklet_init(&my_tasklet, tasklet_handler, 0); ??????? tasklet_schedule(&my_tasklet); ??????? return 0; } static void __exit test_exit(void) { ??????? tasklet_kill(&tasklet); ??????? printk(KERN_ALERT “test_exit running.n”); } MODULE_LICENSE(“GPL”); module_init(test_init); module_exit(test_exit); |
??????? 從這個(gè)例子可以看出,所謂的小任務(wù)機(jī)制是為下半部函數(shù)的執(zhí)行提供了一種執(zhí)行機(jī)制,也就是說,推遲處理的事情是由tasklet_handler實(shí)現(xiàn),何時(shí)執(zhí)行,經(jīng)由小任務(wù)機(jī)制封裝后交給內(nèi)核去處理。
總結(jié)
以上是生活随笔為你收集整理的中断处理的tasklet(小任务)机制-不过如此的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库可疑
- 下一篇: 软件测试按照各种方式分类