sq-poll-kthread tests if the 'io_uring-sq' kthread is stopped when the userspace process ended with or without closing the io_uring fd. Signed-off-by: Stefano Garzarella <sgarzare@xxxxxxxxxx> --- .gitignore | 1 + test/Makefile | 4 +- test/sq-poll-kthread.c | 165 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 test/sq-poll-kthread.c diff --git a/.gitignore b/.gitignore index 1ab4075..9f85a5f 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ /test/short-read /test/socket-rw /test/sq-full +/test/sq-poll-kthread /test/sq-space_left /test/statx /test/stdout diff --git a/test/Makefile b/test/Makefile index cf91011..09c7aa2 100644 --- a/test/Makefile +++ b/test/Makefile @@ -20,7 +20,7 @@ all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register connect 7ad0e4b2f83c-test submit-reuse fallocate open-close \ file-update statx accept-reuse poll-v-poll fadvise madvise \ short-read openat2 probe shared-wq personality eventfd \ - send_recv eventfd-ring across-fork + send_recv eventfd-ring across-fork sq-poll-kthread include ../Makefile.quiet @@ -47,7 +47,7 @@ test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \ 7ad0e4b2f83c-test.c submit-reuse.c fallocate.c open-close.c \ file-update.c statx.c accept-reuse.c poll-v-poll.c fadvise.c \ madvise.c short-read.c openat2.c probe.c shared-wq.c \ - personality.c eventfd.c eventfd-ring.c across-fork.c + personality.c eventfd.c eventfd-ring.c across-fork.c sq-poll-kthread.c test_objs := $(patsubst %.c,%.ol,$(test_srcs)) diff --git a/test/sq-poll-kthread.c b/test/sq-poll-kthread.c new file mode 100644 index 0000000..d53605c --- /dev/null +++ b/test/sq-poll-kthread.c @@ -0,0 +1,165 @@ +/* + * Description: test if io_uring SQ poll kthread is stopped when the userspace + * process ended with or without closing the io_uring fd + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/poll.h> +#include <sys/wait.h> +#include <sys/epoll.h> + +#include "liburing.h" + +#define SQ_THREAD_IDLE 2000 +#define BUF_SIZE 128 +#define KTHREAD_NAME "io_uring-sq" + +enum { + TEST_OK = 0, + TEST_SKIPPED = 1, + TEST_FAILED = 2, +}; + +static int do_test_sq_poll_kthread_stopped(bool do_exit) +{ + int ret = 0, pipe1[2]; + struct io_uring_params param; + struct io_uring ring; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + uint8_t buf[BUF_SIZE]; + struct iovec iov; + + if (geteuid()) { + fprintf(stderr, "sqpoll requires root!\n"); + return TEST_SKIPPED; + } + + if (pipe(pipe1) != 0) { + perror("pipe"); + return TEST_FAILED; + } + + memset(¶m, 0, sizeof(param)); + + param.flags |= IORING_SETUP_SQPOLL; + param.sq_thread_idle = SQ_THREAD_IDLE; + + ret = io_uring_queue_init_params(16, &ring, ¶m); + if (ret) { + fprintf(stderr, "ring setup failed\n"); + ret = TEST_FAILED; + goto err_pipe; + } + + ret = io_uring_register_files(&ring, &pipe1[1], 1); + if (ret) { + fprintf(stderr, "file reg failed: %d\n", ret); + ret = TEST_FAILED; + goto err_uring; + } + + iov.iov_base = buf; + iov.iov_len = BUF_SIZE; + + sqe = io_uring_get_sqe(&ring); + if (!sqe) { + fprintf(stderr, "io_uring_get_sqe failed\n"); + ret = TEST_FAILED; + goto err_uring; + } + + io_uring_prep_writev(sqe, 0, &iov, 1, 0); + sqe->flags |= IOSQE_FIXED_FILE; + + ret = io_uring_submit(&ring); + if (ret < 0) { + fprintf(stderr, "io_uring_submit failed - ret: %d\n", + ret); + ret = TEST_FAILED; + goto err_uring; + } + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) { + fprintf(stderr, "io_uring_wait_cqe - ret: %d\n", + ret); + ret = TEST_FAILED; + goto err_uring; + } + + if (cqe->res != BUF_SIZE) { + fprintf(stderr, "unexpected cqe->res %d [expected %d]\n", + cqe->res, BUF_SIZE); + ret = TEST_FAILED; + goto err_uring; + + } + + io_uring_cqe_seen(&ring, cqe); + + ret = TEST_OK; + +err_uring: + if (do_exit) + io_uring_queue_exit(&ring); +err_pipe: + close(pipe1[0]); + close(pipe1[1]); + + return ret; +} + +int test_sq_poll_kthread_stopped(bool do_exit) { + pid_t pid; + int status = 0; + + pid = fork(); + + if (pid == 0) { + int ret = do_test_sq_poll_kthread_stopped(do_exit); + exit(ret); + } + + pid = wait(&status); + if (status != 0) + return WEXITSTATUS(status); + + if (system("ps --ppid 2 | grep " KTHREAD_NAME) == 0) { + fprintf(stderr, "%s kthread still running!\n", KTHREAD_NAME); + return TEST_FAILED; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = test_sq_poll_kthread_stopped(true); + if (ret == TEST_SKIPPED) { + printf("test_sq_poll_kthread_stopped_exit: skipped\n"); + } else if (ret == TEST_FAILED) { + fprintf(stderr, "test_sq_poll_kthread_stopped_exit failed\n"); + return ret; + } + + ret = test_sq_poll_kthread_stopped(false); + if (ret == TEST_SKIPPED) { + printf("test_sq_poll_kthread_stopped_noexit: skipped\n"); + } else if (ret == TEST_FAILED) { + fprintf(stderr, "test_sq_poll_kthread_stopped_noexit failed\n"); + return ret; + } + + return 0; +} -- 2.24.1