日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Linux內(nèi)核開發(fā)之阻塞非阻塞IO----輪詢操作

 rookie 2012-04-10

“小王,來聊聊,今天面試的情況怎么樣,應(yīng)該挺順利的吧..”看著小王平淡的眉頭,我問道。

“唉,別提了,你說,我的運(yùn)氣咋這差呢,面試前你不是給我講了有關(guān)阻塞的問題嗎,我見了面試官是吧,還跟他好好的用今天排隊(duì)的例子說了有關(guān)阻塞的問題,但是..”小王哀聲嘆氣地說到。

“別但是了,怎么啦..”

“可問題是面試官壓根就沒打算問我有關(guān)阻塞的問題及解決方案,但是問我說:這樣吧,你給我說說在Linux設(shè)備驅(qū)動(dòng)中有關(guān)非阻塞的方法,我這一聽,傻眼了不是,你剛好給我講的是阻塞的東西,可人家偏要問我有關(guān)非阻塞的問題,我..”小王欲哭無淚啊..

“怎么這樣呢,算了,機(jī)會(huì)多的是,亡羊補(bǔ)牢,我現(xiàn)在就給你說說有關(guān)非阻塞的問題----Linux設(shè)備驅(qū)動(dòng)程序之阻塞非阻塞IO----輪詢操作”。

通過上一節(jié),我們都明白了,有關(guān)阻塞的相關(guān)知識(shí)(不知道,那我沒轍了,飯送到嘴,你還挑食,難不成我拿把起子把嘴撬開不成,自己看上一篇吧),現(xiàn)在就來聊聊對(duì)

立面非阻塞。

使用非阻塞I/O的應(yīng)用程序通常會(huì)使用select()和poll()系統(tǒng)調(diào)用查詢是否可對(duì)設(shè)備進(jìn)行無阻塞的訪問,這兩個(gè)系統(tǒng)調(diào)用最終又會(huì)引發(fā)設(shè)備驅(qū)動(dòng)中的poll()函數(shù)被執(zhí)行

,所以我們的問題就集中到了如何編寫設(shè)備驅(qū)動(dòng)中的poll()函數(shù)就可以了。二話不說,先來看看設(shè)備驅(qū)動(dòng)中的poll()函數(shù)原型:

unsigned int (*poll)(struct file *filp, struct poll_table *wait);

這個(gè)函數(shù)要進(jìn)行下面兩項(xiàng)工作。首先,對(duì)可能引起設(shè)備文件狀態(tài)變化的等待隊(duì)列調(diào)用poll_wait(),將對(duì)應(yīng)的等待隊(duì)列頭添加到poll_table.然后,返回表示是否能對(duì)設(shè)備進(jìn)行無阻塞讀寫訪問的掩碼。在上面提到了一個(gè)poll_wait()函數(shù),它的原型:

void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

它的作用就是把當(dāng)前進(jìn)程添加到wait參數(shù)指定的等待列表(poll_table)中。需要注意的是這個(gè)函數(shù)是不會(huì)引起阻塞的,呵呵,誰給它取得個(gè)名字帶wait的,給咱們添這么多麻煩。

“等等,你先停停,你是高手,我可是菜鳥呢,你先給我說說poll_table結(jié)構(gòu)吧,心里總是想它是什么..”小王打斷我道。

行行,說起這個(gè)結(jié)構(gòu),我也是費(fèi)了一番周折,它定義在“include/linux/poll.h, line 38“,具體如下:

