BruceChen7 / gitblog

My blog
6 stars 1 forks source link

liburing使用之拷贝文件 #64

Open BruceChen7 opened 1 year ago

BruceChen7 commented 1 year ago

参考资料

在拷贝之的初始化

int main(int argc, char *argv[])
{
    struct io_uring ring;
    off_t insize;
    int ret;

    if (argc < 3) {
        ...
    }

    //open files
    infd = open(argv[1], O_RDONLY);
    if (infd < 0) {
        ...
    }
    // write file
    outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (outfd < 0) {
        ...
    }

    if (setup_context(QD, &ring))
        ...
    // get file size
    if (get_file_size(infd, &insize))
        ...

    // copy to ring
    ret = copy_file(&ring, insize);

    close(infd);
    close(outfd);
    io_uring_queue_exit(&ring);
    return ret;
}

setup_context

拷贝文件

static int copy_file(struct io_uring *ring, off_t insize)
{
    unsigned long reads, writes;
    // complete queue
    struct io_uring_cqe *cqe;
    off_t write_left, offset;
    int ret;

    // left bytes to be written
    write_left = insize;
    writes = reads = offset = 0;
    while(insize || write_left) {
        ....
    }
    while(writes) {
        ...
    }
}

读写文件的过程


while (insize || write_left) {
    unsigned long had_reads;
    int got_comp;

    /*
     * Queue up as many reads as we can
     */
    had_reads = reads;
    while (insize) {
        ...
    }

    if (had_reads != reads) {
        ...
    }

    /*
     * Queue is full at this point. Find at least one completion.
     */
    got_comp = 0;
    while (write_left) {
        ...
    }
}

while(insize)

while (insize) {
    off_t this_size = insize;

    // over buffer size
    if (reads + writes >= QD)
        break;

    // 32 KB
    if (this_size > BS)
        this_size = BS;
    // is zero
    else if (!this_size)
        break;

    // queue read
    // read error
    // none zero means failed
    if (queue_read(ring, this_size, offset))
        break;

    // left read size
    insize -= this_size;
    // last read pointer
    offset += this_size;
    reads++;
}

queue_read(ring, this_size, offset)

static int queue_read(struct io_uring *ring, off_t size, off_t offset)
{
    // submit queue
    struct io_uring_sqe *sqe;
    // io data
    struct io_data *data;

    data = malloc(size + sizeof(*data));
    if (!data)
        return 1;

    // get a submit entry
    sqe = io_uring_get_sqe(ring);
    if (!sqe) {
        free(data);
        return 1;
    }

    // set data ready to be read
    data->read = 1;
    // set off set
    data->offset = data->first_offset = offset;

    // set actual data pointer
    data->iov.iov_base = data + 1;
    // read size
    data->iov.iov_len = size;
    data->first_len = size;

    // prepare for read, set read buffer which is data->iov
    // offset 上次读的位置
    // 设置关联的文件描述符
    io_uring_prep_readv(sqe, infd, &data->iov, 1, offset);
    // set bussiness data pointer
    io_uring_sqe_set_data(sqe, data);
    return 0;
}
struct io_data {
    int read;
    off_t first_offset, offset;
    size_t first_len;
    struct iovec iov;
};

if (had_reads != reads)

if (had_reads != reads) {
    ret = io_uring_submit(ring);
    if (ret < 0) {
        ...
        break;
    }
}

while(write_left)

got_comp = 0;
while (write_left) {
    // actual data
    struct io_data *data;

    if (!got_comp) {
        // wait io complete, will write cqe
        ret = io_uring_wait_cqe(ring, &cqe);
        got_comp = 1;
    } else {
        ...
    }
    if (ret < 0) {
        ...
        return 1;
    }
    if (!cqe)
        break;

    // read from complete queue
    data = io_uring_cqe_get_data(cqe);
    // deal with error
    if (cqe->res < 0) {
        ...
    } else if ((size_t)cqe->res != data->iov.iov_len) {
        ...
    }

    /*
     * All done. if write, nothing else to do. if read,
     * queue up corresponding write.
     */
    // data has been read
    if (data->read) {
        ...
    } else {
        ...
    }
    // mark cqe has been dealed with
    io_uring_cqe_seen(ring, cqe);
}

while(writes)

/* wait out pending writes */
while (writes) {
    struct io_data *data;

    ret = io_uring_wait_cqe(ring, &cqe);
    if (ret) {
        fprintf(stderr, "wait_cqe=%d\n", ret);
        return 1;
    }
    if (cqe->res < 0) {
        fprintf(stderr, "write res=%d\n", cqe->res);
        return 1;
    }
    // 从read 中获取datata
    data = io_uring_cqe_get_data(cqe);
    free(data);
    writes--;
    io_uring_cqe_seen(ring, cqe);
}

queue_write(ring, data)


static void queue_write(struct io_uring *ring, struct io_data *data)
{
    data->read = 0;
    data->offset = data->first_offset;

    data->iov.iov_base = data + 1;
    data->iov.iov_len = data->first_len;

    queue_prepped(ring, data);
    io_uring_submit(ring);
}

queue_prepped

static void queue_prepped(struct io_uring *ring, struct io_data *data)
{
    struct io_uring_sqe *sqe;

    // get a submit entry
    sqe = io_uring_get_sqe(ring);
    assert(sqe);

    if (data->read)
        // prepare for read, 1 means iov_len
        io_uring_prep_readv(sqe, infd, &data->iov, 1, data->offset);
    else
        io_uring_prep_writev(sqe, outfd, &data->iov, 1, data->offset);

    // set bussiness data pointer
    io_uring_sqe_set_data(sqe, data);
}

总结

在使用liburing时,



#type/code #type/linux #public