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