typedef struct poll_table_struct {
    poll_queue_proc qproc;
    unsigned long key;
} poll_table;   看看,其實(shí)沒什么吧,不要想的太復(fù)雜了
經(jīng)過以上驅(qū)動(dòng)程序的poll()函數(shù)應(yīng)該返回設(shè)備資源的可獲取狀態(tài),即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏的位"或"結(jié)果.每個(gè)宏的含義都表示設(shè)備的一種狀態(tài),如:
常量 說明
POLLIN 普通或優(yōu)先級(jí)帶數(shù)據(jù)可讀
POLLRDNORM 普通數(shù)據(jù)可讀
POLLRDBAND 優(yōu)先級(jí)帶數(shù)據(jù)可讀
POLLPRI 高優(yōu)先級(jí)數(shù)據(jù)可讀
POLLOUT 普通數(shù)據(jù)可寫
POLLWRNORM 普通數(shù)據(jù)可寫
POLLWRBAND 優(yōu)先級(jí)帶數(shù)據(jù)可寫
POLLERR 發(fā)生錯(cuò)誤
POLLHUP 發(fā)生掛起
POLLNVAL 描述字不是一個(gè)打開的文件
"小王,你明白了沒.."看著小王眨巴眨巴的小眼睛,我說。
"呵呵,你干脆給我來個(gè)典型模板,行不?"小王苛求道。
行,沒問題,你現(xiàn)在特殊時(shí)期,我是有求必應(yīng)。請(qǐng)看下邊:
static unsigned int XXX_poll(struct file *filp, poll_table *wait)
{
    unsigned int mask = 0;
        struct XXX_dev *dev = filp->private_data;     //獲得設(shè)備結(jié)構(gòu)指針
    ...
    poll_wait(filp, &dev->r_wait, wait);    //加讀等待對(duì)列頭
    poll_wait(filp ,&dev->w_wait, wait);    //加寫等待隊(duì)列頭
    
    if(...)//可讀
    {
          mask |= POLLIN | POLLRDNORM;    //標(biāo)識(shí)數(shù)據(jù)可獲得if(...)//可寫
    {
          mask |= POLLOUT | POLLRDNORM;    //標(biāo)識(shí)數(shù)據(jù)可寫入
     }
    ..
    return mask;
}

"小王,這次看明白了吧,要是還看不明白,我就再給你講講用戶空間的輪詢編程,兩個(gè)結(jié)合起來也許好懂點(diǎn),行不"。我補(bǔ)充道。

在用戶程序中,select()和poll()本質(zhì)上是一樣的, 不同只是引入的方式不同,前者是在BSD UNIX中引入的,后者是在System V中引入的。用的比較廣泛的是select

系統(tǒng)調(diào)用。原型如下:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptionfds, struct timeval *timeout);

其中readfs,writefds,exceptfds分別是select()監(jiān)視的讀,寫和異常處理的文件描述符集合,numfds的值是需要檢查的號(hào)碼最高的文件描述符加1,timeout則是一個(gè)時(shí)間上限值,超過該值后,即使仍沒有描述符準(zhǔn)備好也會(huì)返回。

struct timeval
{
    int tv_sec;    //秒
    int tv_usec;   //微秒
}
涉及到文件描述符集合的操作主要有以下幾種:
1)清除一個(gè)文件描述符集   FD_ZERO(fd_set *set);
2)將一個(gè)文件描述符加入文件描述符集中    FD_SET(int fd,fd_set *set);
3)將一個(gè)文件描述符從文件描述符集中清除  FD_CLR(int fd,fd_set *set);
4)判斷文件描述符是否被置位    FD_ISSET(int fd,fd_set *set);

最后我們利用上面的文件描述符集的相關(guān)來寫個(gè)驗(yàn)證添加了設(shè)備輪詢的驅(qū)動(dòng),把上邊兩塊聯(lián)系起來:

必要的頭文件
 
#define FIFO_CLEAR 0x1
#define BUFFER_LEN 20
main()
{
  int fd, num;
  char rd_ch[BUFFER_LEN];
  fd_set rfds,wfds;
  /*以非阻塞方式打開/dev/polltest設(shè)備文件*/
  fd = open("/dev/polltest", O_RDONLY | O_NONBLOCK);
  if (fd !=  - 1)
  { /*FIFO清0*/
    if (ioctl(fd, FIFO_CLEAR, 0) < 0)
    {
      printf("ioctl command failed\n");
    }
    while (1)
    {
      FD_ZERO(&rfds);
      FD_ZERO(&wfds);
      FD_SET(fd, &rfds);
      FD_SET(fd, &wfds);
      select(fd + 1, &rfds, &wfds, NULL, NULL);
      /*數(shù)據(jù)可獲得*/
      if (FD_ISSET(fd, &rfds))
      {
      	printf("Device can be read now\n");
      }
      /*數(shù)據(jù)可寫入*/
      if (FD_ISSET(fd, &wfds))
      {
      	printf("Device can be written now\n");
      }      
    }
  }
  else
  {
    printf("Device open failure now\n");
  }
} 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多