<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 牛人業(yè)話 > Linux內(nèi)核開(kāi)發(fā)之異步通知與異步I/O(一)

          Linux內(nèi)核開(kāi)發(fā)之異步通知與異步I/O(一)

          作者: 時(shí)間:2016-12-05 來(lái)源:網(wǎng)絡(luò) 收藏

            “小王,聽(tīng)說(shuō)過(guò)錦上添花吧..”我拍拍下王的頭說(shuō)。

          本文引用地址:http://www.ex-cimer.com/article/201612/341125.htm

            “還錦上添花你,為你上次提的幾個(gè)東東,我是頭上長(zhǎng)包..”小王氣憤地瞪著我。

            “啊,為啥這樣呢,本來(lái)還特意拒絕了MM的約會(huì),抽出時(shí)間打算給你說(shuō)點(diǎn)高級(jí)的東東,看來(lái)現(xiàn)在是不行了”我吃驚道,“這樣吧,這次就給你講些和前邊有關(guān)的東西,也不失為錦上添花不是?”。

            “好,我也是這么打算的,就是沒(méi)好意思說(shuō),今天講些啥呢?”小王暗淡的眼光總算閃了閃。(為啥這么難受呢,好像跟什么會(huì)嚎叫的特像,哈哈)

            那就言歸正傳,今天我們講---設(shè)備驅(qū)動(dòng)程序之異步通知與.”

            小王,前邊不是講了阻塞與非阻塞訪問(wèn),poll()函數(shù)等提供的較好的解決設(shè)備訪問(wèn)的機(jī)制,那么通過(guò)這次有關(guān)異步通知整套機(jī)制的配合,就更相得益彰,錦上添花了。

            啥叫異步通知:很簡(jiǎn)單,一旦設(shè)備準(zhǔn)備好,就主動(dòng)通知應(yīng)用程序,這種情況下應(yīng)用程序就不需要查詢?cè)O(shè)備狀態(tài),這是不是特像硬件上常提的“中斷的概念”。上邊比較準(zhǔn)確的說(shuō)法其實(shí)應(yīng)該叫做“信號(hào)驅(qū)動(dòng)的”,信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬。

            “小王,給你一個(gè)表現(xiàn)的機(jī)會(huì),說(shuō)說(shuō)這個(gè)和前邊的幾點(diǎn)不同和差異。。”

            “嗯,我的理解是這樣的哈,阻塞I/O意味著一直等待設(shè)備可訪問(wèn)再訪問(wèn),非阻塞I/O意味著使用poll()來(lái)查詢是否可訪問(wèn),而異步通知?jiǎng)t意味著設(shè)備通知應(yīng)用程序自身可訪問(wèn)。”看著小王聰明的眼睛和清晰的思路,我也忍不住給予一個(gè)鼓勵(lì)的微笑啊。

            說(shuō)的好,我只是想強(qiáng)調(diào)一點(diǎn):上面三種方式,其實(shí)本身是沒(méi)有優(yōu)劣的,應(yīng)該根據(jù)不同的應(yīng)用場(chǎng)景合理選擇罷了。

            說(shuō)到信號(hào),在應(yīng)用程序中,為了捕獲信號(hào)(還捕獲呢, 不就是一個(gè)處理嗎)可以使用signal()函數(shù)來(lái)設(shè)置對(duì)應(yīng)的信號(hào)的處理函數(shù)。函數(shù)原型是

            void (*signal(int signo,void (*func)(int))) (int) 這個(gè)看起來(lái)費(fèi)勁吧,不光你,我看著也費(fèi)勁,沒(méi)關(guān)系,給你來(lái)個(gè)例子:

            void sigterm_handler(int signo)

            {

            char data[MAX_LEN];

            int len;

            len=read(STDIN_FILENO, &data,MAX_LEN);

            data[len]=0;

            printf("Input available:%sn",data);

            exit(0);

            }

            int main(void)

            {

            int oflags;

            //啟動(dòng)信號(hào)驅(qū)動(dòng)機(jī)制

            signal(SIGIO, sigterm_handler);

            fcntl(STDIN_FILENO, F_SETOWN, getpid());

            oflags = fcntl(STDIN_FILENO, F_GETFL);

            fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);

            //建立一個(gè)死循環(huán),防止程序結(jié)束

            while(1);

            return 0;

            }

            看了這段代碼明白啥意思了吧,我也不多少了,咱們繼續(xù)往下走..為了一個(gè)用戶在用戶空間中能處理一個(gè)設(shè)備釋放的信號(hào),它必須完成一下3份工作:

            1)通過(guò)F_SETOWN控制指令設(shè)置設(shè)備文件的擁有者為本進(jìn)程,這樣從設(shè)備驅(qū)動(dòng)中發(fā)出的信號(hào)才能被本進(jìn)程收到。

            2)通過(guò)F_SETFLIO控制命令設(shè)置設(shè)備文件支持FASYNC,即異步通知模式。

            3)通過(guò)signal()鏈接信號(hào)和信號(hào)處理函數(shù)。

            當(dāng)然,如果你了解linux/Unix信號(hào)機(jī)制的話,你可能會(huì)問(wèn)為啥沒(méi)說(shuō)sigaction函數(shù),其實(shí)沒(méi)關(guān)系,作用差不多,想知道的話,自己看書(shū)Apue的P261.

            有了信號(hào)的發(fā)送,那么就一定得有信號(hào)的釋放了:

            在設(shè)備驅(qū)動(dòng)和應(yīng)用程序的異步通知交互中,僅僅在應(yīng)用程序端捕獲信號(hào)是不夠的,因?yàn)樾盘?hào)沒(méi)有的源頭是在驅(qū)動(dòng)端,因此要在適當(dāng)?shù)臅r(shí)機(jī)讓設(shè)備驅(qū)動(dòng)釋放信號(hào)。

            為了使設(shè)備支持異步通知機(jī)制,驅(qū)動(dòng)程序中涉及三個(gè)操作:

            1)支持F_SETOWN命令,能在這個(gè)控制命令處理中設(shè)置filp->f_owner為對(duì)應(yīng)的進(jìn)程ID。不過(guò)此項(xiàng)工作已由內(nèi)核完成,設(shè)備驅(qū)動(dòng)無(wú)須處理。

            2)支持F_SETFL命令的處理,每當(dāng)FASYNC標(biāo)志改變時(shí),驅(qū)動(dòng)程序中fasync()函數(shù)將得以進(jìn)行。因此,驅(qū)動(dòng)程序必須實(shí)現(xiàn)fasync()函數(shù)。

            3)在設(shè)備資源可獲得時(shí),調(diào)用kill_fasync()函數(shù)激發(fā)相應(yīng)的信號(hào)。

            驅(qū)動(dòng)程序中上面的三步是和應(yīng)用程序是一一對(duì)應(yīng)的。如下圖:

            設(shè)備驅(qū)動(dòng)中異步通知編程還是比較簡(jiǎn)單的,主要就是一些數(shù)據(jù)結(jié)構(gòu),和兩個(gè)函數(shù):

            數(shù)據(jù)結(jié)構(gòu):fasync_struct結(jié)構(gòu)體

            函數(shù):1)處理FASYNC標(biāo)志變更的函數(shù)int fasync_helper(int fd, struct file *filp, int mode ,struct fasync_struct **fa);

            2) 釋放信號(hào)用的函數(shù)void kill_fasync(struct fasync_struct **fa, int sig, int band);

            和其他設(shè)備驅(qū)動(dòng)一樣,一般將fasync_struct放到設(shè)備結(jié)構(gòu)體中。下邊是典型模版:

            struct xxx_dev

            {

            struct cdev cdev;

            ...

            struct fasync_struct *async_queue; //異步結(jié)構(gòu)體

            }

            而在驅(qū)動(dòng)的fasync()函數(shù)中,只需要簡(jiǎn)單的將該參數(shù)的3個(gè)參數(shù)以及fasync_struct結(jié)構(gòu)體指針的指針作為第四個(gè)參數(shù)傳給fasync_helper函數(shù)即可.下邊是典型模版:

            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);

            }

            一旦設(shè)備資源可以獲得時(shí),應(yīng)該調(diào)用kill_fasync()釋放SIGIO信號(hào),可讀時(shí)第三個(gè)參數(shù)設(shè)置為POLL_IN,可寫(xiě)時(shí)第三個(gè)參數(shù)設(shè)置為POLL_OUT,下邊是釋放信號(hào)的典型模版:

            static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_ops)

            {

            struct xxx_dev *dev = filp->private_data;

            ....

            //產(chǎn)生異步信號(hào)

            if(dev->async_queue)

            {

            kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

            }

            ..

            }

            最后,在文件關(guān)閉時(shí),即在設(shè)備驅(qū)動(dòng)的release函數(shù)中,應(yīng)調(diào)用設(shè)備驅(qū)動(dòng)的fasync()函數(shù)將文件從異步通知的列表中刪除,下邊是設(shè)備驅(qū)動(dòng)的釋放函數(shù)的典型模版:

            static int xxx_release(struct inode *inode, struct file *filp)

            {

            struct xxx_dev *dev = filp->private_data;

            //將文件從異步通知列表中刪除

            xxx_fasync(-1,filp,0);

            ...

            return 0;

            }

            “等等,我知道你明白,你是想向我個(gè)例子,我知道你啥意思,沒(méi)關(guān)系,我下次補(bǔ)上 。”沒(méi)等小王,我立刻給她堵上“你啊,心里幾根小九九,我還不知道啊..”



          關(guān)鍵詞: Linux 異步I/O

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();