| /* SPDX-License-Identifier: MIT */ | |
| /* | |
| * Description: check that STDOUT write works | |
| */ | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <fcntl.h> | |
| #include "helpers.h" | |
| #include "liburing.h" | |
| static int test_pipe_io_fixed(struct io_uring *ring) | |
| { | |
| const char str[] = "This is a fixed pipe test\n"; | |
| struct io_uring_cqe *cqe; | |
| struct io_uring_sqe *sqe; | |
| struct iovec vecs[2]; | |
| char buffer[128]; | |
| int i, ret, fds[2]; | |
| t_posix_memalign(&vecs[0].iov_base, 4096, 4096); | |
| memcpy(vecs[0].iov_base, str, strlen(str)); | |
| vecs[0].iov_len = strlen(str); | |
| if (pipe(fds) < 0) { | |
| perror("pipe"); | |
| return 1; | |
| } | |
| ret = io_uring_register_buffers(ring, vecs, 1); | |
| if (ret) { | |
| fprintf(stderr, "Failed to register buffers: %d\n", ret); | |
| return 1; | |
| } | |
| sqe = io_uring_get_sqe(ring); | |
| if (!sqe) { | |
| fprintf(stderr, "get sqe failed\n"); | |
| goto err; | |
| } | |
| io_uring_prep_write_fixed(sqe, fds[1], vecs[0].iov_base, | |
| vecs[0].iov_len, 0, 0); | |
| sqe->user_data = 1; | |
| sqe = io_uring_get_sqe(ring); | |
| if (!sqe) { | |
| fprintf(stderr, "get sqe failed\n"); | |
| goto err; | |
| } | |
| vecs[1].iov_base = buffer; | |
| vecs[1].iov_len = sizeof(buffer); | |
| io_uring_prep_readv(sqe, fds[0], &vecs[1], 1, 0); | |
| sqe->user_data = 2; | |
| ret = io_uring_submit(ring); | |
| if (ret < 0) { | |
| fprintf(stderr, "sqe submit failed: %d\n", ret); | |
| goto err; | |
| } else if (ret != 2) { | |
| fprintf(stderr, "Submitted only %d\n", ret); | |
| goto err; | |
| } | |
| for (i = 0; i < 2; i++) { | |
| ret = io_uring_wait_cqe(ring, &cqe); | |
| if (ret < 0) { | |
| fprintf(stderr, "wait completion %d\n", ret); | |
| goto err; | |
| } | |
| if (cqe->res < 0) { | |
| fprintf(stderr, "I/O write error on %lu: %s\n", | |
| (unsigned long) cqe->user_data, | |
| strerror(-cqe->res)); | |
| goto err; | |
| } | |
| if (cqe->res != strlen(str)) { | |
| fprintf(stderr, "Got %d bytes, wanted %d on %lu\n", | |
| cqe->res, (int)strlen(str), | |
| (unsigned long) cqe->user_data); | |
| goto err; | |
| } | |
| if (cqe->user_data == 2 && memcmp(str, buffer, strlen(str))) { | |
| fprintf(stderr, "read data mismatch\n"); | |
| goto err; | |
| } | |
| io_uring_cqe_seen(ring, cqe); | |
| } | |
| io_uring_unregister_buffers(ring); | |
| free(vecs[0].iov_base); | |
| return 0; | |
| err: | |
| return 1; | |
| } | |
| static int test_stdout_io_fixed(struct io_uring *ring) | |
| { | |
| const char str[] = "This is a fixed pipe test\n"; | |
| struct io_uring_cqe *cqe; | |
| struct io_uring_sqe *sqe; | |
| struct iovec vecs; | |
| int ret; | |
| t_posix_memalign(&vecs.iov_base, 4096, 4096); | |
| memcpy(vecs.iov_base, str, strlen(str)); | |
| vecs.iov_len = strlen(str); | |
| ret = io_uring_register_buffers(ring, &vecs, 1); | |
| if (ret) { | |
| fprintf(stderr, "Failed to register buffers: %d\n", ret); | |
| return 1; | |
| } | |
| sqe = io_uring_get_sqe(ring); | |
| if (!sqe) { | |
| fprintf(stderr, "get sqe failed\n"); | |
| goto err; | |
| } | |
| io_uring_prep_write_fixed(sqe, STDOUT_FILENO, vecs.iov_base, vecs.iov_len, 0, 0); | |
| ret = io_uring_submit(ring); | |
| if (ret < 0) { | |
| fprintf(stderr, "sqe submit failed: %d\n", ret); | |
| goto err; | |
| } else if (ret < 1) { | |
| fprintf(stderr, "Submitted only %d\n", ret); | |
| goto err; | |
| } | |
| ret = io_uring_wait_cqe(ring, &cqe); | |
| if (ret < 0) { | |
| fprintf(stderr, "wait completion %d\n", ret); | |
| goto err; | |
| } | |
| if (cqe->res < 0) { | |
| fprintf(stderr, "STDOUT write error: %s\n", strerror(-cqe->res)); | |
| goto err; | |
| } | |
| if (cqe->res != vecs.iov_len) { | |
| fprintf(stderr, "Got %d write, wanted %d\n", cqe->res, (int)vecs.iov_len); | |
| goto err; | |
| } | |
| io_uring_cqe_seen(ring, cqe); | |
| io_uring_unregister_buffers(ring); | |
| free(vecs.iov_base); | |
| return 0; | |
| err: | |
| return 1; | |
| } | |
| static int test_stdout_io(struct io_uring *ring) | |
| { | |
| struct io_uring_cqe *cqe; | |
| struct io_uring_sqe *sqe; | |
| struct iovec vecs; | |
| int ret; | |
| vecs.iov_base = "This is a pipe test\n"; | |
| vecs.iov_len = strlen(vecs.iov_base); | |
| sqe = io_uring_get_sqe(ring); | |
| if (!sqe) { | |
| fprintf(stderr, "get sqe failed\n"); | |
| goto err; | |
| } | |
| io_uring_prep_writev(sqe, STDOUT_FILENO, &vecs, 1, 0); | |
| ret = io_uring_submit(ring); | |
| if (ret < 0) { | |
| fprintf(stderr, "sqe submit failed: %d\n", ret); | |
| goto err; | |
| } else if (ret < 1) { | |
| fprintf(stderr, "Submitted only %d\n", ret); | |
| goto err; | |
| } | |
| ret = io_uring_wait_cqe(ring, &cqe); | |
| if (ret < 0) { | |
| fprintf(stderr, "wait completion %d\n", ret); | |
| goto err; | |
| } | |
| if (cqe->res < 0) { | |
| fprintf(stderr, "STDOUT write error: %s\n", | |
| strerror(-cqe->res)); | |
| goto err; | |
| } | |
| if (cqe->res != vecs.iov_len) { | |
| fprintf(stderr, "Got %d write, wanted %d\n", cqe->res, | |
| (int)vecs.iov_len); | |
| goto err; | |
| } | |
| io_uring_cqe_seen(ring, cqe); | |
| return 0; | |
| err: | |
| return 1; | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| struct io_uring ring; | |
| int ret; | |
| if (argc > 1) | |
| return 0; | |
| ret = io_uring_queue_init(8, &ring, 0); | |
| if (ret) { | |
| fprintf(stderr, "ring setup failed\n"); | |
| return 1; | |
| } | |
| ret = test_stdout_io(&ring); | |
| if (ret) { | |
| fprintf(stderr, "test_pipe_io failed\n"); | |
| return ret; | |
| } | |
| ret = test_stdout_io_fixed(&ring); | |
| if (ret) { | |
| fprintf(stderr, "test_pipe_io_fixed failed\n"); | |
| return ret; | |
| } | |
| ret = test_pipe_io_fixed(&ring); | |
| if (ret) { | |
| fprintf(stderr, "test_pipe_io_fixed failed\n"); | |
| return ret; | |
| } | |
| return 0; | |
| } |