0

sendfile(2)と を使用して、本質的に の機能を非同期的に模倣しようとしてaio_read(3)aio_write(3)ます。

大きな (> 150k) ファイルのテストを除いて、すべて正常に動作しているようです。

struct io_request転送を追跡するために使用している単純なものがあります。

struct io_request {
    int status;
    struct aiocb *aiocbp;
    int sfd;
};

まず、aio_read()呼び出しを作成します。

struct io_request * ioreq = malloc(sizeof(struct io_request));
ioreq->status = EINPROGRESS;
ioreq->sfd = sfd;

struct aiocb * aiocbreq = malloc(sizeof(struct aiocb));
memset(aiocbreq, 0, sizeof(struct aiocb));

ioreq->aiocbp = aiocbreq;

ioreq->aiocbp->aio_fildes = ffd;

if (ioreq->aiocbp->aio_fildes == -1) {
    perror("aio_fildes");
}

ioreq->aiocbp->aio_buf = malloc(st.st_size);
if (ioreq->aiocbp->aio_buf == NULL) {
    perror("aio_buf malloc");
}

ioreq->aiocbp->aio_nbytes = st.st_size;
ioreq->aiocbp->aio_reqprio = 0;
ioreq->aiocbp->aio_offset = 0;
ioreq->aiocbp->aio_sigevent.sigev_signo = IO_READ_SIGNAL;
ioreq->aiocbp->aio_sigevent.sigev_value.sival_ptr = ioreq;
if (aio_read(ioreq->aiocbp) == -1) {
    perror("aio_read");
}

その後、IO_READ_SIGNALハンドラーにキャプチャされます。

static void
aio_read_handler(int sig, siginfo_t *si, void *ucontext)
{
    if (si->si_code == SI_ASYNCIO) {
        struct io_request *ioreq = si->si_value.sival_ptr;

        // Build the AIO write request
        struct aiocb aiocbreq;
        memset(&aiocbreq, 0, sizeof(struct aiocb));
        aiocbreq.aio_fildes = ioreq->sfd;
        aiocbreq.aio_buf = ioreq->aiocbp->aio_buf;
        aiocbreq.aio_nbytes = ioreq->aiocbp->aio_nbytes;
        aiocbreq.aio_sigevent.sigev_signo = IO_WRITE_SIGNAL;
        aiocbreq.aio_sigevent.sigev_value.sival_ptr = ioreq;

        if (aio_write((void *) &aiocbreq) == -1) {
            perror("aio_write");
        }
    }
}

ioreq->aiocbp->aio_bufハンドラー内では、大きなファイルであっても、内容が完全であることが確認できます。

後で、ハンドラーaio_write()にキャプチャされます。IO_WRITE_SIGNAL

static void
aio_write_handler(int sig, siginfo_t *si, void *ucontext)
{
    if (si->si_code == SI_ASYNCIO) {
        struct io_request *ioreq = si->si_value.sival_ptr;

        ssize_t bytes_written = aio_return(ioreq->aiocbp);
        printf("Wrote %zu of %zu bytes\n", bytes_written, ioreq->aiocbp->aio_nbytes);
        //free(ioreq->aiocbp);
        //free(ioreq);

        if (aio_error(ioreq->aiocbp) != 0) {
            perror("aio_write_handler");
        }
    }
}

この時点aio_write()で完了しているはずです。戻り値を確認し、それに応じて行動します。どちらの呼び出しも、適切なバイト数が書き込まれ、書き込み中にエラーが発生しなかったことを報告します。

より大きなアプリケーションは HTTP サーバーです。この問題が発生するのは、リモート クライアントが .csv に追いつくのに十分な速さで読み取ることができないためだと推測しますaio_write()sendfile()これを実装したときsendfile()、ファイル転送を完了するために複数回呼び出す必要がありました。

いくつかの直接的な質問:

  • が問題を報告しないaio_return()のはなぜですか?aio_error()
  • この動作を修正するにはどうすればよいですか?
  • バッファリングする方法はありますaio_write()か? に渡されたn_bytes内部のキャッピングを考えていて、内部から複数回呼び出すだけでした。struct aiocbaio_write()aio_write()aio_write_handler()

ご協力いただきありがとうございます!

4

1 に答える 1

0

私の理解が正しければ、あなたはaio_returnbeforeを使用していますaio_erroraio_returnマニュアルページには、

この関数は、 aio_error (3) がEINPROGRESS以外の値を返した後、特定のリクエストに対して 1 回だけ呼び出す必要があり ます。

于 2016-12-08T22:46:40.983 に答える