天天看點

poll機制總結

總結:

1. poll > sys_poll > do_sys_poll >poll_initwait,poll_initwait函數注冊一下回調函數__pollwait,它就是我們的驅動程式執行poll_wait時,真正被調用的函數。 

2. 接下來執行file->f_op->poll,即我們驅動程式裡自己實作的poll函數

   它會調用poll_wait把自己挂入某個隊列,這個隊列也是我們的驅動自己定義的;

   它還判斷一下裝置是否就緒。 

3. 如果裝置未就緒,do_sys_poll裡會讓程序休眠一定時間,這個時間是應用提供的“逾時時間” 

4. 程序被喚醒的條件有2:一是上面說的“一定時間”到了,二是被驅動程式喚醒。驅動程式發現條件就緒時,就把“某個隊列”上挂着的程序喚醒,這個隊列,就是前面通過poll_wait把本程序挂過去的隊列。 

5. 如果驅動程式沒有去喚醒程序,那麼chedule_timeout(__timeou)逾時後,會重複2、3動作1次,直到應用程式給定的時間, 然後傳回。

驅動的poll函數編寫模闆如下:

static DECLARE_WAIT_QUEUE_HEAD(my_waitq);  //休眠要挂的等待隊列

static unsigned drv_poll(struct file *file, poll_table *wait)

{

unsigned int mask = 0;

poll_wait(file, &my_waitq, wait); // 不會立即休眠

if (有資料)

mask |= POLLIN | POLLRDNORM;

return mask;

}

執行個體:

在驅動函數中

前面要加一個等待隊列,

static unsigned forth_drv_poll(struct file *file, poll_table *wait)

{

    unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait); // 不會立即休眠

    if (a)                  //這個是自己定的有資料的标志,在中斷函數中定義了一個标志位,如果這個标志位為1的時候,表示已經收到資料了

        mask |= 1 ;//這個mask的值可以随便定,但是要和應用程式中 fds[0].events的值一樣,這樣才會符合

    return mask;

}

在應用程式中

    fds[0].fd     = fd;

    fds[0].events = 1

    ret = poll(fds, 1, 1000);//ret = 1 ;

if(ret == 0)

{

三個條件都沒有滿足

}

else{

有資料時做什麼

}

總的來說就是,先加入到等待隊列,然後利用mask喚醒