深入淺出:Linux裝置驅動中的阻塞和非阻塞I/O

發表於2015-04-29

今天寫的是Linux裝置驅動中的阻塞和非阻塞I/0,何謂阻塞與非阻塞I/O?簡單來說就是對I/O操作的兩種不同的方式,驅動程式可以靈活的支援使用者空間對裝置的這兩種訪問方式。

一、基本概念:

  • 阻塞操作 : 是指在執行裝置操作時,若不能獲得資源,則掛起程式直到滿足操作條件後再進行操作。被掛起的程式進入休眠, 被從排程器移走,直到條件滿足。
  • 非阻塞操作 :在不能進行裝置操作時,並不掛起,它或者放棄,或者不停地查詢,直到可以進行操作。非阻塞應用程式通常使用select系統呼叫查詢是否可以對裝置進行無阻塞的訪問最終會引發裝置驅動中 poll函式執行。

二、輪詢操作

阻塞的讀取一個字元:

非阻塞的讀一個字元:

阻塞操作常常用等待佇列來實現,而非阻塞操作用輪詢的方式來實現。非阻塞I/O的操作在應用層通常會用到select()和poll()系統呼叫查詢是否可對裝置進行無阻塞訪問。select()和poll()系統呼叫最終會引發裝置驅動中的poll()函式被呼叫。這裡對佇列就不多介紹了,大家可以看看資料結構裡面的知識點。

應用層的select()原型為:

應用程式為:

下面說說裝置驅動中的poll()函式,函式原型如下:

  • 對可能引起裝置檔案狀態變化的等待佇列呼叫poll_wait()函式,將對應的等待佇列頭新增到poll_table
  • 返回表示是否能對裝置進行無阻塞讀,寫訪問的掩碼

這裡還要提到poll_wait()函式,很多人會以為是和wait_event()一樣的函式,會阻塞的等待某件事情的發生,其實這個函式並不會引起阻塞,它的工作是把當前的程式增添到wait引數指定的等待列表poll_table中去,poll_wait()函式原型如下:

驅動函式中的poll()函式典型模板如下:

三、支援輪詢操作的globalfifo驅動

在globalfifo的poll()函式中,首先將裝置結構體重的r_wait和w_wait等待佇列頭加到等待佇列表,globalfifo裝置驅動的poll()函式如下:

四、總結

阻塞與非阻塞操作:

  • 定義並初始化等待對列頭;
  • 定義並初始化等待佇列;
  • 把等待佇列新增到等待佇列頭
  • 設定程式狀態(TASK_INTERRUPTIBLE(可以被訊號打斷)和TASK_UNINTERRUPTIBLE(不能被訊號打斷))
  • 呼叫其它程式

poll機制:

  • 把等待佇列頭加到poll_table
  • 返回表示是否能對裝置進行無阻塞讀,寫訪問的掩碼

相關文章