內核中與驅動相關的內存操作之十六(異步I/O)

1.異步IO簡介:

    Linux 異步 I/O 是Linux 2.6 中的一個標準特性,其本質思想就是進程發出數據傳輸請求之後,進程不會被阻塞,也不用等待任何操作完成,進程可以在數據傳輸的時候繼續執行其他的操作.相對於同步訪問文件的方式來說,異步訪問文件的方式可以提高應用程序的效率,並且提高系統資源利用率.直接 I/O 經常會和異步訪問文件的方式結合在一起使用.

    如下:



2.內核中關於異步IO的API:

    實際上,異步IO在驅動中很少會涉及.它也屬於fpos中的一個成員.如下:

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);
    aio_fsync 操作只對文件系統代碼感興趣, 因此我們在此不必討論它. 其他 2 個, aio_read 和 aio_write, 看起來非常象常規的 read 和 write 方法, 但是有幾個例外. 一個是 offset 參數由值傳遞; 異步操作從不改變文件位置, 因此沒有理由傳一個指針給它.

    這裏比較核心的參數是iocb,它是由內核創建、傳遞的,專門用於異步IO操作的.

    異步IO狀態查詢:

int is_sync_kiocb(struct kiocb *iocb); 
    如果這個函數返回一個非零值, 你的驅動必須同步執行這個操作.

    完成一個異步IO操作:

int aio_complete(struct kiocb *iocb, long res, long res2);
    iocb 是起初傳遞給你的同一個 IOCB,並且 res 是這個操作的通常的結果狀態.res2 是將被返回給用戶空間的第2個結果碼;大部分的異步 I/O 實現作爲 0 傳遞 res2. 一旦你調用 aio_complete,你不應當再碰 IOCB 或者用戶緩衝.
    

3.示例模板:

    下面的示例模板來自LDD3.

static ssize_t scullp_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(0, iocb, buf, count, pos);
}

static ssize_t scullp_aio_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(1, iocb, (char *) buf, count, pos);
}
    其中,scullp_aio_read()和scullp_aio_write()分別對應用戶空間的異步讀寫的系統調用.兩函數只調用了scullp_defer_op()函數:

struct async_work
{
        struct kiocb *iocb;
        int result;
        struct work_struct work;

};

static int scullp_defer_op(int write, struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        struct async_work *stuff;
        int result;

        /* Copy now while we can access the buffer */
        if (write)
                result = scullp_write(iocb->ki_filp, buf, count, &pos);
        else
                result = scullp_read(iocb->ki_filp, buf, count, &pos);

        /* If this is a synchronous IOCB, we return our status now. */
        if (is_sync_kiocb(iocb))
                return result;

        /* Otherwise defer the completion for a few milliseconds. */
        stuff = kmalloc (sizeof (*stuff), GFP_KERNEL);
        if (stuff == NULL)

                return result; /* No memory, just complete now */
        stuff->iocb = iocb;
        stuff->result = result;
        INIT_WORK(&stuff->work, scullp_do_deferred_op, stuff);
        schedule_delayed_work(&stuff->work, HZ/100);
        return -EIOCBQUEUED;
}
    注意到上述對iocb進行了狀態的輪詢,見上述語句:

        if (is_sync_kiocb(iocb))
                return result;
    一個異步IO的完成在等待隊列裏面:

static void scullp_do_deferred_op(void *p) 
{
 struct async_work *stuff = (struct async_work *) p;
 aio_complete(stuff->iocb, stuff->result, 0);
 kfree(stuff); 
} 








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章