linux中驅動非同步通知應用程式的方法

來源:互聯網
上載者:User

驅動程式運行在核心空間中,應用程式運行在使用者空間中,兩者是不能直接通訊的。

但在實際應用中,在裝置已經準備好的時候,我們希望通知使用者程式裝置已經ok,

使用者程式可以讀取了,這樣應用程式就不需要一直查詢該裝置的狀態,從而節約了資源,這就是非同步通知。
好,那下一個問題就來了,這個過程如何?呢?簡單,兩方面的工作。
一 驅動方面:
1. 在裝置抽象的資料結構中增加一個struct fasync_struct的指標
2. 實現裝置操作中的fasync函數,這個函數很簡單,其主體就是調用核心的fasync_helper函數。
3. 在需要向使用者空間通知的地方(例如中斷中)調用核心的kill_fasync函數。
4. 在驅動的release方法中調用前面定義的fasync函數
呵呵,簡單吧,就三點。其中fasync_helper和kill_fasync都是核心功能,我們只需要調用就可以了。在

1中定義的指標是一個重要參數,fasync_helper和kill_fasync會使用這個參數。
二 應用程式層方面
1. 利用signal或者sigaction設定SIGIO訊號的處理函數
2. fcntl的F_SETOWN指令設定當前進程為裝置檔案owner
3. fcntl的F_SETFL指令設定FASYNC標誌
完成了以上的工作的話,當核心執行到kill_fasync函數,使用者空間SIGIO函數的處理函數就會被調用了。
呵呵,看起來不是很複雜把,讓我們結合具體代碼看看就更明白了。
先從應用程式層代碼開始吧:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define MAX_LEN 100
void input_handler(int num)
//處理函數,沒什麼好講的,使用者自己定義
{
 char data[MAX_LEN];
 int len;
 //讀取並輸出STDIN_FILENO上的輸入
 len = read(STDIN_FILENO, &data, MAX_LEN);
 data[len] = 0;
 printf("input available:%s/n", data);
} main()
{
 int oflags;  //啟動訊號驅動機制
 signal(SIGIO, input_handler);
  /*
  將SIGIO訊號同input_handler函數關聯起來,
  一旦產生SIGIO訊號,就會執行input_handler,
   */
 fcntl(STDIN_FILENO, F_SETOWN, getpid());
  /*
    STDIN_FILENO是開啟的裝置檔案描述符,
    F_SETOWN用來決定操作是幹什麼的,
    getpid()是個系統調用,功能是返回當前進程的進程號
    整個函數的功能是STDIN_FILENO設定這個裝置檔案的擁有者為當前進程。
  */
 oflags = fcntl(STDIN_FILENO, F_GETFL);
  /*得到開啟檔案描述符的狀態*/
 fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
  /*
   設定檔案描述符的狀態為oflags | FASYNC屬性,
   一旦檔案描述符被設定成具有FASYNC屬性的狀態,
   也就是將裝置檔案切換到非同步作業模式。
   這時系統就會自動調用驅動程式的fasync方法。
  */  //最後進入一個死迴圈,程式什麼都不幹了,只有訊號能激發input_handler的運行
 //如果程式中沒有這個死迴圈,會立即執行完畢
 while (1);
}
再看驅動層代碼,驅動層其他部分代碼不變,就是增加了一個fasync方法的實現以及一些改動
static struct fasync_struct *fasync_queue;
/*首先是定義一個結構體,其實這個結構體存放的是一個列表,這個列表儲存的是
  一系列裝置檔案,SIGIO訊號就發送到這些裝置上*/
static int my_fasync(int fd, struct file * filp, int on)
/*fasync方法的實現*/
{
    int retval;
    retval=fasync_helper(fd,filp,on,&fasync_queue);
    /*將該裝置登記到fasync_queue隊列中去*/
    if(retval<0)
      return retval;
    return 0;
}
在驅動的release方法中我們再調用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
 /*..processing..*/
        drm_fasync(-1, filp, 0);
        /*..processing..*/
} 這樣後我們在需要的地方(比如中斷)調用下面的代碼,就會向fasync_queue隊列裡的裝置發送SIGIO訊號,應用程式收到訊號,執行處理常式
    if (fasync_queue)
      kill_fasync(&fasync_queue, SIGIO, POLL_IN);
好了,這下大家知道該怎麼用非同步通知機制了吧? 以下是幾點說明[1]:
1 兩個函數的原型
int fasync_helper(struct inode *inode, struct file *filp, int mode, struct fasync_struct **fa);
一個"幫忙者", 來實現 fasync 裝置方法. mode 參數是傳遞給方法的相同的值, 而 fa 指標指向一個裝置特定的 fasync_struct * void kill_fasync(struct fasync_struct *fa, int sig, int band);
如果這個驅動支援非同步通知, 這個函數可用來發送一個訊號到登記在 fa 中的進程. 2.
fasync_helper 用來向等待非同步訊號的裝置鏈表中添加或者刪除裝置檔案,   kill_fasync 被用來通知擁有相關裝置的進程. 它的參數是被傳遞的訊號(常常是 SIGIO)和 band, 這幾乎都是 POLL_IN[25](但是這可用來發送"緊急"或者帶外資料, 在網路代碼裡). 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.