summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2021-01-21 05:38:56 -0700
committerJens Axboe <axboe@kernel.dk>2021-01-21 05:38:56 -0700
commit2edfa3f84bcc44612b7a04caf1f048f5406fcc7a (patch)
treee37d24116eebe421a0345d47f9e0ab40fa4b30ed
parent73a9b2b06b08812ad83d1225be0abf31557a077f (diff)
downloadliburing-2edfa3f84bcc44612b7a04caf1f048f5406fcc7a.tar.gz
liburing-2edfa3f84bcc44612b7a04caf1f048f5406fcc7a.tar.bz2
Add test case for thread exiting with pending IO
A thread exiting should not have its IO canceled, that should only happen when the parent exits. Test that we are able to issue IO from a thread, with the parent reaping the completion when the thread exits. Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--test/Makefile3
-rw-r--r--test/thread-exit.c156
2 files changed, 159 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile
index 6aa1788..ce5d9e3 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -102,6 +102,7 @@ test_targets += \
stdout \
submit-reuse \
teardowns \
+ thread-exit \
timeout \
timeout-new \
timeout-overflow \
@@ -226,6 +227,7 @@ test_srcs := \
stdout.c \
submit-reuse.c \
teardowns.c \
+ thread-exit.c \
timeout-new.c \
timeout-overflow.c \
timeout.c \
@@ -248,6 +250,7 @@ ce593a6c480a-test: XCFLAGS = -lpthread
wakeup-hang: XCFLAGS = -lpthread
pipe-eof: XCFLAGS = -lpthread
timeout-new: XCFLAGS = -lpthread
+thread-exit: XCFLAGS = -lpthread
install: $(test_targets) runtests.sh runtests-loop.sh
$(INSTALL) -D -d -m 755 $(datadir)/liburing-test/
diff --git a/test/thread-exit.c b/test/thread-exit.c
new file mode 100644
index 0000000..722edbc
--- /dev/null
+++ b/test/thread-exit.c
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test that thread pool issued requests don't cancel on thread
+ * exit, but do get canceled once the parent exits. Do both
+ * writes that finish and a poll request that sticks around.
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <pthread.h>
+
+#include "liburing.h"
+
+#define NR_IOS 8
+#define WSIZE 512
+
+static int create_file(const char *file, size_t size)
+{
+ ssize_t ret;
+ char *buf;
+ int fd;
+
+ buf = malloc(size);
+ memset(buf, 0xaa, size);
+
+ fd = open(file, O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ perror("open file");
+ return 1;
+ }
+ ret = write(fd, buf, size);
+ close(fd);
+ free(buf);
+ return ret != size;
+}
+
+struct d {
+ int fd;
+ struct io_uring *ring;
+ unsigned long off;
+ int pipe_fd;
+ int err;
+};
+
+static void *do_io(void *data)
+{
+ struct d *d = data;
+ struct io_uring_sqe *sqe;
+ char *buffer;
+ int ret;
+
+ buffer = malloc(WSIZE);
+ memset(buffer, 0x5a, WSIZE);
+ sqe = io_uring_get_sqe(d->ring);
+ if (!sqe) {
+ d->err++;
+ return NULL;
+ }
+ io_uring_prep_write(sqe, d->fd, buffer, WSIZE, d->off);
+ sqe->user_data = d->off;
+
+ sqe = io_uring_get_sqe(d->ring);
+ if (!sqe) {
+ d->err++;
+ return NULL;
+ }
+ io_uring_prep_poll_add(sqe, d->pipe_fd, POLLIN);
+
+ ret = io_uring_submit(d->ring);
+ if (ret != 2)
+ d->err++;
+
+ free(buffer);
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ const char *fname;
+ pthread_t thread;
+ int ret, do_unlink, i, fd;
+ struct d d;
+ int fds[2];
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ ret = io_uring_queue_init(32, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed\n");
+ return 1;
+ }
+
+ if (argc > 1) {
+ fname = argv[1];
+ do_unlink = 0;
+ } else {
+ fname = ".thread.exit";
+ do_unlink = 1;
+ }
+
+ if (do_unlink && create_file(fname, 4096)) {
+ fprintf(stderr, "file create failed\n");
+ return 1;
+ }
+
+ fd = open(fname, O_WRONLY);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ d.fd = fd;
+ d.ring = &ring;
+ d.off = 0;
+ d.pipe_fd = fds[0];
+ d.err = 0;
+ for (i = 0; i < NR_IOS; i++) {
+ memset(&thread, 0, sizeof(thread));
+ pthread_create(&thread, NULL, do_io, &d);
+ pthread_join(thread, NULL);
+ d.off += WSIZE;
+ }
+
+ for (i = 0; i < NR_IOS; i++) {
+ struct io_uring_cqe *cqe;
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "io_uring_wait_cqe=%d\n", ret);
+ goto err;
+ }
+ if (cqe->res != WSIZE) {
+ fprintf(stderr, "cqe->res=%d, Expected %d\n", cqe->res,
+ WSIZE);
+ goto err;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ }
+
+ if (do_unlink)
+ unlink(fname);
+ return d.err;
+err:
+ if (do_unlink)
+ unlink(fname);
+ return 1;
+}