fasync這個(gè)東西就是為了使驅(qū)動(dòng)的讀寫和application的讀寫分開,使得application可以在驅(qū)動(dòng)讀寫時(shí)去做別的事,通過kill_fasync
(kill_fasync(&async, SIGIO, POLL_IN);)發(fā)SIGIO信號(hào)給應(yīng)用,應(yīng)用通過fcntl把自己這個(gè)SIGIO的信號(hào)換成自己的響應(yīng)函數(shù),當(dāng)驅(qū)動(dòng)發(fā)
(kill_fasync(&async, SIGIO, POLL_IN);)給應(yīng)用時(shí)應(yīng)用就調(diào)用了自己的handler去處理。fasync_helper作用就是初始化fasync這個(gè)東西,包括分配內(nèi)存和設(shè)置屬性。最后記得在驅(qū)動(dòng)的release里把fasync_helper初始化的東西free掉。
POLL_IN POLL_OUT
=================================================================================
驅(qū)動(dòng)程序向用戶程序發(fā)信號(hào)
---------------------------------------------
當(dāng)設(shè)備有IO事件發(fā)生,就有機(jī)制保證向應(yīng)用進(jìn)程發(fā)送信號(hào),顯然設(shè)備驅(qū)動(dòng)程序扮演重要角色,實(shí)際終端tty、網(wǎng)絡(luò)socket等的標(biāo)準(zhǔn)實(shí)現(xiàn)已經(jīng)包括了實(shí)時(shí)信號(hào)驅(qū)動(dòng)的支持,所以,在Linux中它們可以如上直接使用。但有些設(shè)備的驅(qū)動(dòng)程序還并沒有支持,所以需要定制設(shè)備驅(qū)動(dòng)程序。以下兩個(gè)API應(yīng)該是可以屏蔽所有相關(guān)瑣碎操作(類似send_sig())的標(biāo)準(zhǔn)接口:
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);
如果需要支持異步通知機(jī)制,如下設(shè)備結(jié)構(gòu)中需要有異步事件通知隊(duì)列(它應(yīng)該與睡眠隊(duì)列類似),并且增加fasync()接口的實(shí)現(xiàn)(該函數(shù)將本進(jìn)程登記到async_queue上去)。 當(dāng)一個(gè)打開的文件FASYNC標(biāo)志變化時(shí)(調(diào)用fcntl()函數(shù),設(shè)置FASYNC文件標(biāo)志時(shí)),fasync()接口將被調(diào)用。
struct kpp_dev {
struct cdev cdev;
struct fasync_struct *async_queue;
};
static int kpp_fasync(int fd, struct file *filp, int mode)
{
struct kpp_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
事件發(fā)生的時(shí)機(jī),就是中斷服務(wù)程序或相應(yīng)的軟中斷中調(diào)用kill_fasync():
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
如果是寫操作,就是POLL_OUT。注意,無論用戶進(jìn)程設(shè)定了什么期望的信號(hào),在這個(gè)環(huán)節(jié),發(fā)送的一般就是SIGIO。注意在設(shè)備文件關(guān)閉(release方法)時(shí),注意執(zhí)行fasync(),使得本文件的操作從上述的設(shè)備異步事件等待鏈表中剝離。
static int kpp_release(struct inode *inode, struct file *filp)
{
kpp_fasync(-1, filp, 0);
return 0;
}