1 /*
2 * Test 5.7 regression with task_work not being run while a task is
3 * waiting on another event in the kernel.
4 */
5 #include <errno.h>
6 #include <poll.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/eventfd.h>
10 #include <unistd.h>
11 #include <pthread.h>
12 #include "liburing.h"
13 #include "helpers.h"
14
15 static int use_sqpoll = 0;
16
notify_fd(int fd)17 void notify_fd(int fd)
18 {
19 char buf[8] = {0, 0, 0, 0, 0, 0, 1};
20 int ret;
21
22 ret = write(fd, &buf, 8);
23 if (ret < 0)
24 perror("write");
25 }
26
delay_set_fd_from_thread(void * data)27 void *delay_set_fd_from_thread(void *data)
28 {
29 int fd = (intptr_t) data;
30
31 sleep(1);
32 notify_fd(fd);
33 return NULL;
34 }
35
main(int argc,char * argv[])36 int main(int argc, char *argv[])
37 {
38 struct io_uring_params p = {};
39 struct io_uring ring;
40 int loop_fd, other_fd;
41 struct io_uring_sqe *sqe;
42 struct io_uring_cqe *cqe = NULL;
43 int ret, use_fd;
44 char buf[8] = {0, 0, 0, 0, 0, 0, 1};
45 pthread_t tid;
46
47 if (argc > 1)
48 return 0;
49
50 /* Create an eventfd to be registered with the loop to be
51 * notified of events being ready
52 */
53 loop_fd = eventfd(0, EFD_CLOEXEC);
54 if (loop_fd == -1) {
55 fprintf(stderr, "eventfd errno=%d\n", errno);
56 return 1;
57 }
58
59 /* Create an eventfd that can create events */
60 use_fd = other_fd = eventfd(0, EFD_CLOEXEC);
61 if (other_fd == -1) {
62 fprintf(stderr, "eventfd errno=%d\n", errno);
63 return 1;
64 }
65
66 if (use_sqpoll)
67 p.flags = IORING_SETUP_SQPOLL;
68
69 /* Setup the ring with a registered event fd to be notified on events */
70 ret = t_create_ring_params(8, &ring, &p);
71 if (ret == T_SETUP_SKIP)
72 return 0;
73 else if (ret < 0)
74 return ret;
75
76 ret = io_uring_register_eventfd(&ring, loop_fd);
77 if (ret < 0) {
78 fprintf(stderr, "register_eventfd=%d\n", ret);
79 return 1;
80 }
81
82 if (use_sqpoll) {
83 ret = io_uring_register_files(&ring, &other_fd, 1);
84 if (ret < 0) {
85 fprintf(stderr, "register_files=%d\n", ret);
86 return 1;
87 }
88 use_fd = 0;
89 }
90
91 /* Submit a poll operation to wait on an event in other_fd */
92 sqe = io_uring_get_sqe(&ring);
93 io_uring_prep_poll_add(sqe, use_fd, POLLIN);
94 sqe->user_data = 1;
95 if (use_sqpoll)
96 sqe->flags |= IOSQE_FIXED_FILE;
97 ret = io_uring_submit(&ring);
98 if (ret != 1) {
99 fprintf(stderr, "submit=%d\n", ret);
100 return 1;
101 }
102
103 /*
104 * CASE 3: Hangs forever in Linux 5.7.5; Works in Linux 5.6.0 When this
105 * code is uncommented, we don't se a notification on other_fd until
106 * _after_ we have started the read on loop_fd. In that case, the read() on
107 * loop_fd seems to hang forever.
108 */
109 pthread_create(&tid, NULL, delay_set_fd_from_thread,
110 (void*) (intptr_t) other_fd);
111
112 /* Wait on the event fd for an event to be ready */
113 ret = read(loop_fd, buf, 8);
114 if (ret < 0) {
115 perror("read");
116 return 1;
117 } else if (ret != 8) {
118 fprintf(stderr, "Odd-sized eventfd read: %d\n", ret);
119 return 1;
120 }
121
122
123 ret = io_uring_wait_cqe(&ring, &cqe);
124 if (ret) {
125 fprintf(stderr, "wait_cqe=%d\n", ret);
126 return ret;
127 }
128 if (cqe->res < 0) {
129 fprintf(stderr, "cqe->res=%d\n", cqe->res);
130 return 1;
131 }
132
133 io_uring_cqe_seen(&ring, cqe);
134 return 0;
135 }
136