【linux】驅動-14-非同步通知

李柱明發表於2021-06-22


前言

14. 非同步通知

本章內容為驅動基石之一
驅動只提供功能,不提供策略

阻塞與非阻塞是 APP 詢問 驅動裝置。
非同步通知是 驅動裝置 主動通知 APP。

原文:https://www.cnblogs.com/lizhuming/p/14918049.html

14.1 非同步通知的一些概念

非同步通知:一旦裝置就緒,則主動通知APP,這樣APP就不用輪詢查詢裝置狀態了。

非同步IO:APP 發起 IO 請求後,立即返回。然後再查詢 IO 完成情況,或者 IO 完成後被調回。這個過程叫做 非同步IO

14.2 Linux 訊號

可以使用 訊號 來進行程式間通訊(IPC)。

Linux訊號表:

  • 路徑參考:include\uapi\asm-generic\signal.h
訊號 說明
SIGHUP 1 掛起
SIGINT 2 中斷中斷
SIGQUIT 3 終端退出
SIGILL 4 無效命令
SIGTRAP 5 跟蹤陷阱
SIGABRT 6 異常終止訊號,和 SIGIOT 同義
SIGIOT 6 IOT陷阱,和 SIGABRT 同義
SIGBUS 7 BUS錯誤
SIGFPE 8 浮點異常
SIGKILL 9 強制終止
SIGUSR1 10 使用者自定義訊號1
SIGSEGV 11 無效的記憶體段處理
SIGUSR2 12 使用者自定義訊號2
SIGPIPE 13 半關閉管道的寫操作
SIGALRM 14 計時器到期
SIGTERM 15 終止
SIGSTKFLT 16 堆疊錯誤
SIGCHLD 17 子程式已經停止或退出
SIGCONT 18 如果停止了,繼續執行
SIGSTOP 19 停止執行
SIGTSTP 20 終端停止訊號
SIGTTIN 21 後臺程式需要從終端讀取輸入
SIGTTOU 22 後臺程式需要從終端寫出
SIGURG 23 緊急的套接字事件
SIGXCPU 24 超額使用CPU分配的時間
SIGXFSZ 25 檔案尺寸超額
SIGVTALRM 26 虛擬時鐘訊號
SIGPROF 27 時鐘訊號描述
SIGWINCH 28 出口尺寸變化
SIGIO 29 I/O
SIGPOLL SIGIO I/O

除了 SIGSTOPSIGKILL 兩個訊號外,程式能夠忽略或捕獲其它所有訊號。
一個訊號被捕獲的意思是當一個訊號到達時有相應程式碼處理它。
如果一個訊號沒有被這程式所捕獲,核心將採取預設行為處理。

14.3 訊號接收

14.4 使用流程

14.4.1 參考流程圖

流程圖參考韋東山:

14.4.2 分析&程式設計步驟

分析中的細節部分會在後本節後面說明
分析:

  • ②:繫結訊號與回撥函式。使用sighandler_t signal(int signum, sighandler_t handler)

  • ③:把 APP PID 告訴核心。同時,該 PID 會儲存到該驅動的核心檔案 file 結構體中。

  • ④:讀取該驅動程式檔案的 Flag。

  • ⑤:設定 Flag 裡面的 FASYNC 位為 1。當 FASYNC 位發生變化時,該驅動會呼叫驅動操作 drv_fasync 函式。

  • ⑥:驅動開發者實現的函式。主要是呼叫 fasync_helper 函式。

  • ⑦:呼叫 fasync_helper() 函式,主要是把 驅動程式核心檔案 file 結構體繫結到 button_async->fa_file 中。而 file 包含了 APPPID。所以傳送訊號時,只需要使用 button_async 作為引數即可。

  • ⑩:傳送訊號給對應的 APP。引數為 button_async

  • 注:button_async 結構體由驅動開發者建立,維護。

APP 訊號程式設計步驟

  • ①:編寫訊號回撥函式。
  • ②:繫結訊號與回撥函式。
  • ③:開啟驅動。
  • ④:獲取 PID ,告知核心。
  • ⑤:獲取程式狀態值。
  • ⑥:當前狀態值新增非同步功能,觸發呼叫驅動非同步處理函式。

KERNEL 訊號程式設計步驟

  • ①:定義非同步結構體。
  • ②:實現非同步操作函式,並把該函式填充到裝置核心驅動操作結構體中。
    • 該函式內容主要呼叫 fasync_helper() 函式,初始化非同步結構體。(把 file ,核心PID,交給非同步結構體
  • ③:傳送訊號。

14.4.3 使用函式說明

14.4.3.1 相關結構體及參考模型

APP 模型 截段:

......

/* 設定訊號 SIGIO 的處理函式 */
signal(SIGIO, sigio_signal_func);

fcntl(fd, F_SETOWN, getpid());     /* 將當前程式的程式號告訴給核心  */ 
flags = fcntl(fd, F_GETFD);           /* 獲取當前的程式狀態 */ 
fcntl(fd, F_SETFL, flags | FASYNC); /* 設定程式啟用非同步通知功能。會呼叫驅動中的 drv_fasync 函式 */

......

fasync_struct

  • (在核心原始碼中,目前沒有去找核心文件該結構體內容的相關資訊)
struct fasync_struct {
	rwlock_t		fa_lock;
	int			      magic;
	int			      fa_fd;
	struct fasync_struct	*fa_next; /* singly linked list */
	struct file		*fa_file;
	struct rcu_head		fa_rcu;
};
14.4.3.2 signal 函式

APP 使用

函式原型sighandler_t signal(int signum, sighandler_t handler) :

  • 功能:繫結訊號與回撥函式。
  • signum:訊號型別。除 SIGKILLSIGSTOP 外的任何一種訊號。
  • handler:該引數有三種型別。
    • ①:SIG_IGN 型別。表示忽略該訊號。
    • ②:SIG_DFL 型別。表示恢復對訊號的系統預設處理。
    • ③:sighandler_t 型別的函式指標。即是回撥函式。typedef void (*sighandler_t)(int);
  • 注:APP 收到訊號執行回撥函式時,signum 引數會被傳到回撥函式的形參傳遞給回撥函式。即是回撥函式的形參就是訊號型別。
14.4.3.3 kill_fasync 函式

KERNEL 使用

函式原型void kill_fasync(struct fasync_struct **fp, int sig, int band) :

  • 功能:傳送訊號給 fp 引數繫結的程式。(by PID
  • 參考路徑:linux-5.12.8\fs\fcntl.c
  • fp:需要操作的 fasync_struct
  • sig:訊號型別。
  • band:可讀時設定為 POLL_IN;可寫時設定為 POLL_OUT。當然該引數還可以填
    POLL_MSG。以上三個值在應用層接收時,si_code 分別為 0x01、0x02、0x03。

相關文章