Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation. All rights reserved.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk_internal/usdt.h"
7 : :
8 : : #include "spdk/env.h"
9 : : #include "spdk/log.h"
10 : : #include "spdk/queue.h"
11 : :
12 : : #include "spdk/fd_group.h"
13 : :
14 : : #ifdef __linux__
15 : : #include <sys/epoll.h>
16 : : #endif
17 : :
18 : : #define SPDK_MAX_EVENT_NAME_LEN 256
19 : :
20 : : enum event_handler_state {
21 : : /* The event_handler is added into an fd_group waiting for event,
22 : : * but not currently in the execution of a wait loop.
23 : : */
24 : : EVENT_HANDLER_STATE_WAITING,
25 : :
26 : : /* The event_handler is currently in the execution of a wait loop. */
27 : : EVENT_HANDLER_STATE_RUNNING,
28 : :
29 : : /* The event_handler was removed during the execution of a wait loop. */
30 : : EVENT_HANDLER_STATE_REMOVED,
31 : : };
32 : :
33 : : /* file descriptor of the interrupt event */
34 : :
35 : : /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
36 : : struct event_handler {
37 : : TAILQ_ENTRY(event_handler) next;
38 : : enum event_handler_state state;
39 : :
40 : : spdk_fd_fn fn;
41 : : void *fn_arg;
42 : : /* file descriptor of the interrupt event */
43 : : int fd;
44 : : uint32_t events;
45 : : char name[SPDK_MAX_EVENT_NAME_LEN + 1];
46 : : };
47 : :
48 : : struct spdk_fd_group {
49 : : int epfd;
50 : : int num_fds; /* Number of fds registered in this group. */
51 : :
52 : : struct spdk_fd_group *parent;
53 : :
54 : : /* interrupt sources list */
55 : : TAILQ_HEAD(, event_handler) event_handlers;
56 : : };
57 : :
58 : : int
59 : 0 : spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
60 : : {
61 [ # # # # ]: 0 : return fgrp->epfd;
62 : : }
63 : :
64 : : #ifdef __linux__
65 : :
66 : : static __thread struct epoll_event *g_event = NULL;
67 : :
68 : : int
69 : 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
70 : : {
71 [ # # ]: 0 : if (g_event == NULL) {
72 : 0 : return -EINVAL;
73 : : }
74 : 0 : *event = *g_event;
75 : 0 : return 0;
76 : 0 : }
77 : :
78 : : static int
79 : 264 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
80 : : {
81 : 264 : struct event_handler *ehdlr = NULL;
82 : 264 : struct epoll_event epevent = {0};
83 : : int rc;
84 : 264 : int ret = 0;
85 : :
86 [ + + # # : 552 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
87 [ # # # # ]: 288 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
88 [ - + ]: 288 : if (rc < 0) {
89 [ # # # # ]: 0 : if (errno == ENOENT) {
90 : : /* This is treated as success. It happens if there are multiple
91 : : * attempts to remove fds from the group.
92 : : */
93 : 0 : continue;
94 : : }
95 : :
96 [ # # # # ]: 0 : ret = -errno;
97 [ # # # # : 0 : SPDK_ERRLOG("Failed to remove fd %d from group: %s\n", ehdlr->fd, strerror(errno));
# # ]
98 : 0 : goto recover;
99 : : }
100 : 0 : }
101 : :
102 : 264 : return 0;
103 : :
104 : 0 : recover:
105 : : /* We failed to remove everything. Let's try to get everything put back into
106 : : * the original group. */
107 [ # # # # : 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
108 [ # # # # ]: 0 : epevent.events = ehdlr->events;
109 [ # # ]: 0 : epevent.data.ptr = ehdlr;
110 [ # # # # ]: 0 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
111 [ # # ]: 0 : if (rc < 0) {
112 [ # # # # ]: 0 : if (errno == EEXIST) {
113 : : /* This is fine. Keep going. */
114 : 0 : continue;
115 : : }
116 : :
117 : : /* Continue on even though we've failed. But indicate
118 : : * this is a fatal error. */
119 [ # # ]: 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
120 : 0 : ret = -ENOTRECOVERABLE;
121 : 0 : }
122 : 0 : }
123 : :
124 : 0 : return ret;
125 : 0 : }
126 : :
127 : : static int
128 : 264 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
129 : : {
130 : 264 : struct event_handler *ehdlr = NULL;
131 : 264 : struct epoll_event epevent = {0};
132 : : int rc;
133 : 264 : int ret = 0;
134 : :
135 : : /* Hoist the fds from the child up into the parent */
136 [ + + # # : 552 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
137 [ # # # # ]: 288 : epevent.events = ehdlr->events;
138 [ # # ]: 288 : epevent.data.ptr = ehdlr;
139 [ # # # # ]: 288 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
140 [ - + ]: 288 : if (rc < 0) {
141 [ # # # # ]: 0 : if (errno == EEXIST) {
142 : : /* This is treated as success */
143 : 0 : continue;
144 : : }
145 : :
146 [ # # # # ]: 0 : ret = -errno;
147 [ # # ]: 0 : SPDK_ERRLOG("Failed to add fd to fd group: %s\n", strerror(errno));
148 : 0 : goto recover;
149 : : }
150 : 0 : }
151 : :
152 : 264 : return 0;
153 : :
154 : 0 : recover:
155 : : /* We failed to add everything, so try to remove what we did add. */
156 [ # # # # : 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
157 [ # # # # ]: 0 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
158 [ # # ]: 0 : if (rc < 0) {
159 [ # # # # ]: 0 : if (errno == ENOENT) {
160 : : /* This is treated as success. */
161 : 0 : continue;
162 : : }
163 : :
164 : :
165 : : /* Continue on even though we've failed. But indicate
166 : : * this is a fatal error. */
167 [ # # ]: 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
168 : 0 : ret = -ENOTRECOVERABLE;
169 : 0 : }
170 : 0 : }
171 : :
172 : 0 : return ret;
173 : 0 : }
174 : :
175 : : int
176 : 132 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
177 : : {
178 : : int rc;
179 : :
180 [ + - - + ]: 132 : if (parent == NULL || child == NULL) {
181 : 0 : return -EINVAL;
182 : : }
183 : :
184 [ - + # # : 132 : if (child->parent != parent) {
# # ]
185 : 0 : return -EINVAL;
186 : : }
187 : :
188 [ # # # # ]: 132 : rc = _fd_group_del_all(parent->epfd, child);
189 [ - + ]: 132 : if (rc < 0) {
190 : 0 : return rc;
191 : : }
192 : :
193 [ # # # # ]: 132 : child->parent = NULL;
194 : :
195 [ # # # # ]: 132 : return _fd_group_add_all(child->epfd, child);
196 : 0 : }
197 : :
198 : : int
199 : 132 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
200 : : {
201 : : int rc;
202 : :
203 [ + - - + ]: 132 : if (parent == NULL || child == NULL) {
204 : 0 : return -EINVAL;
205 : : }
206 : :
207 [ - + # # : 132 : if (child->parent) {
# # ]
208 : 0 : return -EINVAL;
209 : : }
210 : :
211 [ - + # # : 132 : if (parent->parent) {
# # ]
212 : : /* More than one layer of nesting is not currently supported */
213 [ # # ]: 0 : assert(false);
214 : : return -ENOTSUP;
215 : : }
216 : :
217 [ # # # # ]: 132 : rc = _fd_group_del_all(child->epfd, child);
218 [ - + ]: 132 : if (rc < 0) {
219 : 0 : return rc;
220 : : }
221 : :
222 [ # # # # ]: 132 : child->parent = parent;
223 : :
224 [ # # # # ]: 132 : return _fd_group_add_all(parent->epfd, child);
225 : 0 : }
226 : :
227 : : int
228 : 7240 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
229 : : void *arg, const char *name)
230 : : {
231 : 7240 : return spdk_fd_group_add_for_events(fgrp, efd, EPOLLIN, fn, arg, name);
232 : : }
233 : :
234 : : int
235 : 9131 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events,
236 : : spdk_fd_fn fn, void *arg, const char *name)
237 : : {
238 : 9131 : struct event_handler *ehdlr = NULL;
239 : 9131 : struct epoll_event epevent = {0};
240 : : int rc;
241 : : int epfd;
242 : :
243 : : /* parameter checking */
244 [ + - + - : 9131 : if (fgrp == NULL || efd < 0 || fn == NULL) {
- + ]
245 : 0 : return -EINVAL;
246 : : }
247 : :
248 : : /* check if there is already one function registered for this fd */
249 [ + + + - : 21357 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + + +
- + - +
- ]
250 [ + + + - : 12226 : if (ehdlr->fd == efd) {
+ - ]
251 : 0 : return -EEXIST;
252 : : }
253 : 83 : }
254 : :
255 : : /* create a new event src */
256 : 9131 : ehdlr = calloc(1, sizeof(*ehdlr));
257 [ + + ]: 9131 : if (ehdlr == NULL) {
258 [ # # # # ]: 0 : return -errno;
259 : : }
260 : :
261 [ + - + - ]: 9131 : ehdlr->fd = efd;
262 [ + - + - ]: 9131 : ehdlr->fn = fn;
263 [ + - + - ]: 9131 : ehdlr->fn_arg = arg;
264 [ + - + - ]: 9131 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
265 [ + - + - ]: 9131 : ehdlr->events = events;
266 [ + - ]: 9131 : snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
267 : :
268 [ + + + - : 9131 : if (fgrp->parent) {
- + ]
269 [ # # # # : 1891 : epfd = fgrp->parent->epfd;
# # # # ]
270 : 0 : } else {
271 [ - + - + ]: 7240 : epfd = fgrp->epfd;
272 : : }
273 : :
274 [ + - + - ]: 9131 : epevent.events = ehdlr->events;
275 [ + - ]: 9131 : epevent.data.ptr = ehdlr;
276 : 9131 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
277 [ + + ]: 9131 : if (rc < 0) {
278 : 0 : free(ehdlr);
279 [ # # # # ]: 0 : return -errno;
280 : : }
281 : :
282 [ + - + - : 9131 : TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
283 [ + - + - ]: 9131 : fgrp->num_fds++;
284 : :
285 : 9131 : return 0;
286 : 166 : }
287 : :
288 : : void
289 : 9098 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
290 : : {
291 : : struct event_handler *ehdlr;
292 : : int rc;
293 : : int epfd;
294 : :
295 [ + - - + ]: 9098 : if (fgrp == NULL || efd < 0) {
296 : 0 : SPDK_ERRLOG("Invalid to remove efd(%d) from fd_group(%p).\n", efd, fgrp);
297 [ # # ]: 0 : assert(0);
298 : : return;
299 : : }
300 : :
301 : :
302 [ + - + - : 19865 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + - +
- + - +
- ]
303 [ + + + - : 19865 : if (ehdlr->fd == efd) {
+ + ]
304 : 9098 : break;
305 : : }
306 : 83 : }
307 : :
308 [ + + ]: 9098 : if (ehdlr == NULL) {
309 : 0 : SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
310 : 0 : return;
311 : : }
312 : :
313 [ + + + - : 9098 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
+ - # # ]
314 : :
315 [ + + + - : 9098 : if (fgrp->parent) {
- + ]
316 [ # # # # : 1891 : epfd = fgrp->parent->epfd;
# # # # ]
317 : 0 : } else {
318 [ + - + - ]: 7207 : epfd = fgrp->epfd;
319 : : }
320 : :
321 [ + - + - ]: 9098 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
322 [ + + ]: 9098 : if (rc < 0) {
323 : 0 : SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
324 : 0 : return;
325 : : }
326 : :
327 [ + + + - : 9098 : assert(fgrp->num_fds > 0);
+ - # # ]
328 [ + - + - ]: 9098 : fgrp->num_fds--;
329 [ + + + - : 9098 : TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
330 : :
331 : : /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
332 [ + + + - : 9098 : if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
- + ]
333 [ # # # # ]: 648 : ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
334 : 0 : } else {
335 : 8450 : free(ehdlr);
336 : : }
337 : 166 : }
338 : :
339 : : int
340 : 0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
341 : : int efd, int event_types)
342 : : {
343 : 0 : struct epoll_event epevent;
344 : : struct event_handler *ehdlr;
345 : : int epfd;
346 : :
347 [ # # # # ]: 0 : if (fgrp == NULL || efd < 0) {
348 : 0 : return -EINVAL;
349 : : }
350 : :
351 [ # # # # : 0 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
# # # # #
# # # #
# ]
352 [ # # # # : 0 : if (ehdlr->fd == efd) {
# # ]
353 : 0 : break;
354 : : }
355 : 0 : }
356 : :
357 [ # # ]: 0 : if (ehdlr == NULL) {
358 : 0 : return -EINVAL;
359 : : }
360 : :
361 [ # # # # : 0 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
# # # # ]
362 : :
363 [ # # # # ]: 0 : ehdlr->events = event_types;
364 : :
365 [ # # # # : 0 : if (fgrp->parent) {
# # ]
366 [ # # # # : 0 : epfd = fgrp->parent->epfd;
# # # # ]
367 : 0 : } else {
368 [ # # # # ]: 0 : epfd = fgrp->epfd;
369 : : }
370 : :
371 [ # # # # ]: 0 : epevent.events = ehdlr->events;
372 [ # # ]: 0 : epevent.data.ptr = ehdlr;
373 : :
374 [ # # # # ]: 0 : return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
375 : 0 : }
376 : :
377 : : int
378 : 3644 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
379 : : {
380 : : struct spdk_fd_group *fgrp;
381 : :
382 [ + + ]: 3644 : if (_egrp == NULL) {
383 : 0 : return -EINVAL;
384 : : }
385 : :
386 : 3644 : fgrp = calloc(1, sizeof(*fgrp));
387 [ + + ]: 3644 : if (fgrp == NULL) {
388 : 0 : return -ENOMEM;
389 : : }
390 : :
391 : : /* init the event source head */
392 [ + - + - : 3644 : TAILQ_INIT(&fgrp->event_handlers);
+ - + - +
- + - + -
+ - ]
393 : :
394 [ + - + - ]: 3644 : fgrp->num_fds = 0;
395 [ + - + - ]: 3644 : fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
396 [ + + + - : 3644 : if (fgrp->epfd < 0) {
+ - ]
397 : 0 : free(fgrp);
398 [ # # # # ]: 0 : return -errno;
399 : : }
400 : :
401 [ + - ]: 3644 : *_egrp = fgrp;
402 : :
403 : 3644 : return 0;
404 : 83 : }
405 : :
406 : : void
407 : 3638 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
408 : : {
409 [ + - + + : 3638 : if (fgrp == NULL || fgrp->num_fds > 0) {
+ - ]
410 : 0 : SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
411 [ # # ]: 0 : assert(0);
412 : : return;
413 : : }
414 : :
415 [ + - + - ]: 3638 : close(fgrp->epfd);
416 : 3638 : free(fgrp);
417 : :
418 : 3638 : return;
419 : : }
420 : :
421 : : int
422 : 152465778 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
423 : 152459255 : {
424 [ + - + - ]: 152465778 : int totalfds = fgrp->num_fds;
425 [ + + ]: 152465778 : struct epoll_event events[totalfds];
426 : : struct event_handler *ehdlr;
427 : : int n;
428 : : int nfds;
429 : :
430 [ + + + - : 152465778 : if (fgrp->parent != NULL) {
- + ]
431 [ # # ]: 0 : if (timeout < 0) {
432 : 0 : SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
433 [ # # ]: 0 : assert(false);
434 : : return -EINVAL;
435 : : } else {
436 : 0 : SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events\n");
437 : 0 : return 0;
438 : : }
439 : : }
440 : :
441 [ + + + - : 152465778 : nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
+ - ]
442 [ + + ]: 152465772 : if (nfds < 0) {
443 [ - + # # ]: 19 : if (errno != EINTR) {
444 [ # # ]: 0 : SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
445 : 0 : }
446 : :
447 [ # # # # ]: 19 : return -errno;
448 [ + + ]: 152465753 : } else if (nfds == 0) {
449 : 559 : return 0;
450 : : }
451 : :
452 [ + + + - ]: 383441018 : for (n = 0; n < nfds; n++) {
453 : : /* find the event_handler */
454 [ + - + - : 230975824 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
455 : :
456 [ + + ]: 230975824 : if (ehdlr == NULL) {
457 : 0 : continue;
458 : : }
459 : :
460 : : /* Tag ehdlr as running state in case that it is removed
461 : : * during this wait loop but before or when it get executed.
462 : : */
463 [ + + + - : 230975824 : assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
+ - # # ]
464 [ + - + - ]: 230975824 : ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
465 : 6526 : }
466 : :
467 [ + + + - ]: 383441018 : for (n = 0; n < nfds; n++) {
468 : : /* find the event_handler */
469 [ + - + - : 230975824 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
470 : :
471 [ + - + + : 230975824 : if (ehdlr == NULL || ehdlr->fn == NULL) {
+ - - + ]
472 : 0 : continue;
473 : : }
474 : :
475 : : /* It is possible that the ehdlr was removed
476 : : * during this wait loop but before it get executed.
477 : : */
478 [ + + + - : 230975824 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
479 : 122 : free(ehdlr);
480 : 122 : continue;
481 : : }
482 : :
483 [ + - + - ]: 230975702 : g_event = &events[n];
484 : : /* call the interrupt response function */
485 [ + - + - : 230975702 : ehdlr->fn(ehdlr->fn_arg);
- + + - +
- + - ]
486 : 230975702 : g_event = NULL;
487 : :
488 : : /* It is possible that the ehdlr was removed
489 : : * during this wait loop when it get executed.
490 : : */
491 [ + + + - : 230975702 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
492 : 526 : free(ehdlr);
493 : 0 : } else {
494 [ + - + - ]: 230975176 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
495 : : }
496 : 6526 : }
497 : :
498 : 152465194 : return nfds;
499 : 6523 : }
500 : :
501 : : #else
502 : :
503 : : int
504 : : spdk_fd_group_get_epoll_event(struct epoll_event *event)
505 : : {
506 : : return -ENOTSUP;
507 : : }
508 : :
509 : : int
510 : : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
511 : : void *arg, const char *name)
512 : : {
513 : : return -ENOTSUP;
514 : : }
515 : :
516 : : int
517 : : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events, spdk_fd_fn fn,
518 : : void *arg, const char *name)
519 : : {
520 : : return -ENOTSUP;
521 : : }
522 : :
523 : : void
524 : : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
525 : : {
526 : : }
527 : :
528 : : int
529 : : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
530 : : int efd, int event_types)
531 : : {
532 : : return -ENOTSUP;
533 : : }
534 : :
535 : : int
536 : : spdk_fd_group_create(struct spdk_fd_group **fgrp)
537 : : {
538 : : return -ENOTSUP;
539 : : }
540 : :
541 : : void
542 : : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
543 : : {
544 : : }
545 : :
546 : : int
547 : : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
548 : : {
549 : : return -ENOTSUP;
550 : : }
551 : :
552 : : int
553 : : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
554 : : {
555 : : return -ENOTSUP;
556 : : }
557 : :
558 : : int
559 : : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
560 : : {
561 : : return -ENOTSUP;
562 : : }
563 : :
564 : : #endif
|