1. 程式人生 > >核心中與驅動相關的記憶體操作之十六(非同步I/O)

核心中與驅動相關的記憶體操作之十六(非同步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); 
}