標籤:
linux驅動程式中的非同步編程
A
前面介紹的等待隊列和輪詢編程提供了較好的解決裝置訪問的機制,但是這些機制都
是由應用程式發起的,都需要應用程式主動訪問裝置。更完美的方式是由驅動程式主
動通知應用程式,也就是說,當驅動程式滿足某些條件後,會主動通知應用程式處理
,這些處理方式有些像物件導向編程的事件,而在linux核心使用的事件是接下來要介
紹的訊號。
#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;
len=read(STDIN_FILENO,&data,MAX_LEN);
data[len]=0;
printf("input available:%s\n",data);
}
main()
{
int oflags;
signal(SIGIO,input_handler); //捕獲SIGIO訊號
//通過F_SETOWN將標準輸入裝置檔案(驅動)STDIN_FILENO--的擁有者設定為
//當前進程,這樣從裝置驅動STDIN_FILENO發出的訊號才能被當前進程所接到。
fcntl(STDIN_FILENO,F_SETOWN,getpid());
oflags=fcntl(STDIN_FILENO,F_GETFL);
// 通過F_SETFL使裝置檔案支援FASYNC,也就是非同步通知模式。
fcntl(STDIN_FILENO,F_SETFL,oflags|FASYNC);
while(1);
}
B
裝置驅動中非同步通知編程比較簡單,主要用到一項資料結構和兩個函數。
資料結構是 fasync_struct 結構體,
兩個函數分別如下。
處理 FASYNC 標誌變更的函數。
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
釋放訊號用的函數。
void kill_fasync(struct fasync_struct **fa, int sig, int band);
和其他的裝置驅動一樣,將 fasync_struct 結構體指標放在裝置結構體中仍然是最
佳選擇,代碼清單給出了支援非同步通知的裝置結構體模板。
struct xxx_dev
{
struct cdev cdev; /*cdev 結構體*/
...
struct fasync_struct *async_queue; /* 非同步結構體指標 */
};
在裝置驅動的 fasync() 函數中,只需要簡單地將該函數的 3 個參數以及
fasync_struct 結構體指標的指標作為第 4 個參數傳入 fasync_helper()函數即
可。代碼清單給出了支援非同步通知的裝置驅動程式 fasync()函數的模板。
//處理應用程式的F_SETFL命令的fasync函數
static int xxx_fasync(int fd, struct file *filp, int mode)
{
struct xxx_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
static struct file_operations dev_fops=
{
.owner=...
.read=....
.write=...
.fasync=xxx_fasync;
}
在裝置資源可以獲得時,應該調用 kill_fasync()釋放 SIGIO 訊號,可讀時第 3
個參數設定為 POLL_IN,可寫時第 3 個參數設定為 POLL_OUT。下面代碼為釋放訊號
的範例。
static ssize_t xxx_write(struct file *filp, const char _ _user *buf, size_t count,loff_t *f_pos}
{
struct xxx_dev *dev = filp->private_data;
...
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 產生非同步讀訊號 */
...
}
最後,在檔案關閉時,即在裝置驅動的 release()函數中,應調用裝置驅動的
fasync()函數將檔案從非同步通知的列表中刪除。下面代碼清單給出了支援非同步通知的
裝置驅動release()函數的模板。
static int xxx_release(struct inode *inode, struct file *filp)
{
struct xxx_dev *dev = filp->private_data;
/* 將檔案從非同步通知清單中刪除 */
xxx_fasync(-1, filp, 0);
...
return 0;
}
應用程式:
開啟兩個終端,一個運行應用程式,另外一個執行 echo "hello" >/dev/裝置名稱 ,
執行完這條指令後,驅動調用write函數,驅動程式中的write函數中會調用
kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 產生非同步讀訊號 */ ,
這樣應用程式馬上捕捉到SIGIO,此時應用程式進入處理接受訊號函數。
linux驅動程式中的非同步編程