| /* 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); |
| 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); |
| 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; |
| } |