前面兩章分別提到io模型中的阻塞與非阻塞linux驅動(六)裝置驅動中的阻塞與非阻塞io,io多路復用驅動中輪詢操作實現,這一章我們再來看看非同步io,這樣,io模型就可以都搞定了。
回顧一下在應用程式中使用非同步io的步驟
1,應用程式
1)設定非同步標誌位
int flags = fcntl(fd, f_getfl);
flags |= o_async,
fcntl(fd, f_setfl, flags);
2)設定檔案的屬主
fcntl(fd, f_setown, getpid());
3)註冊非同步訊號sigio
signal(sigio, handler);
上述三部分在核心中都會有對應的實現,其中第二步由核心幫我們實現,其餘的則需要在核心驅動中實現。
第一步:修改非同步標誌位,將呼叫驅動的fasync()函式,自然而然的可以想到,該函式也是在struct file_operations集合當中的。
這裡提一下,只要修改了非同步標誌位,就會呼叫底層的fasync函式,當程序設定非同步標誌位時,核心驅動中呼叫 fasync , 將程序新增到非同步佇列中去。當程序退出時,非同步標誌位被清除,也呼叫fasync,將程序 從非同步佇列中移除。
第二步:應用層註冊的非同步訊號函式什麼時候執行的呢?底層驅動需要用到kill_fasync()函式。
繼續處理上述兩部需要的資料結構和函式
1、非同步訊號結構體
struct fasync_struct ;
使用很簡單,前三個引數直接繼承自fasync(),第四個引數是乙個非同步訊號結構體的二級指標。
3、訊號釋放函式
void kill_fasync(struct fasync_struct **fp, int sig, int band)
功能:向非同步佇列中的指定程序傳送sigio 訊號
引數:fp 非同步佇列的頭節點
sig 訊號
band 事件 pollin , pollout, pollrdnorm, pollwrnorm, pollerr
返回值:無
來個例程看看
應用層:#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include module_license("gpl");
dev_t devno;
int major = 0;
int minor = 0;
int count = 1;
#define kmax 1024
char kbuf[kmax] = {};
int counter = 0; //用它記錄kbuf中實際儲存的位元組數量
struct virtural_dev;
struct virtural_dev *virtural_devp = null;
struct class * pclass;
struct device * pdevice;
int demo_open(struct inode * inodep, struct file * filep)
int demo_release(struct inode *inodep, struct file *filep)
// read(fd, buff, n) --> ... --> demo_read()
ssize_t demo_read(struct file * filep, char __user * buffer, size_t size, loff_t * offlen)
if(wait_event_interruptible(virtural_devp->wq,counter != 0))
}down_interruptible(&virtural_devp->sem_r);
if(size > counter)
if(copy_to_user(buffer, kbuf, size) != 0)
counter = 0;
up(&virtural_devp->sem_w);
return size;
}// write(fd, buff, n) --> ... --> demo_write();
ssize_t demo_write(struct file *filep, const char __user *buffer, size_t size, loff_t * offlen)
if(copy_from_user(kbuf, buffer,size) != 0)
printk(kern_info"kbuf:%s\n", kbuf);
counter = size;
up(&virtural_devp->sem_r);
// 喚醒等待佇列
wake_up(&virtural_devp->wq);
//傳送訊號+++++++++++++++++++++++++++++++++
kill_fasync(&virtural_devp->fasync, sigio, pollin|pollrdnorm);
return size;
}// select() --> sys_select() --> ... --> demo_poll();
unsigned int demo_poll(struct file * filep, struct poll_table_struct * table)
return mask;
}//新增fasync函式+++++++++++++++++++++++++++++
int demo_fasync(int fd, struct file * filep, int on)
struct file_operations fops = ;
static int __init demo_init(void)
printk(kern_info"devno:%d , major:%d minor:%d\n", devno, major(devno), minor(devno));
virtural_devp->pdev = cdev_alloc();
if(virtural_devp->pdev == null)
cdev_init(virtural_devp->pdev, &fops);
ret = cdev_add(virtural_devp->pdev, devno, count);
if(ret < 0)
pclass = class_create(this_module, "myclass");
if(is_err(pclass))
pdevice = device_create(pclass, null, devno, null, "hello");
if(is_err(pdevice))
sema_init(&virtural_devp->sem_r, 0);
sema_init(&virtural_devp->sem_w, 1);
// 等待佇列初始化
init_waitqueue_head(&virtural_devp->wq);
return 0;
err4:
class_destroy(pclass);
err3:
cdev_del(virtural_devp->pdev);
err2:
kfree(virtural_devp->pdev);
err1:
unregister_chrdev_region(devno, count);
return ret;
}static void __exit demo_exit(void)
module_init(demo_init);
module_exit(demo_exit);
#include #include #include #include #include #include #include #define n 128
int fd;
void handler(int sig)
; read(fd, buf, n);
printf("buf:%s\n", buf);
}int main(int argc, const char *argv)
else
getchar();
// 1)設定非同步標誌位
flags = fcntl(fd, f_getfl);
flags |= o_async;
fcntl(fd, f_setfl, flags);
getchar();
// 2)設定檔案的屬主
fcntl(fd, f_setown, getpid());
getchar();
// 3)註冊非同步訊號sigio
signal(sigio, handler);
while(1)
close(fd);
return 0;
}
linux裝置驅動中的非同步通知機制
非同步通知的意思是 一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上 中斷 的概念,比較準確的稱謂是 訊號驅動的非同步i o 訊號是在軟體層次上對中斷機制的一種模擬,在原理上,乙個程序收到乙個訊號與處理器收到乙個中斷請求可以說是一樣的.訊號是非同步的,乙...
linux中驅動非同步通知
驅動程式執行在核心空間中,應用程式執行在使用者空間中,兩者是不能直接通訊的。但在實際應用中,在裝置已經準備好的時候,我們希望通知使用者程式裝置已經ok,使用者程式可以讀取了,這樣應用程式就不需要一直查詢該裝置的狀態,從而節約了資源,這就是非同步通知。好,那下乙個問題就來了,這個過程如何實現呢?簡單,...
Linux驅動中的非同步通知
在很多應用中都需要應用程式主動去查詢驅動中是否有資料可讀或者是否可以向驅動寫入資料,對於單執行緒的應用,這可能會導致程序阻塞。當然,可以使用select來不斷輪詢驅動是否可讀或可寫,但是這並不是很好的解決方法,更好的解決方式是由驅動主動通知應用程式其狀態,而不是應用程式主動去查詢驅動的狀態。非同步通...