Linux設備驅動之阻塞I/O與非同步通知

来源:http://www.cnblogs.com/archiexie/archive/2016/12/08/6126723.html
-Advertisement-
Play Games

阻塞與非阻塞訪問是 I/O 操作的兩種不同模式,前者在 I/O 操作暫時不可進行時會讓進程睡眠,後者則不然。在設備驅動中使用非同步通知可以使得對設備的訪問可進行時,由驅動主動通知應用程式進行訪問。這樣,使用無阻塞 I/O 的應用程式無需輪詢設備是否可訪問,而阻塞訪問也可以被類似“中斷”的非同步通知所取代... ...


阻塞與非阻塞訪問是 I/O 操作的兩種不同模式,前者在 I/O 操作暫時不可進行時會讓進程睡眠,後者則不然。在設備驅動中阻塞 I/O一般基於等待隊列來實現,等待隊列可用於同步驅動中事件發生的先後順序。使用非阻塞 I/O 的應用程式也可藉助輪詢函數來查詢設備是否能立即被訪問,用戶空間調用 select()和 poll()介面,設備驅動提供 poll()函數。設備驅動的 poll()本身不會阻塞,但是 poll()和 select()系統調用則會阻塞地等待文件描述符集合中的至少一個可訪問或超時。
在設備驅動中使用非同步通知可以使得對設備的訪問可進行時,由驅動主動通知應用程式進行訪問。這樣,使用無阻塞 I/O 的應用程式無需輪詢設備是否可訪問,而阻塞訪問也可以被類似“中斷”的非同步通知所取代。


等待隊列

進程阻塞會進入睡眠,進入睡眠時應確保有其他進程或者中斷將其喚醒,而用於喚醒的進程必須知道正在睡眠的進程在哪兒,於是就有了等待隊列——睡眠進程的隊列,都等待一個特定的喚醒信號。

  • 等待隊列是被等待隊列頭管理的
    include <linux/wait.h>

    /* defined and initialized statically */
    DECLARE_WAIT_QUEUE_HEAD(name);

    /* dynamicly */
    wait_queue_head_t my_queue;
    init_waitqueue_head(&my_queue);
  • 進入睡眠
    /* 
       condition為等待條件,睡眠前後都要判斷,如果condition == false則繼續睡眠;
       interruptible版被中斷時會返回非0值,驅動應據此返回-ERESTARTSYS;
       timeout版等待超時後返回0,單位jiffies。
    */
    wait_event(queue, condition)
    wait_event_interruptible(queue, condition)
    wait_event_timeout(queue, condition, timeout)
    wait_event_interruptible_timeout(queue, condition, timeout)
  • 喚醒
    /*
       對應的常見的喚醒方法會喚醒等待隊列頭所管理的等待隊列中所有進程;
       interruptible版只能喚醒interruptible版的wait_event。
    */
    void wake_up(wait_queue_head_t *queue);
    void wake_up_interruptible(wait_queue_head_t *queue);

輪詢

使用非阻塞 I/O的應用程式通常會使用 select()和 poll()系統調用查詢是否可對設備進行無阻塞的訪問。 select()和poll()系統調用最終會引發設備驅動中的 poll()函數被執行。
設備驅動中 poll()函數的原型是:

    include <linux/poll.h>

    /*
       wait: 輸入的輪詢表指針
       返回是否能對設備進行無阻塞讀、寫訪問的掩碼:
            POLLIN | POLLRDNORM -> 可讀
            POLLOUT | POLLWRNORM -> 可寫
            POLLHUP -> 讀到文件尾
            POLLERR -> 設備錯誤
            read more: poll.h
    */        
    unsigned int(*poll)(struct file * filp, struct poll_table* wait);

關鍵的用於向 poll_table 註冊等待隊列的 poll_wait()函數的原型如下:

    /* 把管理當前進程的隊列頭queue添加到wait參數指定的等待列表(poll_table)中 */
    void poll_wait(struct file *filp, wait_queue_heat_t *queue, poll_table * wait);

非同步通知(Asynchronous Notification)

非同步通知的意思是:一旦設備就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢設備狀態,這一點非常類似於硬體上“中斷”的概念,比較準確的稱謂是“信號驅動的非同步 I/O”。
阻塞 I/O 意味著一直等待設備可訪問後再訪問,非阻塞 I/O 中使用 poll()意味著查詢設備是否可訪問,而非同步通知則意味著設備通知自身可訪問,實現了非同步 I/O。
為了使設備支持非同步通知機制,驅動程式中涉及 3 項工作:

  1. 支持 F_SETOWN 命令,能在這個控制命令處理中設置 filp->f_owner 為對應進程 ID。不過此項工作已由內核完成,設備驅動無需處理。
  2. 支持 F_SETFL 命令的處理,每當 FASYNC 標誌改變時,驅動程式中的 fasync()函數將得以執行。因此,驅動中應該實現 fasync()函數。
  3. 在設備資源可獲得時,調用 kill_fasync()函數激發相應的信號。

