1 /* SPDX-License-Identifier: MIT */
2 #include <sys/eventfd.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <pthread.h>
8 #include <liburing.h>
9 #include <fcntl.h>
10 #include <poll.h>
11 #include <sys/time.h>
12
13 struct thread_data {
14 struct io_uring *ring;
15 int write_fd;
16 };
17
error_exit(char * message)18 static void error_exit(char *message)
19 {
20 perror(message);
21 exit(1);
22 }
23
listener_thread(void * data)24 static void *listener_thread(void *data)
25 {
26 struct thread_data *td = data;
27 struct io_uring_cqe *cqe;
28 int ret;
29
30 ret = io_uring_wait_cqe(td->ring, &cqe);
31 if (ret < 0) {
32 fprintf(stderr, "Error waiting for completion: %s\n",
33 strerror(-ret));
34 goto err;
35 }
36 if (cqe->res < 0) {
37 fprintf(stderr, "Error in async operation: %s\n", strerror(-cqe->res));
38 goto err;
39 }
40 io_uring_cqe_seen(td->ring, cqe);
41 return NULL;
42 err:
43 return (void *) 1;
44 }
45
wakeup_io_uring(void * data)46 static void *wakeup_io_uring(void *data)
47 {
48 struct thread_data *td = data;
49 int res;
50
51 res = eventfd_write(td->write_fd, (eventfd_t) 1L);
52 if (res < 0) {
53 perror("eventfd_write");
54 return (void *) 1;
55 }
56 return NULL;
57 }
58
test_pipes(void)59 static int test_pipes(void)
60 {
61 struct io_uring_sqe *sqe;
62 struct thread_data td;
63 struct io_uring ring;
64 pthread_t t1, t2;
65 int ret, fds[2];
66 void *pret;
67
68 if (pipe(fds) < 0)
69 error_exit("eventfd");
70
71 ret = io_uring_queue_init(8, &ring, 0);
72 if (ret) {
73 fprintf(stderr, "Unable to setup io_uring: %s\n", strerror(-ret));
74 return 1;
75 }
76
77 td.write_fd = fds[1];
78 td.ring = ˚
79
80 sqe = io_uring_get_sqe(&ring);
81 io_uring_prep_poll_add(sqe, fds[0], POLLIN);
82 sqe->user_data = 2;
83 ret = io_uring_submit(&ring);
84 if (ret != 1) {
85 fprintf(stderr, "ring_submit=%d\n", ret);
86 return 1;
87 }
88
89 pthread_create(&t1, NULL, listener_thread, &td);
90
91 sleep(1);
92
93 pthread_create(&t2, NULL, wakeup_io_uring, &td);
94 pthread_join(t1, &pret);
95
96 io_uring_queue_exit(&ring);
97 return pret != NULL;
98 }
99
test_eventfd(void)100 static int test_eventfd(void)
101 {
102 struct io_uring_sqe *sqe;
103 struct thread_data td;
104 struct io_uring ring;
105 pthread_t t1, t2;
106 int efd, ret;
107 void *pret;
108
109 efd = eventfd(0, 0);
110 if (efd < 0)
111 error_exit("eventfd");
112
113 ret = io_uring_queue_init(8, &ring, 0);
114 if (ret) {
115 fprintf(stderr, "Unable to setup io_uring: %s\n", strerror(-ret));
116 return 1;
117 }
118
119 td.write_fd = efd;
120 td.ring = ˚
121
122 sqe = io_uring_get_sqe(&ring);
123 io_uring_prep_poll_add(sqe, efd, POLLIN);
124 sqe->user_data = 2;
125 ret = io_uring_submit(&ring);
126 if (ret != 1) {
127 fprintf(stderr, "ring_submit=%d\n", ret);
128 return 1;
129 }
130
131 pthread_create(&t1, NULL, listener_thread, &td);
132
133 sleep(1);
134
135 pthread_create(&t2, NULL, wakeup_io_uring, &td);
136 pthread_join(t1, &pret);
137
138 io_uring_queue_exit(&ring);
139 return pret != NULL;
140 }
141
main(int argc,char * argv[])142 int main(int argc, char *argv[])
143 {
144 int ret;
145
146 if (argc > 1)
147 return 0;
148
149 ret = test_pipes();
150 if (ret) {
151 fprintf(stderr, "test_pipe failed\n");
152 return ret;
153 }
154
155 ret = test_eventfd();
156 if (ret) {
157 fprintf(stderr, "test_eventfd failed\n");
158 return ret;
159 }
160
161 return 0;
162 }
163