在設備驅動中使用異步通知可以使得對設備的訪問可進行時,由驅動主動通知應用程序進行訪問。因此,使用無阻塞I/O的應用程序無需輪詢設備是否可訪問,而阻塞訪問也可以被類似“中斷”的異步通知所取代。異步通知類似於硬件上的“中斷”概念,比較准確的稱謂是“信號驅動的異步I/O”。
SIGHUP 終止進程 終端線路掛斷
SIGINT 終止進程 中斷進程
SIGQUIT 建立CORE文件終止進程,並且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟蹤自陷
SIGBUS 建立CORE文件 總線錯誤
SIGSEGV 建立CORE文件 段非法錯誤
SIGFPE 建立CORE文件 浮點異常
SIGIOT 建立CORE文件 執行I/O自陷
SIGKILL 終止進程 殺死進程
SIGPIPE 終止進程 向一個沒有讀進程的管道寫數據
SIGALARM 終止進程 計時器到時
SIGTERM 終止進程 軟件終止信號
SIGSTOP 停止進程 非終端來的停止信號
SIGTSTP 停止進程 終端來的停止信號
SIGCONT 忽略信號 繼續執行一個停止的進程
SIGURG 忽略信號 I/O緊急信號
SIGIO 忽略信號 描述符上可以進行I/O
SIGCHLD 忽略信號 當子進程停止或退出時通知父進程
SIGTTOU 停止進程 後台進程寫終端
SIGTTIN 停止進程 後台進程讀終端
SIGXGPU 終止進程 CPU時限超時
SIGXFSZ 終止進程 文件長度過長
SIGWINCH 忽略信號 窗口大小發生變化
SIGPROF 終止進程 統計分布圖用計時器到時
SIGUSR1 終止進程 用戶定義信號1
SIGUSR2 終止進程 用戶定義信號2
SIGVTALRM 終止進程 虛擬計時器到時
int sigaction(int signo,const struct sigaction *restrict act, struct sigaction *restrict oact);
實例:使用信號實現異步通知
//啟動信號機制
void sigterm_handler(int sigo)
{
char data[MAX_LEN];
int len;
len = read(STDIN_FILENO,&data,MAX_LEN);
data[len] = 0;
printf("Input available:%s\n",data);
exit(0);
}
int main(void)
{
int oflags;
//啟動信號驅動機制
signal(SIGIO,sigterm_handler);
fcntl(STDIN_FILENO,F_SETOWN,getpid());
oflags = fcntl(STDIN_FILENO,F_GETFL);
fctcl(STDIN_FILENO,F_SETFL,oflags | FASYNC);
//建立一個死循環,防止程序結束
whlie(1);
return 0;
}
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);
將fasync_struct結構體指針放到設備結構體中是最佳的選擇
//異步通知的設備結構體模板
struct xxx_dev{
struct cdev cdev;
...
struct fasync_struct *async_queue;//異步結構體指針
};
在設備驅動中的fasync()函數中,只需簡單地將該函數的3個參數以及fasync_struct結構體指針的指針作為第四個參數傳入fasync_helper()函數就可以了,模板如下
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);
}
在設備資源可獲得時應該調用kill_fasync()函數釋放SIGIO信號,可讀時第三個參數為POLL_IN,可寫時第三個參數為POLL_OUT,模板如下
static ssize_t xxx_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
struct xxx_dev *dev = filp->private_data;
...
//產生異步讀信息
if(dev->async_queue)
kill_fasync(&dev->async_queue,GIGIO,POLL_IN);
...
}
最後在文件關閉時,要將文件從異步通知列表中刪除
int xxx_release(struct inode *inode,struct file *filp)
{
//將文件從異步通知列表中刪除
xxx_fasync(-1,filp,0);
...
return 0;
}
同步I/O:linux系統中最常用的輸入輸出(I/O)模型是同步I/O,在這個模型中,當請求發出後,應用程序就會阻塞,知道請求滿足
異步I/O:I/O請求可能需要與其它進程產生交疊
Linux 系統中最常用的輸入/輸出(I/O)模型是同步 I/O
在這個模型中,當請求發出之後,應用程序就會阻塞,直到請求滿足為止 調用應用程序在等待 I/O 請求完成時不需要使用任何中央處理單元(CPU) 在某些情況下,I/O 請求可能需要與其他進程產生交疊,可移植操作系統接口(POSIX)異步 I/O(AIO)應用程序接口(API)就提供了這種功能
int aio_read( struct aiocb *aiocbp );
aio_write–異步寫
int aio_write( struct aiocb *aiocbp );
aio_error
int aio_error( struct aiocb *aiocbp );
aio_return–獲得異步操作的返回值
ssize_t aio_return( struct aiocb *aiocbp );
aio_suspend–掛起異步操作,直到異步請求完成為止
int aio_suspend( const struct aiocb *const cblist[], int n, const struct timespec *timeout );
aio_cancel–取消異步請求
int aio_cancel( int fd, struct aiocb *aiocbp );
lio_listio–同時發起多個傳輸(一次系統調用可以啟動大量的I/O操作)
int lio_listio( int mode, struct aiocb *list[], int nent, struct sigevent *sig );
io_setup( )
//Initializes an asynchronous context for the current process
io_submit( )
//Submits one or more asynchronous I/O operations
io_getevents( )
//Gets the completion status of some outstanding asynchronous I/O operations
io_cancel( )
//Cancels an outstanding I/O operation
io_destroy( )
//Removes an asynchronous context for the current process
通過is_sync_kiocb判斷某kiocb是否為同步I/O請求
如果是返回真,表示為異步I/O請求字符設備:必須明確應支持AIO(極少數是異步I/O操作)
字符設備驅動程序中file_operations 包含 3 個與 AIO 相關的成員函數,
ssize_t (*aio_read) (struct kiocb *iocb, char *buffer, size_t count, loff_t offset);
ssize_t (*aio_write) (struct kiocb *iocb, const char *buffer, size_t count, loff_t offset);
int (*aio_fsync) (struct kiocb *iocb, int datasync);
塊設備和網絡設備:本身是異步的