1. 程式人生 > >(六)3中斷下半部之工作佇列

(六)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)

定義並初始化一個叫nwork_struct資料結構,它對應的的處理函式是

f

對應的動態初始化方法,該函式返回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.04Sublime Text3配置anaconda和tensorflow

注:本文非標準教程,僅是總結個人學習過程,可能存在紕漏,如有錯誤之處歡迎留言告知,非常感謝 上一篇學習筆記是使用IPYTHON去編譯tensorflow,但是我沒有圖形化介面實在不習慣,於是下了很多 IDE嘗試去編譯tensorflow,但是一律都是

ArcGIS API For Javascript查詢功能

1.引言 在ArcGIS API中查詢功能是非常常用的,Esri給我們提供了三個類用於實現向量資料查詢功能。FindTask,QueryTask,IdentifyTask,他們之間的區別為: FindTask只能進行屬性查詢,QueryTask,

Scrapy研究探索——自動爬取網頁IICrawlSpider

一.目的。 在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原始碼分析——refreshobtainFreshBeanFactory方法@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模式相關處理,然後根據當前處於使用