linux驅動編寫之poll機制

2021-09-07 11:39:03 字數 3755 閱讀 5755

一、概念

1、poll情景描述

以按鍵驅動為例進行說明,用阻塞的方式開啟按鍵驅動檔案/dev/buttons,應用程式使用read()函式來讀取按鍵的鍵值。這樣做的效果是:如果有按鍵按下了,呼叫該read()函式的程序,就成功讀取到資料,應用程式得到繼續執行;倘若沒有按鍵按下,則要一直處於休眠狀態,等待這有按鍵按下這樣的事件發生。

這種功能在一些場合是適用的,但是並不能滿足我們所有的需要,有時我們需要乙個時間節點。倘若沒有按鍵按下,那麼超過多少時間之後,也要返回超時錯誤資訊,程序能夠繼續得到執行,而不是沒有按鍵按下,就永遠休眠。這種例子其實還有很多,比方說兩人相親,男方等待女方給個確定相處的信,男方不可能因為女方不給信,就永遠等待下去,雙方需要乙個時間節點。這個時間節點,就是說超過這個時間之後,不能再等了,程式還要繼續執行,需要採取其他的行動來解決問題。

example:  

微控制器程式設計,等待iic裝置乙個事件的發生,如果在允許的時間內發生了就返回1(success),否則返回0(error)。

uint8_t i2c_waitforevent(i2c_typedef*i2cx, uint32_t i2c_event,int32_t delay)

return1;

}

此段函式**可以這樣來呼叫,如下:

int8_t i2c_ee_pagewrite(u8*pbuffer, u16 writeaddr, u8 numbytetowrite)

............

}

這個例子是stm32微控制器寫i2cflash--at24c02,可見上述的頁寫函式呼叫的等待位元組傳輸完成函式(i2c_event_master_byte_transmitted)

,如果在限定的時間內(cpu將100000減到0),還沒有成功寫入,那麼就將返回超時錯誤,頁寫函式也會返回寫入失敗的錯誤資訊。之後,任務重新得到了執行。

對於微控制器這樣通常單任務執行的狀況,必須採取這樣的措施。如果沒有超時限制,那麼程式將陷入宕機,不能再繼續執行。

2、linux應用程式poll的使用

對於類似的場景,linux系統使用poll功能來解決這樣的問題。而且,與上述微控制器等待方式不同,linux系統再呼叫poll()函式時候,如果沒有發生需要的事件,那麼程序進入休眠。如果在限定的時間內得到需要的事件,那麼成功返回,如果沒有則返回超時錯誤資訊。

可見,等待期間將程序休眠,利用事件驅動來喚醒程序,將更能提高cpu的效率。下面,以乙個應用例程來說明poll的應用程式使用方法:

#include #include 

#include

#include

#include

int main(int argc, char **ar**)

fds[

0].fd =fd;

fds[

0].events =pollin;

while (1

)

else

}close(fd);

return

0;

}

例程實現的功能是這樣的:用poll()函式監測按鍵按下的事件,如果按下了就將鍵值列印出來;如果超過5s,還沒有按鍵按下,就列印出超時資訊。

3、poll()函式

函式原型

int poll(struct pollfd *fds, nfds_t nfds, int timeout)

輸入引數

fds         可以傳遞多個結構體,也就是說可以監測多個驅動裝置所產生的事件,只要有乙個產生了請求事件,就能立即返回

struct pollfd ;

nfds       監測驅動檔案的個數

timeout  超時時間,單位為ms 

事件型別events 可以為下列值:

pollin           有資料可讀

pollrdnorm 有普通資料可讀,等效與pollin

pollpri         有緊迫資料可讀

pollout        寫資料不會導致阻塞

poller          指定的檔案描述符發生錯誤

pollhup        指定的檔案描述符掛起事件

pollnval      無效的請求,打不開指定的檔案描述符

返回值

有事件發生        返回revents域不為0的檔案描述符個數(也就是說事件發生,或者錯誤報告)

超時                返回0;

失敗            返回-1,並設定errno為錯誤型別

二、驅動實現方法

/* 定義乙個等待佇列,這個等待佇列實際上是由中斷驅動的,當中斷發生時,會令掛接到這個等待佇列的休眠程序喚醒 */

static declare_wait_queue_head(button_waitq);

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

上述**展示了乙個poll()函式功能,具體對應的底層驅動實現細節。利用這樣的框架,我們可以寫出類似驅動的poll功能。但是,這個框架很難理解,不知道為什麼這樣編寫?為此,我們需要了解linux系統poll功能實現的機制。

三、linux核心poll實現機制

從應用程式呼叫poll()函式開始,一直到呼叫drivers_poll函式,期間的過程很複雜,撿主要的內容列出來:

|drv:sys_poll

|— do_sys_poll(

struct pollfd __user * ufds, unsigned int nfds, struct timespec *end_time)

|

- poll_initwait(&table); > 實際效果:令函式指標 table.pt.qproc = __pollwait,這個函式指標最終會傳遞給poll_wait函式呼叫中的wait->qproc

|- do_poll(nfds, head, &table, end_time);

|_ for

( ; ; )

} if (count || timed_out) /* 如果有事件發生,或者超時,則跳出poll */

break;

if (!poll_schedule_timeout(wait, task_interruptible, to, slack)) /* 如果沒有事件發生,那麼陷入休眠狀態 */

timed_out = 1;

}由此可見,我們的drivers_poll()函式,是系統在執行sys_poll()過程中的乙個呼叫,呼叫的目的是「將程序掛接到等待佇列下」和「返回事件型別mask」。當已經發生了請求事件,那麼通過標記mask非0,if (do_pollfd(pfd, pt))判斷為真,令count++,從而可以直接令poll()函式成功返回。如果還沒有發生請求的事件,那麼mask被標記為0,程序將通過函式poll_schedule_timeout()陷入休眠狀態。一旦發生了請求的事件,因為之前已經將程序掛接到等待佇列下,所以程序將被喚醒,重新執行drivers_poll(),而顯然此時能夠成功返回。

備註:分析的原始碼版本為linux-2.6.30.4。

linux驅動編寫之poll機制

1.poll情景描述 以按鍵驅動為例進行說明,用阻塞的方式開啟按鍵驅動檔案 dev buttons,應用程式使用read 函式來讀取按鍵的鍵值。這樣做的效果是 如果有按鍵按下 了,呼叫該read 函式的程序,就成功讀取到資料,應用程式得到繼續執行 倘 若沒有按鍵按下,則要一直處於休眠狀態,等待這有按...

poll函式 Linux驅動基石之POLL機制

在前面引入中斷時,我們曾經舉過乙個例子 媽媽怎麼知道臥室裡小孩醒了?時不時進房間看一下 查詢方式 簡單,但是累 進去房間陪小孩一起睡覺,小孩醒了會吵醒她 休眠 喚醒 不累,但是媽媽幹不了活了 媽媽要幹很多活,但是可以陪小孩睡一會,定個鬧鐘 poll方式 要浪費點時間,但是可以繼續幹活。媽媽要麼是被小...

linux驅動之poll操作

poll是乙個系統呼叫,其核心入口函式為sys poll,sys poll差點兒不做不論什麼處理直接呼叫do sys poll,do sys poll的執行過程能夠分為三個部分 1,將使用者傳入的pollfd陣列複製到核心空間,由於拷貝操作和陣列長度相關。時間上這是乙個o n 操作,這一步的 在do...