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