(六)3中斷下半部之工作佇列
1、工作佇列的使用
按慣例,在介紹工作佇列如何實現之前,先說說如何使用工作佇列實現下半部。
步驟一、定義並初始化工作佇列:
建立工作佇列函式:
struct workqueue_struct *create_workqueue(const char *name)
函式傳參是核心中工作佇列的名稱,返回值是workqueue_struct結構體的指標,該結構體用來維護一個等待佇列。
我的程式碼如下:
/*6th_irq_3/4th/test.c*/
14 struct workqueue_struct *xiaobai_wq; //定義工作佇列
33 xiaobai_wq = create_workqueue("xiaobai");
步驟二、定義並初始化work結構體:
核心使用結構體來維護一個加入工作佇列的任務:
/*linux/workqueue.h*/
25 struct work_struct {
26 atomic_long_t data;
27 #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
28 #define WORK_STRUCT_FLAG_MASK (3UL)
29 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
30 struct list_head entry;
31 work_func_t func; //這個是重點,下半部實現的處理函式指標就放在這
32 #ifdef CONFIG_LOCKDEP
33 struct lockdep_map lockdep_map;
34 #endif
35 };
同樣有靜態和動態兩種方法:
靜態定義並初始化work結構體:
/*linux/workqueue.h*/
72 #define DECLARE_WORK(n, f) \
73 struct work_struct n = __WORK_INITIALIZER(n, f)
定義並初始化一個叫n的work_struct資料結構,它對應的的處理函式是
對應的動態初始化方法,該函式返回work_struct指標,所以需要先定義一個work_struct結構:
/*linux/workqueue.h*/
107 #define INIT_WORK(_work, _func) \
108 do { \
109 (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
110 INIT_LIST_HEAD(&(_work)->entry); \
111 PREPARE_WORK((_work), (_func)); \
112 } while (0)
113 #endif
跟tasklet一樣,在初始化的同時,需要將處理函式實現,程式碼如下:
/*6th_irq_3/4th/test.c*/
15 struct work_struct xiaobai_work; //定義work結構體
16
17 void xiaobai_func(struct work_struct *work) //處理函式
18 {
19 printk("hello xiaobai!\n"); //同樣什麼都沒幹,只是列印
20 }
34 INIT_WORK(&xiaobai_work, xiaobai_func); //初始化work結構體
步驟三、在中斷處理函式中排程任務:
工作佇列和worl結構體都已經實現了,接下來就可以排程了,使用一下函式:
/*kernel/workqueue.c*/
161 int queue_work(struct workqueue_struct *wq, struct work_struct *work)
將指定的任務(work_struct),新增到指定的工作佇列中。同樣的,排程並不代表處理函式能夠馬上執行,這由核心程序排程決定。
步驟四、在解除安裝模組時,重新整理並登出等待佇列:
重新整理等待佇列函式:
/*kernel/workqueue.c*/
411 void flush_workqueue(struct workqueue_struct *wq)
該函式會一直等待,知道指定的等待佇列中所有的任務都執行完畢並從等待佇列中移除。
登出等待佇列:
/*kernel/workqueue.c*/
904 void destroy_workqueue(struct workqueue_struct *wq)
該函式是是建立等待佇列的反操作,登出掉指定的等待佇列。
四個步驟講完,貼個程式碼:
/*6th_irq_3/4th/test.c*/
1 #include
2 #include
3
4 #include
5 #include
6
7 #define DEBUG_SWITCH 1
8 #if DEBUG_SWITCH
9 #define P_DEBUG(fmt, args...) printk("<1>" "[%s]"fmt, __FUNCTI ON__, ##args)
10 #else
11 #define P_DEBUG(fmt, args...) printk("<7>" "[%s]"fmt, __FUNCTI ON__, ##args)
12 #endif
13
14 struct workqueue_struct *xiaobai_wq; //1.定義工作佇列
15 struct work_struct xiaobai_work; //2定義work結構體
16
17 void xiaobai_func(struct work_struct *work) //2實現處理函式
18 {
19 printk("hello xiaobai!\n");
20 }
21
22 irqreturn_t irq_handler(int irqno, void *dev_id)
23 {
24 printk("key down\n");
25 queue_work(xiaobai_wq ,&xiaobai_work); //3排程任務
26 return IRQ_HANDLED;
27 }
28 static int __init test_init(void) //模組初始化函式
29 {
30 int ret;
31
32 /*work*/
33 xiaobai_wq = create_workqueue("xiaobai"); //1初始化工作對列
34 INIT_WORK(&xiaobai_work, xiaobai_func); //2初始化work結構體
35
36 ret = request_irq(IRQ_EINT1, irq_handler,
37 IRQF_TRIGGER_FALLING, "key INT_EINT1", NULL);
38 if(ret){
39 P_DEBUG("request irq failed!\n");
40 return ret;
41 }
42
43 printk("hello irq\n");
44 return 0;
45 }
46
47 static void __exit test_exit(void) //模組解除安裝函式
48 {
49 flush_workqueue(xiaobai_wq); //4重新整理工作佇列
50 destroy_workqueue(xiaobai_wq); //4登出工作佇列
51 free_irq(IRQ_EINT1, NULL);
52 printk("good bye irq\n");
53 }
54
55 module_init(test_init);
56 module_exit(test_exit);
57
58 MODULE_LICENSE("GPL");
59 MODULE_AUTHOR("xoao bai");
60 MODULE_VERSION("v0.1");
和以往的一樣,下半部僅僅是列印,沒實質操作,看效果:
[root: 4th]# insmod test.ko
hello irq
[root: 4th]# key down
hello xiaobai!
key down
hello xiaobai!
[root: 4th]# rmmod test
good bye irq
二、使用共享的工作佇列
在核心中有一個預設的工作佇列events,使用共享的工作佇列可以省去建立和登出工作佇列的步驟。當然,佇列是共享的,用起來當然會不爽,如果有多個不同的任務都加入到這個工作對列中,每個任務排程的速度就會比較慢,肯定不如自己建立一個爽。不過,一般預設工作佇列都能滿足要求,不需要建立一個新的。
少了上面建立和登出等待佇列兩步,使用共享工作佇列步驟相對少一點
步驟一、實現處理函式,定義並初始化work結構體:
這一步驟上一節介紹的步驟二完全一樣,所以就不說了。
步驟二、排程任務:
預設工作佇列的中任務的排程不需要指定工作對列,所以函式有所不同:
/*kernel/workqueue.c*/
620 int schedule_work(struct work_struct *work)
該函式會把work_struct結構體加入到預設工作對列events中。
上函式:
/*6th_irq_3/3rd/test.c*/
1 #include
2 #include
3
4 #include
5 #include
6
7 #define DEBUG_SWITCH 1
8 #if DEBUG_SWITCH
9 #define P_DEBUG(fmt, args...) printk("<1>" "[%s]"fmt, __FUNCTI ON__, ##args)
10 #else
11 #define P_DEBUG(fmt, args...) printk("<7>" "[%s]"fmt, __FUNCTI ON__, ##args)
12 #endif
13
14 struct work_struct xiaobai_work; //定義work結構體
15
16 void xiaobai_func(struct work_struct *work)
17 {
18 printk("hello xiaobai!\n");
19 }
20
21 irqreturn_t irq_handler(int irqno, void *dev_id) //中斷處理函式
22 {
23 printk("key down\n");
24 schedule_work(&xiaobai_work); //排程任務
25 return IRQ_HANDLED;
26 }
27 static int __init test_init(void) //模組初始化函式
28 {
29 int ret;
30
31 /*work*/
32 INIT_WORK(&xiaobai_work, xiaobai_func); //初始化worl結構體
33
34 ret = request_irq(IRQ_EINT1, irq_handler,
35 IRQF_TRIGGER_FALLING, "key INT_EINT1", NULL);
36 if(ret){
37 P_DEBUG("request irq failed!\n");
38 return ret;
39 }
40
41 printk("hello irq\n");
42 return 0;
43 }
44
45 static void __exit test_exit(void) //模組解除安裝函式
46 {
47 free_irq(IRQ_EINT1, NULL);
48 printk("good bye irq\n");
相關推薦
(六)3中斷下半部之工作佇列
1、工作佇列的使用 按慣例,在介紹工作佇列如何實現之前,先說說如何使用工作佇列實現下半部。 步驟一、定義並初始化工作佇列: 建立工作佇列函式: struct workqueue_struct *create_workqueue(const char *nam
linux裝置驅動歸納總結(六):3.中斷下半部之tasklet
linux裝置驅動歸納總結(六):3.中斷的上半部和下半部——tasklet xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一、什麼是下半部 中斷是一個很霸道的東西,處理
中斷服務下半部之工作佇列【轉】
1 工作佇列概述 工作佇列 (work queue) 是另外一種將工作推後執行的形式,它和我們前面討論的所有其他形式都不相同。工作佇列可以把工作推後,交由一個核心執行緒去執行—這個下半部分總是會在程序上下文執行,但由於是核心執行緒,其不能訪問使用者空間。 最重要
中斷下半部_工作佇列(work queue)
1>work_queue:<linux/workqueue.h> __3.0.4 2>description: 中斷下半部,在核心執行緒的程序上下文中執行推後的工作. 它是唯一能在程序上下文執行的中斷下半部實現機制,也只有它才可以睡眠. 3>建
linux 觸控式螢幕驅動中斷下半部實現-工作佇列
工作佇列(work queue)是Linux kernel中將工作推後執行的一種機制。這種機制和BH或Tasklets不同之處在於工作佇列是把推後的工作交由一個核心執行緒去執行,因此工作佇列的優勢就在於它允許重新排程甚至睡眠。工作佇列可以把工作推後,交由一個核心執行緒去執
FFmpeg總結(六)AV系列結構體之AVPacket
type 獲得 tty his err views pen required pan AVPacket位置:libavcodec/avcodec.h下: AVPacket: 通常通過demuxer導出的data packet作為解碼器的inpu
【NOIP模擬賽(六)】花園的守護之神(greendam)-最短路-最大流最小割
greate make rand pair bsp min com solution bool Problem Greemdam 題目大意 給一個圖$G=(V,E)$,求要使這個圖的最短路增長所需要增加的最小權值的值。 Solution 既然是要求這個玩意兒,我們可
Scala入門系列(六):面向對象之object
所有 name 應用 eight lac box dfa port clas object Person { private var eyeNum = 2 println("this Person object") def getEyeNum = eyeNum
編譯原理(六)自底向上分析之LR分析法
markdown lr分析 編譯原理 lock mar blog pre 分析法 logs 自底向上分析之LR分析法 說明:以老師PPT為標準,借鑒部分教材內容,AlvinZH學習筆記。 本節內容太多了,考完再寫了,對不起~ 引用說明 - 邵老師課堂PDF - 《編譯原
Golang從入門到精通(六):Golang控制語句之for
for結構介紹 Go語言只有for迴圈這一種迴圈結構。 基本的for迴圈包含三個由分號分開的組成部分: 1.初始化語句:在第一次迴圈執行前被執行 2.迴圈條件表示式:每輪迭代開始前被求值 3.後置語句:每輪迭代後被執行 初始化語句一般是一個短變數宣告
學習筆記(六)ubuntu16.04下Sublime Text3配置anaconda和tensorflow
注:本文非標準教程,僅是總結個人學習過程,可能存在紕漏,如有錯誤之處歡迎留言告知,非常感謝 上一篇學習筆記是使用IPYTHON去編譯tensorflow,但是我沒有圖形化介面實在不習慣,於是下了很多 IDE嘗試去編譯tensorflow,但是一律都是
(六)ArcGIS API For Javascript之查詢功能
1.引言 在ArcGIS API中查詢功能是非常常用的,Esri給我們提供了三個類用於實現向量資料查詢功能。FindTask,QueryTask,IdentifyTask,他們之間的區別為: FindTask只能進行屬性查詢,QueryTask,
Scrapy研究探索(六)——自動爬取網頁之II(CrawlSpider)
一.目的。 在pipelines.py中實現獲得資料的過濾以及儲存。 但是以上述方法只能爬取start_url列表中的網頁,而網路爬蟲如google等搜尋引擎爬蟲實現的就是對整個網際網路的爬取,所以在本教程中研究使用scrapy自動實現多網頁爬取功能。 二.熱身。
別樣JAVA學習(六)繼承下(2.3)異常下
關閉 exit dsm 練習 方便 pub xtend 運行 script 1、RuntimeException Exception中有一個特殊的子類異常RuntimeException執行時異常。 假設在函數內容拋出該異常,函數上能夠不用聲明。編譯一樣
《Linux內核設計與實現》讀書筆記(八)- 中斷下半部的處理
sym dmesg 重新編譯 warn dad style lsp 之前 res 在前一章也提到過,之所以中斷會分成上下兩部分,是由於中斷對時限的要求非常高,需要盡快的響應硬件。 主要內容: 中斷下半部處理 實現中斷下半部的機制 總結中斷下半部的實現 中斷實現
Elam的caffe筆記之配置篇(六):Centos6.5下編譯caffe及caffe的python3.6介面
Elam的caffe筆記之配置篇(六):Centos6.5下編譯caffe及caffe的python3.6介面 配置要求: 系統:centos6.5 目標:基於CUDA8.0+Opencv3.1+Cudnnv5.1+python3.6介面的caffe框架 綜合來說,caf
嵌入式核心及驅動開發之學習筆記(六) 驅動層中斷實現
由於中斷訊號的突發性,CPU要捕獲中斷訊號,有兩種方式。一是不斷輪詢是否有中斷髮生,這樣有點傻;二是通過中斷機制,過程如下: 中斷源 ---> 中斷訊號 ---> 中斷控制器 ---> CPU 中斷源有很多,CPU拿
Redis叢集之主從複製,讀寫分離(下)(六)
上一次呢我們講到了redis的叢集,還有redis的主從複製,讀寫分離的一些配置,那麼接下來就接著上次還未完結的內容 上一次呢講的是在正常的情況下redis服務在各個主機上的執行情況,那麼接下來就是要介紹不正常的情況了。 假如說我們的redis的主庫掛了或者
spring4.2.9 java專案環境下ioc原始碼分析(六)——refresh之obtainFreshBeanFactory方法(@4預設標籤bean,beans解析、最終註冊)
接上篇文章,解析了import和alias標籤,只是開胃菜比較簡單,下面介紹bean標籤的載入,也是預設名稱空間下解析的重點。protected void processBeanDefinition(Element ele, BeanDefinitionParserDeleg
Linux kernel的中斷子系統之(六):ARM中斷處理過程
總結:二中斷處理經過兩種模式:IRQ模式和SVC模式,這兩種模式都有自己的stack,同時涉及到異常向量表中的中斷向量。 三ARM處理器在感知到中斷之後,切換CPSR暫存器模式到IRQ;儲存CPSR和PC;mask irq;PC指向irq vector。 四進入中斷的IRQ模式相關處理,然後根據當前處於使用