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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...