• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Test case testing exit without cleanup and io-wq work pending or queued.
4  *
5  * From Florian Fischer <florian.fl.fischer@fau.de>
6  * Link: https://lore.kernel.org/io-uring/20211202165606.mqryio4yzubl7ms5@pasture/
7  *
8  */
9 #include <assert.h>
10 #include <err.h>
11 #include <errno.h>
12 #include <pthread.h>
13 #include <semaphore.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/sysinfo.h>
17 #include <unistd.h>
18 
19 #include "liburing.h"
20 #include "helpers.h"
21 
22 #define IORING_ENTRIES 8
23 
24 static pthread_t *threads;
25 static pthread_barrier_t init_barrier;
26 static int sleep_fd, notify_fd;
27 static sem_t sem;
28 
thread_func(void * arg)29 void *thread_func(void *arg)
30 {
31 	struct io_uring ring;
32 	int res;
33 
34 	res = io_uring_queue_init(IORING_ENTRIES, &ring, 0);
35 	if (res)
36 		err(EXIT_FAILURE, "io_uring_queue_init failed");
37 
38 	pthread_barrier_wait(&init_barrier);
39 
40 	for(;;) {
41 		struct io_uring_cqe *cqe;
42 		struct io_uring_sqe *sqe;
43 		uint64_t buf;
44 		int res;
45 
46 		sqe = io_uring_get_sqe(&ring);
47 		assert(sqe);
48 
49 		io_uring_prep_read(sqe, sleep_fd, &buf, sizeof(buf), 0);
50 
51 		res = io_uring_submit_and_wait(&ring, 1);
52 		if (res < 0)
53 			err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
54 
55 		res = io_uring_peek_cqe(&ring, &cqe);
56 		assert(!res);
57 		if (cqe->res < 0) {
58 			errno = -cqe->res;
59 			err(EXIT_FAILURE, "read failed");
60 		}
61 		assert(cqe->res == sizeof(buf));
62 
63 		sem_post(&sem);
64 
65 		io_uring_cqe_seen(&ring, cqe);
66 	}
67 
68 	return NULL;
69 }
70 
main(int argc,char * argv[])71 int main(int argc, char *argv[])
72 {
73 	int res, fds[2], i, cpus;
74 	const uint64_t n = 0x42;
75 
76 	if (argc > 1)
77 		return 0;
78 
79 	cpus = get_nprocs();
80 	res = pthread_barrier_init(&init_barrier, NULL, cpus);
81 	if (res)
82 		err(EXIT_FAILURE, "pthread_barrier_init failed");
83 
84 	res = sem_init(&sem, 0, 0);
85 	if (res)
86 		err(EXIT_FAILURE, "sem_init failed");
87 
88 	threads = t_malloc(sizeof(pthread_t) * cpus);
89 
90 	res = pipe(fds);
91 	if (res)
92 		err(EXIT_FAILURE, "pipe failed");
93 
94 	sleep_fd = fds[0];
95 	notify_fd = fds[1];
96 
97 	for (i = 0; i < cpus; i++) {
98 		errno = pthread_create(&threads[i], NULL, thread_func, NULL);
99 		if (errno)
100 			err(EXIT_FAILURE, "pthread_create failed");
101 	}
102 
103 	// Write #cpus notifications
104 	for (i = 0; i < cpus; i++) {
105 		res = write(notify_fd, &n, sizeof(n));
106 		if (res < 0)
107 			err(EXIT_FAILURE, "write failed");
108 		assert(res == sizeof(n));
109 	}
110 
111 	// Await that all notifications were received
112 	for (i = 0; i < cpus; i++)
113 		sem_wait(&sem);
114 
115 	// Exit without resource cleanup
116 	exit(EXIT_SUCCESS);
117 }
118