eal/windows: cleanup interrupt resources
[dpdk.git] / lib / eal / windows / eal_interrupts.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  */
4
5 #include <rte_interrupts.h>
6
7 #include "eal_private.h"
8 #include "eal_windows.h"
9
10 #define IOCP_KEY_SHUTDOWN UINT32_MAX
11
12 static pthread_t intr_thread;
13
14 static HANDLE intr_iocp;
15 static HANDLE intr_thread_handle;
16
17 static void
18 eal_intr_process(const OVERLAPPED_ENTRY *event)
19 {
20         RTE_SET_USED(event);
21 }
22
23 static int
24 eal_intr_thread_handle_init(void)
25 {
26         DWORD thread_id = GetCurrentThreadId();
27
28         intr_thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
29         if (intr_thread_handle == NULL) {
30                 RTE_LOG_WIN32_ERR("OpenThread(%lu)", thread_id);
31                 return -1;
32         }
33         return 0;
34 }
35
36 static void *
37 eal_intr_thread_main(LPVOID arg __rte_unused)
38 {
39         bool finished = false;
40
41         if (eal_intr_thread_handle_init() < 0) {
42                 RTE_LOG(ERR, EAL, "Cannot open interrupt thread handle\n");
43                 goto cleanup;
44         }
45
46         while (!finished) {
47                 OVERLAPPED_ENTRY events[16];
48                 ULONG event_count, i;
49                 BOOL result;
50
51                 result = GetQueuedCompletionStatusEx(
52                         intr_iocp, events, RTE_DIM(events), &event_count,
53                         INFINITE, /* no timeout */
54                         TRUE);    /* alertable wait for alarm APCs */
55
56                 if (!result) {
57                         DWORD error = GetLastError();
58                         if (error != WAIT_IO_COMPLETION) {
59                                 RTE_LOG_WIN32_ERR("GetQueuedCompletionStatusEx()");
60                                 RTE_LOG(ERR, EAL, "Failed waiting for interrupts\n");
61                                 break;
62                         }
63
64                         /* No I/O events, all work is done in completed APCs. */
65                         continue;
66                 }
67
68                 for (i = 0; i < event_count; i++) {
69                         if (events[i].lpCompletionKey == IOCP_KEY_SHUTDOWN) {
70                                 finished = true;
71                                 break;
72                         }
73                         eal_intr_process(&events[i]);
74                 }
75         }
76
77         CloseHandle(intr_thread_handle);
78         intr_thread_handle = NULL;
79
80 cleanup:
81         intr_thread = 0;
82
83         CloseHandle(intr_iocp);
84         intr_iocp = NULL;
85
86         return NULL;
87 }
88
89 int
90 rte_eal_intr_init(void)
91 {
92         int ret = 0;
93
94         intr_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
95         if (intr_iocp == NULL) {
96                 RTE_LOG_WIN32_ERR("CreateIoCompletionPort()");
97                 RTE_LOG(ERR, EAL, "Cannot create interrupt IOCP\n");
98                 return -1;
99         }
100
101         ret = rte_ctrl_thread_create(&intr_thread, "eal-intr-thread", NULL,
102                         eal_intr_thread_main, NULL);
103         if (ret != 0) {
104                 rte_errno = -ret;
105                 RTE_LOG(ERR, EAL, "Cannot create interrupt thread\n");
106         }
107
108         return ret;
109 }
110
111 int
112 rte_thread_is_intr(void)
113 {
114         return pthread_equal(intr_thread, pthread_self());
115 }
116
117 int
118 rte_intr_rx_ctl(__rte_unused struct rte_intr_handle *intr_handle,
119                 __rte_unused int epfd, __rte_unused int op,
120                 __rte_unused unsigned int vec, __rte_unused void *data)
121 {
122         return -ENOTSUP;
123 }
124
125 int
126 eal_intr_thread_schedule(void (*func)(void *arg), void *arg)
127 {
128         if (!QueueUserAPC((PAPCFUNC)(ULONG_PTR)func,
129                         intr_thread_handle, (ULONG_PTR)arg)) {
130                 RTE_LOG_WIN32_ERR("QueueUserAPC()");
131                 return -EINVAL;
132         }
133
134         return 0;
135 }
136
137 void
138 eal_intr_thread_cancel(void)
139 {
140         if (!PostQueuedCompletionStatus(
141                         intr_iocp, 0, IOCP_KEY_SHUTDOWN, NULL)) {
142                 RTE_LOG_WIN32_ERR("PostQueuedCompletionStatus()");
143                 RTE_LOG(ERR, EAL, "Cannot cancel interrupt thread\n");
144                 return;
145         }
146
147         WaitForSingleObject(intr_thread_handle, INFINITE);
148 }
149
150 int
151 rte_intr_callback_register(
152         __rte_unused const struct rte_intr_handle *intr_handle,
153         __rte_unused rte_intr_callback_fn cb, __rte_unused void *cb_arg)
154 {
155         return -ENOTSUP;
156 }
157
158 int
159 rte_intr_callback_unregister_pending(
160         __rte_unused const struct rte_intr_handle *intr_handle,
161         __rte_unused rte_intr_callback_fn cb_fn, __rte_unused void *cb_arg,
162         __rte_unused rte_intr_unregister_callback_fn ucb_fn)
163 {
164         return -ENOTSUP;
165 }
166
167 int
168 rte_intr_callback_unregister(
169         __rte_unused const struct rte_intr_handle *intr_handle,
170         __rte_unused rte_intr_callback_fn cb_fn, __rte_unused void *cb_arg)
171 {
172         return 0;
173 }
174
175 int
176 rte_intr_callback_unregister_sync(
177         __rte_unused const struct rte_intr_handle *intr_handle,
178         __rte_unused rte_intr_callback_fn cb_fn, __rte_unused void *cb_arg)
179 {
180         return 0;
181 }
182
183 int
184 rte_intr_enable(__rte_unused const struct rte_intr_handle *intr_handle)
185 {
186         return -ENOTSUP;
187 }
188
189 int
190 rte_intr_ack(__rte_unused const struct rte_intr_handle *intr_handle)
191 {
192         return -ENOTSUP;
193 }
194
195 int
196 rte_intr_disable(__rte_unused const struct rte_intr_handle *intr_handle)
197 {
198         return -ENOTSUP;
199 }
200
201 int
202 rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
203 {
204         RTE_SET_USED(intr_handle);
205         RTE_SET_USED(nb_efd);
206
207         return 0;
208 }
209
210 void
211 rte_intr_efd_disable(struct rte_intr_handle *intr_handle)
212 {
213         RTE_SET_USED(intr_handle);
214 }
215
216 int
217 rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
218 {
219         RTE_SET_USED(intr_handle);
220
221         return 0;
222 }
223
224 int
225 rte_intr_allow_others(struct rte_intr_handle *intr_handle)
226 {
227         RTE_SET_USED(intr_handle);
228
229         return 1;
230 }
231
232 int
233 rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
234 {
235         RTE_SET_USED(intr_handle);
236
237         return 0;
238 }
239
240 int
241 rte_epoll_wait(int epfd, struct rte_epoll_event *events,
242                 int maxevents, int timeout)
243 {
244         RTE_SET_USED(epfd);
245         RTE_SET_USED(events);
246         RTE_SET_USED(maxevents);
247         RTE_SET_USED(timeout);
248
249         return -ENOTSUP;
250 }
251
252 int
253 rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events,
254                              int maxevents, int timeout)
255 {
256         RTE_SET_USED(epfd);
257         RTE_SET_USED(events);
258         RTE_SET_USED(maxevents);
259         RTE_SET_USED(timeout);
260
261         return -ENOTSUP;
262 }
263
264 int
265 rte_epoll_ctl(int epfd, int op, int fd, struct rte_epoll_event *event)
266 {
267         RTE_SET_USED(epfd);
268         RTE_SET_USED(op);
269         RTE_SET_USED(fd);
270         RTE_SET_USED(event);
271
272         return -ENOTSUP;
273 }
274
275 int
276 rte_intr_tls_epfd(void)
277 {
278         return -ENOTSUP;
279 }
280
281 void
282 rte_intr_free_epoll_fd(struct rte_intr_handle *intr_handle)
283 {
284         RTE_SET_USED(intr_handle);
285 }