2015年4月22日 星期三

在Raspberry Pi & Pi2 上面學 Linux 驅動程式開發 -- work queue --

實驗名稱:

    Linux 驅動程式開發 work queue 

實驗目的:

    介紹 work queue 在 Linux Kernel 裡面的作用與使用方式。

使用材料及設備:

    硬體: Raspberry Pi B+

    軟體: 可編譯 Linux Module 的 Raspbian 系統。

原理介紹:

    work queue 和 tasklet 的主要功用是類似的,就是向系統核心註冊一個工作,系統核心會把該工作排進去它的行程表之中,並等到適當的時機去處理這個被註冊的工作。但 tasklet 通常是和中斷服務程式配合使用,而 work queue 則是設計給一般的工作排程所使用。

work queue 和 tasklet 在使用上會感受到的差異在於 work_queue 的工作排程可以進入睡眠或是重新調度等等,但是為了簡化範例,此範例將只介紹最簡單的用法。work queue 在排入工作排程之後,核心會安排另一個 thread 來執行 work queue,這在多核 CPU 系統可以得到較明顯的好處。tasklet 不能指定執行的時間,但是 work queue 可以。


 程式碼說明

程式碼內容

------------------CODE---------------------

------------------CODE---------------------

程式碼架構

此模組的架構包含了模組的進入點函式和離開點函式。進入點函式為my_init() 由系統模組工具函式 module_init() 註冊進去系統核心之中。離開點函式則由系統模組工具函式module_exit() 註冊進去系統核心之中。

使用到 work queue 時必須宣告資料型態為 struct work_struct 的全域變數,這邊我們使用的變數名稱為 workq 。

而此 workq 在宣告之後使用之前必須先變過初始化動作,此初始化的動作我們在函式 my_init() 之中進行,初始化可利用系統核心工具巨集 INIT_WORK() 所完成。

在 workq 用 INIT_WORK() 初始化之時,須指定一個函式指標 ( 當系統排程至 workq 執行時會去呼叫該函式),此範例將函式 my_workqueue_handler() 指定給 workq。

在完成 workq 完成初始化的動作之後,就可以將其註冊進去核心的工作排程當中。此註冊的動作由系統核心工具函式 schedule_work() 所完成。

程式碼說明

此範例示範了 Linux 核心中 work queue 的簡易使用。一開始載入模組之後,直接就初始化 workq ,並指定自定函式 my_workqueue_handler() 。而初始化完之後,就註冊進去系統核心之中。註冊完之後,核心會在眾多工作排程之中輪到執行 workq 之時去呼叫 my_workqueue_handler() ,所以觀察下面的執行結果可以看到,my_workqueue_handler() 是在模組完成函式 my_init() 的執行之後才去執行的。 

INIT_WORK( &workq , my_workqueue_handler ) ,此行程式碼為系統工具巨集,第一個參數必須傳入一個資料型態為 struct work_queue 的變數的指標。此變數代表一個工作排程。而第二個參數 my_workqueue_handler 則為一個函式指標。其資料型態必須為: 

void (*)(struct work_queue *)

在這行程式碼中,會被指定給 workq 。如果系統核心會透過 workq 來呼叫該函式指標。將 workq 排進核心的工作排程是由系統核心工具函式 schedule_work(&workq) 來完成,其傳入的資料必須為 struct work_queue * 。 

為了幫助理解,可以想像一種情境: 假設有一個工程師放假想要整天在家看電影,該位工程師準備了一張張的標籤,每張標籤上面都寫了一部電影名字。然後對這些標籤進行排列組合成一張清單,來安排電影播放順序。此時,宣告為 struct work_queue 的 workq 就是一張標籤,而 my_workqueue_handler 就是這張標籤上的電影名稱。在播放任何時候,都可以插入該張標籤進去播放清單之中的任何地方,並依序一部部電影播放下去,總會有輪到該張標籤然後去播放其指定的電影。

執行結果:






沒有留言 :

張貼留言