驅動中的上述 3 項工作和應用程式中的 3 項工作是一一對應的,如圖所示為非同步通知處理過程中用戶空間和設備驅動的交互:
非同步通知處理過程中用戶空間和設備驅動的交互

設備驅動中非同步通知編程比較簡單,主要用到一項數據結構和兩個函數。數據結構是fasync_struct 結構體, 兩個函數分別是:

    /* 處理 FASYNC 標誌變更 */
    int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
    /* 釋放信號給用戶 */
    void kill_fasync(struct fasync_struct **fa, int sig, int band);

使用方法:

    static int xxx_fasync(int fd, struct file *filp, int mode)
    {
        struct xxx_dev *dev = filp->private_data;
        return fasync_helper(fd, filp, mode, &dev->async_queue);
    }

    static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
    {
        struct xxx_dev *dev = filp->private_data;
        ... 
        /* 產生非同步讀信號 */
        if (dev->async_queue)
            kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* POLL_OUT可寫 */
        ...
    }

    static int xxx_release(struct inode *inode, struct file *filp)
    {
        /* 將文件從非同步通知列表中刪除 */
        xxx_fasync(-1, filp, 0);
        ...
        return 0;
    }

References

1. Linux Device Drivers
2. Linux設備驅動開發詳解(宋寶華第二版)


Copyright (C) 2016 archiexie@cnblogs. All Rights Reserved.



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Notification是在你的應用常規界面之外展示的消息。當app讓系統發送一個消息的時候,消息首先以圖表的形式顯示在通知欄。要查看消息的詳情需要進入通知抽屜(notificationdrawer)中查看。通知欄和通知抽屜 (notificationdrawer)都是系統層面控制的,你可以隨時查看 ...
  • 一、runtime簡介 RunTime簡稱運行時。OC就是 ,也就是在運行時候的一些機制,其中最主要的是消息機制。 對於C語言, 。 對於OC的函數,屬於 ,在編譯的時候並不能決定真正調用哪個函數,只有在真正運行的時候才會根據函數的名稱找到對應的函數來調用。 事實證明: 在編譯階段,OC可以 ,即使 ...
  • 說起tableView的自動計算行高,真的是不想再提了,寫了不知道幾百遍了。可就是這麼一個小玩意兒,把我給難的不行不行的,眼看都要沒頭髮了。 1、設置tableView的預估行高和行高為自動計算 2、設置cell的contentView的底部約束和最下麵一個控制項的底部約束對齊 3、看、看、看,錯誤來 ...
  • Socket,又稱“套接字”, 在應用層和傳輸層之間的一個抽象層,用於描述 IP 地址和埠,是一個通信連的句柄, ...
  • LoopViewPagerLayout無限輪播 項目地址:https://github.com/why168/LoopViewPagerLayout " " 支持三種動畫; 支持修改輪播的速度; 支持修改滑動速率; 支持點擊事件回調監聽; 支持自定義圖片載入方式; 支持自定義ImageView圖片; ...
  • 1 圖解 android學習手冊地址android學習手冊包含9個章節,108個例子,源碼文檔隨便看,例子都是可交互,可運行,源碼採用android studio目錄結構,高亮顯示代碼,文檔都採用文檔結構圖顯示,可以快速定位。360手機助手中下載,圖標上有貝殼 2概念介紹 有一個已經有序的數據序列, ...
  • 一、添加開機自啟服務 在centos7中添加開機自啟服務非常方便,只需要兩條命令(以Jenkins為例): 二、添加開機自啟腳本 在centos7中增加腳本有兩種常用的方法,以腳本autostart.sh為例: 方法一 1、賦予腳本可執行許可權(/opt/script/autostart.sh是你的腳 ...
  • 1.準備工具 我當時下載的是VMware9.0.2,之後升級即可。 2.安裝VMware9.0.2,按照步驟安裝即可,安裝成功並運行 選擇創建新的虛擬機,出現下圖,選擇“自定義”後單擊“繼續” 依次按照圖示進行選擇: 虛擬機名稱及位置自定! 給虛擬機分配記憶體,在安裝成功後也可修改此項。 出現下圖準備 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...