非同步通知的意思是:一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上「中斷」的概念,比較準確的稱謂是「訊號驅動的非同步i/o」.訊號是在軟體層次上對中斷機制的一種模擬,在原理上,乙個程序收到乙個訊號與處理器收到乙個中斷請求可以說是一樣的.訊號是非同步的,乙個程序不必通過任何操作來等待訊號的到達,事實上,程序也不知道訊號到底什麼時候到達。
實現非同步通知機制,使用者程式涉及2項工作,首先,得指定乙個程序作為檔案的「屬主(owner)」.當應用程式使用fcntl系統呼叫執行f_setown命令時,屬主程序的程序id號就被儲存在filp->f_owner中.這一步是必需的,目的是告訴核心將訊號發給誰,也就是發給哪個程序.然後為了真正啟動非同步通知機制,使用者程式還必須在裝置中設定fasync標誌,這通過fcntl的f_setfl命令完成的,檔案開啟時,fasync標誌被預設為是清除的.,每當fasync標誌改變時,驅動程式中的fasync()函式將得以執行。.執行完這兩個步驟之後,核心就可以在新資料到達時通過呼叫kill_fasync()函式請求傳送乙個sigio訊號給應用層,該訊號被傳送到存放在filp->f_owner中的程序(如果是負值就是程序組)
根據核心原始碼來看看呼叫過程,應用層呼叫fcntl(),會進行系統呼叫sys_fcntl(),接著呼叫do_fcntl(),再根據cmd呼叫相應的操作函式
sys_fcntl
do_fcntlasmlinkage long
sys_fcntl
(unsigned
int fd,
unsigned
int cmd,
unsigned
long arg)
err =
do_fcntl
(fd, cmd, arg, filp)
;fput
(filp)
;out:
return err;
}
setfl函式的內部實現static
long
do_fcntl
(int fd,
unsigned
int cmd,
unsigned
long arg,
struct file *filp)
return err;
}
f_setown函式的內部實現static
intsetfl
(int fd,
struct file * filp,
unsigned
long arg)
} filp->f_flags =
(arg & setfl_mask)
|(filp->f_flags &
~setfl_mask)
; out:
unlock_kernel()
;return error;
}t
相關的資料結構和函式int
f_setown
(struct file *filp,
unsigned
long arg,
int force)
static
void
f_modown
(struct file *filp,
unsigned
long pid,
uid_t uid, uid_t euid,
int force)
write_unlock_irq
(&filp->f_owner.lock)
;}
處理fasync標誌變更的函式struct fasync_struct
;
int
fasync_helper
(int fd,
struct file *filp,
int mode,
struct fasync_struct *
*fa)
;
釋放訊號用的函式int
fasync_helper
(int fd,
struct file * filp,
int on,
struct fasync_struct *
write_lock_irq
(&fasync_lock)
;//遍歷整個非同步通知佇列,看是否存在對應的檔案指標
for(fa =
*fp)
!=null
; fp =
&fa->fa_next)
else
goto out;
//找到了}}
//所謂的把程序新增到非同步通知佇列中,實則是將檔案指標關聯到非同步結構體物件,然後將該物件掛載在非同步通知佇列中(等待佇列也是這個原理)
if(on)
out:
write_unlock_irq
(&fasync_lock)
;return result;
}
void
kill_fasync
(struct fasync_struct *
*fa,
int sig,
int band)
;
當乙個開啟的檔案的fasync標誌被修改時,呼叫fasync_helper函式以便從相關的程序表中新增或刪除檔案.當資料到達時,可使用kill_fasync函式通知所有的相關程序。void
kill_fasync
(struct fasync_struct *
*fp,
int sig,
int band)
}void
__kill_fasync
(struct fasync_struct *fa,
int sig,
int band)
fown =
&fa->fa_file->f_owner;
//這就是應用層使用f_setown的意義,讓其通過非同步物件的檔案指標知道其主程序if(
!(sig == sigurg && fown->signum ==0)
)send_sigio
(fown, fa->fa_fd, band)
;//向主程序傳送訊號,也就是向我們的執行了fcntl(fd,f_setown,getpid())命令的應用程式傳送訊號
fa = fa->fa_next;
}}
Linux裝置驅動中的非同步通知和非同步IO
前面兩章分別提到io模型中的阻塞與非阻塞linux驅動 六 裝置驅動中的阻塞與非阻塞io,io多路復用驅動中輪詢操作實現,這一章我們再來看看非同步io,這樣,io模型就可以都搞定了。回顧一下在應用程式中使用非同步io的步驟 1,應用程式 1 設定非同步標誌位 int flags fcntl fd,f...
linux中驅動非同步通知
驅動程式執行在核心空間中,應用程式執行在使用者空間中,兩者是不能直接通訊的。但在實際應用中,在裝置已經準備好的時候,我們希望通知使用者程式裝置已經ok,使用者程式可以讀取了,這樣應用程式就不需要一直查詢該裝置的狀態,從而節約了資源,這就是非同步通知。好,那下乙個問題就來了,這個過程如何實現呢?簡單,...
Linux驅動中的非同步通知
在很多應用中都需要應用程式主動去查詢驅動中是否有資料可讀或者是否可以向驅動寫入資料,對於單執行緒的應用,這可能會導致程序阻塞。當然,可以使用select來不斷輪詢驅動是否可讀或可寫,但是這並不是很好的解決方法,更好的解決方式是由驅動主動通知應用程式其狀態,而不是應用程式主動去查詢驅動的狀態。非同步通...