Make sure all requests of a going away process are cancelled.

Signed-off-by: Pavel Begunkov <[email protected]>
---
 test/io-cancel.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/test/io-cancel.c b/test/io-cancel.c
index 75fbf43..d8b04d9 100644
--- a/test/io-cancel.c
+++ b/test/io-cancel.c
@@ -10,6 +10,8 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
 
 #include "liburing.h"
 
@@ -17,6 +19,8 @@
 #define BS             4096
 #define BUFFERS                (FILE_SIZE / BS)
 
+#define NR_REQS 10
+
 static struct iovec *vecs;
 
 static int create_buffers(void)
@@ -228,10 +232,108 @@ err:
        return 1;
 }
 
+static void submit_child(struct io_uring *ring, int fds[2])
+{
+       struct io_uring_sqe *sqe;
+       int ret, i;
+       char buffer[128];
+
+       for (i = 0; i < NR_REQS; ++i) {
+               sqe = io_uring_get_sqe(ring);
+               if (!sqe) {
+                       fprintf(stderr, "get sqe failed\n");
+                       goto err;
+               }
+               io_uring_prep_read(sqe, fds[0], buffer, sizeof(buffer), 0);
+               sqe->flags |= IOSQE_ASYNC;
+       }
+
+       ret = io_uring_submit(ring);
+       if (ret != NR_REQS) {
+               printf("sqe submit failed: %d\n", ret);
+               goto err;
+       }
+
+       exit(0);
+err:
+       exit(-1);
+}
+
+/* make sure requests of a going away task are cancelled */
+static int test_cancel_exiting_task(void)
+{
+       struct io_uring *ring;
+       int ret, i;
+       pid_t p;
+       int fds[2];
+
+       ring = mmap(0, sizeof(*ring), PROT_READ|PROT_WRITE,
+                   MAP_SHARED | MAP_ANONYMOUS, 0, 0);
+       if (!ring) {
+               fprintf(stderr, "mmap failed\n");
+               return 1;
+       }
+
+       ret = io_uring_queue_init(NR_REQS * 2, ring, 0);
+       if (ret < 0) {
+               fprintf(stderr, "queue init failed\n");
+               return 1;
+       }
+
+       if (pipe(fds)) {
+               perror("pipe() failed");
+               exit(1);
+       }
+
+       p = fork();
+       if (p < 0) {
+               printf("fork() failed\n");
+               return 1;
+       }
+
+       if (p == 0) {
+               /* child */
+               submit_child(ring, fds);
+       } else {
+               int wstatus;
+               struct io_uring_cqe *cqe;
+
+               waitpid(p, &wstatus, 0);
+               if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
+                       fprintf(stderr, "child failed\n");
+                       return 1;
+               }
+
+               for (i = 0; i < NR_REQS; ++i) {
+                       ret = io_uring_wait_cqe(ring, &cqe);
+                       if (ret < 0) {
+                               printf("wait_cqes: wait completion %d\n", ret);
+                               return 1;
+                       }
+                       if (cqe->res != -ECANCELED && cqe->res != -EINTR) {
+                               fprintf(stderr, "invalid CQE: %i\n", cqe->res);
+                               return 1;
+                       }
+                       io_uring_cqe_seen(ring, cqe);
+               }
+       }
+
+       close(fds[0]);
+       close(fds[1]);
+       io_uring_queue_exit(ring);
+       munmap(ring, sizeof(*ring));
+       return 0;
+}
+
 int main(int argc, char *argv[])
 {
        int i, ret;
 
+       if (test_cancel_exiting_task()) {
+               fprintf(stderr, "test_cancel_exiting_task failed\n");
+               return 1;
+       }
+
        if (create_file(".basic-rw")) {
                fprintf(stderr, "file creation failed\n");
                goto err;
-- 
2.24.0

Reply via email to