總結:
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喚醒