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 : : #include "spdk/util.h"
12 : :
13 : : #include "spdk/fd_group.h"
14 : :
15 : : #define SPDK_MAX_EVENT_NAME_LEN 256
16 : :
17 : : enum event_handler_state {
18 : : /* The event_handler is added into an fd_group waiting for event,
19 : : * but not currently in the execution of a wait loop.
20 : : */
21 : : EVENT_HANDLER_STATE_WAITING,
22 : :
23 : : /* The event_handler is currently in the execution of a wait loop. */
24 : : EVENT_HANDLER_STATE_RUNNING,
25 : :
26 : : /* The event_handler was removed during the execution of a wait loop. */
27 : : EVENT_HANDLER_STATE_REMOVED,
28 : : };
29 : :
30 : : /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
31 : : struct event_handler {
32 : : TAILQ_ENTRY(event_handler) next;
33 : : enum event_handler_state state;
34 : :
35 : : spdk_fd_fn fn;
36 : : void *fn_arg;
37 : : /* file descriptor of the interrupt event */
38 : : int fd;
39 : : uint32_t events;
40 : : uint32_t fd_type;
41 : : char name[SPDK_MAX_EVENT_NAME_LEN + 1];
42 : : };
43 : :
44 : : struct spdk_fd_group {
45 : : int epfd;
46 : :
47 : : /* Number of fds registered in this group. The epoll file descriptor of this fd group
48 : : * i.e. epfd waits for interrupt event on all the fds from its interrupt sources list, as
49 : : * well as from all its children fd group interrupt sources list.
50 : : */
51 : : uint32_t num_fds;
52 : :
53 : : struct spdk_fd_group *parent;
54 : :
55 : : /* interrupt sources list */
56 : : TAILQ_HEAD(, event_handler) event_handlers;
57 : : TAILQ_HEAD(, spdk_fd_group) children;
58 : : TAILQ_ENTRY(spdk_fd_group) link;
59 : : };
60 : :
61 : : int
62 : 2 : spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
63 : : {
64 [ # # # # ]: 2 : return fgrp->epfd;
65 : : }
66 : :
67 : : #ifdef __linux__
68 : :
69 : : static __thread struct epoll_event *g_event = NULL;
70 : :
71 : : int
72 : 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
73 : : {
74 [ # # ]: 0 : if (g_event == NULL) {
75 : 0 : return -EINVAL;
76 : : }
77 : 0 : *event = *g_event;
78 : 0 : return 0;
79 : 0 : }
80 : :
81 : : static int
82 : 199 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
83 : : {
84 : 199 : struct event_handler *ehdlr = NULL;
85 : 199 : struct epoll_event epevent = {0};
86 : : int rc;
87 : 199 : int ret = 0;
88 : :
89 [ + + # # : 473 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
90 [ # # # # ]: 274 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
91 [ - + ]: 274 : if (rc < 0) {
92 [ # # # # ]: 0 : if (errno == ENOENT) {
93 : : /* This is treated as success. It happens if there are multiple
94 : : * attempts to remove fds from the group.
95 : : */
96 : 0 : continue;
97 : : }
98 : :
99 [ # # # # ]: 0 : ret = -errno;
100 [ # # # # : 0 : SPDK_ERRLOG("Failed to remove fd: %d from group: %s\n",
# # ]
101 : : ehdlr->fd, strerror(errno));
102 : 0 : goto recover;
103 : : }
104 [ # # ]: 274 : ret++;
105 : 0 : }
106 : :
107 : 199 : return ret;
108 : :
109 : 0 : recover:
110 : : /* We failed to remove everything. Let's try to put everything back into
111 : : * the original group. */
112 [ # # # # : 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
113 [ # # # # ]: 0 : epevent.events = ehdlr->events;
114 [ # # ]: 0 : epevent.data.ptr = ehdlr;
115 [ # # # # ]: 0 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
116 [ # # ]: 0 : if (rc < 0) {
117 [ # # # # ]: 0 : if (errno == EEXIST) {
118 : : /* This is fine. Keep going. */
119 : 0 : continue;
120 : : }
121 : :
122 : : /* Continue on even though we've failed. But indicate
123 : : * this is a fatal error. */
124 [ # # ]: 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
125 : 0 : ret = -ENOTRECOVERABLE;
126 : 0 : }
127 : 0 : }
128 : :
129 : 0 : return ret;
130 : 0 : }
131 : :
132 : : static int
133 : 199 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
134 : : {
135 : 199 : struct event_handler *ehdlr = NULL;
136 : 199 : struct epoll_event epevent = {0};
137 : : int rc;
138 : 199 : int ret = 0;
139 : :
140 : : /* Hoist the fds from the child up into the parent */
141 [ + + # # : 473 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
142 [ # # # # ]: 274 : epevent.events = ehdlr->events;
143 [ # # ]: 274 : epevent.data.ptr = ehdlr;
144 [ # # # # ]: 274 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
145 [ - + ]: 274 : if (rc < 0) {
146 [ # # # # ]: 0 : if (errno == EEXIST) {
147 : : /* This is treated as success */
148 : 0 : continue;
149 : : }
150 : :
151 [ # # # # ]: 0 : ret = -errno;
152 [ # # # # : 0 : SPDK_ERRLOG("Failed to add fd: %d to fd group: %s\n",
# # ]
153 : : ehdlr->fd, strerror(errno));
154 : 0 : goto recover;
155 : : }
156 [ # # ]: 274 : ret++;
157 : 0 : }
158 : :
159 : 199 : return ret;
160 : :
161 : 0 : recover:
162 : : /* We failed to add everything, so try to remove what we did add. */
163 [ # # # # : 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
164 [ # # # # ]: 0 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
165 [ # # ]: 0 : if (rc < 0) {
166 [ # # # # ]: 0 : if (errno == ENOENT) {
167 : : /* This is treated as success. */
168 : 0 : continue;
169 : : }
170 : :
171 : :
172 : : /* Continue on even though we've failed. But indicate
173 : : * this is a fatal error. */
174 [ # # ]: 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
175 : 0 : ret = -ENOTRECOVERABLE;
176 : 0 : }
177 : 0 : }
178 : :
179 : 0 : return ret;
180 : 0 : }
181 : :
182 : : static struct spdk_fd_group *
183 : 14472 : fd_group_get_root(struct spdk_fd_group *fgrp)
184 : : {
185 [ + + + - : 16157 : while (fgrp->parent != NULL) {
- + ]
186 [ # # # # ]: 1685 : fgrp = fgrp->parent;
187 : : }
188 : :
189 : 14472 : return fgrp;
190 : : }
191 : :
192 : : static int
193 : 199 : fd_group_change_parent(struct spdk_fd_group *fgrp, struct spdk_fd_group *old,
194 : : struct spdk_fd_group *new)
195 : : {
196 : : struct spdk_fd_group *child, *tmp;
197 : : int rc, ret;
198 : :
199 [ + + # # : 208 : TAILQ_FOREACH(child, &fgrp->children, link) {
# # # # #
# # # #
# ]
200 : 9 : ret = fd_group_change_parent(child, old, new);
201 [ - + ]: 9 : if (ret != 0) {
202 : 0 : goto recover_children;
203 : : }
204 : 0 : }
205 : :
206 [ # # # # ]: 199 : ret = _fd_group_del_all(old->epfd, fgrp);
207 [ - + ]: 199 : if (ret < 0) {
208 : 0 : goto recover_children;
209 : : }
210 : :
211 [ - + # # : 199 : assert(old->num_fds >= (uint32_t)ret);
# # # # ]
212 [ # # # # ]: 199 : old->num_fds -= ret;
213 : :
214 [ # # # # ]: 199 : ret = _fd_group_add_all(new->epfd, fgrp);
215 [ - + ]: 199 : if (ret < 0) {
216 : 0 : goto recover_epfd;
217 : : }
218 : :
219 [ # # # # ]: 199 : new->num_fds += ret;
220 : 199 : return 0;
221 : :
222 : 0 : recover_epfd:
223 [ # # ]: 0 : if (ret == -ENOTRECOVERABLE) {
224 : 0 : goto recover_children;
225 : : }
226 [ # # # # ]: 0 : rc = _fd_group_add_all(old->epfd, fgrp);
227 [ # # ]: 0 : if (rc >= 0) {
228 [ # # # # ]: 0 : old->num_fds += rc;
229 : 0 : } else {
230 : 0 : SPDK_ERRLOG("Failed to recover epfd\n");
231 : 0 : ret = -ENOTRECOVERABLE;
232 : : }
233 : 0 : recover_children:
234 [ # # # # : 0 : TAILQ_FOREACH(tmp, &fgrp->children, link) {
# # # # #
# # # #
# ]
235 [ # # ]: 0 : if (tmp == child) {
236 : 0 : break;
237 : : }
238 : 0 : rc = fd_group_change_parent(tmp, new, old);
239 [ # # ]: 0 : if (rc != 0) {
240 : 0 : SPDK_ERRLOG("Failed to recover fd_group_change_parent\n");
241 : 0 : ret = -ENOTRECOVERABLE;
242 : 0 : }
243 : 0 : }
244 : 0 : return ret;
245 : 0 : }
246 : :
247 : : int
248 : 98 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
249 : : {
250 : : struct spdk_fd_group *root;
251 : : int rc;
252 : :
253 [ + - - + ]: 98 : if (parent == NULL || child == NULL) {
254 : 0 : return -EINVAL;
255 : : }
256 : :
257 [ + + # # : 98 : if (child->parent != parent) {
# # ]
258 : 3 : return -EINVAL;
259 : : }
260 : :
261 : 95 : root = fd_group_get_root(parent);
262 [ + + - + : 95 : assert(root == parent || parent->num_fds == 0);
# # # # #
# ]
263 : :
264 : 95 : rc = fd_group_change_parent(child, root, child);
265 [ - + ]: 95 : if (rc != 0) {
266 : 0 : return rc;
267 : : }
268 : :
269 [ # # # # ]: 95 : child->parent = NULL;
270 [ - + # # : 95 : TAILQ_REMOVE(&parent->children, child, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
271 : :
272 : 95 : return 0;
273 : 0 : }
274 : :
275 : : int
276 : 95 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
277 : : {
278 : : struct spdk_fd_group *root;
279 : : int rc;
280 : :
281 [ + - - + ]: 95 : if (parent == NULL || child == NULL) {
282 : 0 : return -EINVAL;
283 : : }
284 : :
285 [ - + # # : 95 : if (child->parent) {
# # ]
286 : 0 : return -EINVAL;
287 : : }
288 : :
289 : : /* The epoll instance at the root holds all fds, so either the parent is the root or it
290 : : * doesn't hold any fds.
291 : : */
292 : 95 : root = fd_group_get_root(parent);
293 [ - + - - : 95 : assert(root == parent || parent->num_fds == 0);
# # # # #
# ]
294 : :
295 : 95 : rc = fd_group_change_parent(child, child, root);
296 [ - + ]: 95 : if (rc != 0) {
297 : 0 : return rc;
298 : : }
299 : :
300 [ # # # # ]: 95 : child->parent = parent;
301 [ # # # # : 95 : TAILQ_INSERT_TAIL(&parent->children, child, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
302 : :
303 : 95 : return 0;
304 : 0 : }
305 : :
306 : : void
307 : 14312 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
308 : : size_t opts_size)
309 : : {
310 [ + + ]: 14312 : if (!opts) {
311 : 0 : SPDK_ERRLOG("opts should not be NULL\n");
312 : 0 : return;
313 : : }
314 : :
315 [ + + ]: 14312 : if (!opts_size) {
316 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
317 : 0 : return;
318 : : }
319 : :
320 [ + + ]: 14312 : memset(opts, 0, opts_size);
321 [ + - + - ]: 14312 : opts->opts_size = opts_size;
322 : :
323 : : #define FIELD_OK(field) \
324 : : offsetof(struct spdk_event_handler_opts, field) + sizeof(opts->field) <= opts_size
325 : :
326 : : #define SET_FIELD(field, value) \
327 : : if (FIELD_OK(field)) { \
328 : : opts->field = value; \
329 : : } \
330 : :
331 [ + + + - : 14312 : SET_FIELD(events, EPOLLIN);
+ - ]
332 [ + + + - : 14312 : SET_FIELD(fd_type, SPDK_FD_TYPE_DEFAULT);
+ - ]
333 : :
334 : : #undef FIELD_OK
335 : : #undef SET_FIELD
336 : 332 : }
337 : :
338 : : static void
339 : 7156 : event_handler_opts_copy(const struct spdk_event_handler_opts *src,
340 : : struct spdk_event_handler_opts *dst)
341 : : {
342 [ + + + - : 7156 : if (!src->opts_size) {
+ - ]
343 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
344 [ # # ]: 0 : assert(false);
345 : : }
346 : :
347 : : #define FIELD_OK(field) \
348 : : offsetof(struct spdk_event_handler_opts, field) + sizeof(src->field) <= src->opts_size
349 : :
350 : : #define SET_FIELD(field) \
351 : : if (FIELD_OK(field)) { \
352 : : dst->field = src->field; \
353 : : } \
354 : :
355 [ + - + - : 7156 : SET_FIELD(events);
- + + - +
- + - +
- ]
356 [ + - + - : 7156 : SET_FIELD(fd_type);
- + + - +
- + - +
- ]
357 : :
358 [ + - + - : 7156 : dst->opts_size = src->opts_size;
+ - + - ]
359 : :
360 : : /* You should not remove this statement, but need to update the assert statement
361 : : * if you add a new field, and also add a corresponding SET_FIELD statement */
362 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_event_handler_opts) == 16, "Incorrect size");
363 : :
364 : : #undef FIELD_OK
365 : : #undef SET_FIELD
366 : 7156 : }
367 : :
368 : : int
369 : 6317 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
370 : : void *arg, const char *name)
371 : : {
372 : 6317 : return spdk_fd_group_add_for_events(fgrp, efd, EPOLLIN, fn, arg, name);
373 : : }
374 : :
375 : : int
376 : 6317 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events,
377 : : spdk_fd_fn fn, void *arg, const char *name)
378 : : {
379 : 6317 : struct spdk_event_handler_opts opts = {};
380 : :
381 : 6317 : spdk_fd_group_get_default_event_handler_opts(&opts, sizeof(opts));
382 [ + - ]: 6317 : opts.events = events;
383 [ + - ]: 6317 : opts.fd_type = SPDK_FD_TYPE_DEFAULT;
384 : :
385 : 6317 : return spdk_fd_group_add_ext(fgrp, efd, fn, arg, name, &opts);
386 : : }
387 : :
388 : : int
389 : 7156 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
390 : : const char *name, struct spdk_event_handler_opts *opts)
391 : : {
392 : 7156 : struct event_handler *ehdlr = NULL;
393 : 7156 : struct epoll_event epevent = {0};
394 : 7156 : struct spdk_event_handler_opts eh_opts = {};
395 : : struct spdk_fd_group *root;
396 : : int rc;
397 : :
398 : : /* parameter checking */
399 [ + - + - : 7156 : if (fgrp == NULL || efd < 0 || fn == NULL) {
- + ]
400 : 0 : return -EINVAL;
401 : : }
402 : :
403 : 7156 : spdk_fd_group_get_default_event_handler_opts(&eh_opts, sizeof(eh_opts));
404 [ + - ]: 7156 : if (opts) {
405 : 7156 : event_handler_opts_copy(opts, &eh_opts);
406 : 166 : }
407 : :
408 : : /* check if there is already one function registered for this fd */
409 [ + + + - : 13809 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + + +
- + - +
- ]
410 [ + + + - : 6653 : if (ehdlr->fd == efd) {
+ - ]
411 : 0 : return -EEXIST;
412 : : }
413 : 83 : }
414 : :
415 : : /* create a new event src */
416 : 7156 : ehdlr = calloc(1, sizeof(*ehdlr));
417 [ + + ]: 7156 : if (ehdlr == NULL) {
418 [ # # # # ]: 0 : return -errno;
419 : : }
420 : :
421 [ + - + - ]: 7156 : ehdlr->fd = efd;
422 [ + - + - ]: 7156 : ehdlr->fn = fn;
423 [ + - + - ]: 7156 : ehdlr->fn_arg = arg;
424 [ + - + - ]: 7156 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
425 [ + - + - : 7156 : ehdlr->events = eh_opts.events;
+ - ]
426 [ + - + - : 7156 : ehdlr->fd_type = eh_opts.fd_type;
+ - ]
427 [ + - ]: 7156 : snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
428 : :
429 : 7156 : root = fd_group_get_root(fgrp);
430 [ + - + - ]: 7156 : epevent.events = ehdlr->events;
431 [ + - ]: 7156 : epevent.data.ptr = ehdlr;
432 [ + - + - ]: 7156 : rc = epoll_ctl(root->epfd, EPOLL_CTL_ADD, efd, &epevent);
433 [ + + ]: 7156 : if (rc < 0) {
434 [ # # ]: 0 : SPDK_ERRLOG("Failed to add fd: %d to fd group(%p): %s\n",
435 : : efd, fgrp, strerror(errno));
436 : 0 : free(ehdlr);
437 [ # # # # ]: 0 : return -errno;
438 : : }
439 : :
440 [ + - + - : 7156 : TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
441 [ + - ]: 7156 : root->num_fds++;
442 : :
443 : 7156 : return 0;
444 : 166 : }
445 : :
446 : : void
447 : 7123 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
448 : : {
449 : : struct event_handler *ehdlr;
450 : : struct spdk_fd_group *root;
451 : : int rc;
452 : :
453 [ + - - + ]: 7123 : if (fgrp == NULL || efd < 0) {
454 : 0 : SPDK_ERRLOG("Cannot remove fd: %d from fd group(%p)\n", efd, fgrp);
455 [ # # ]: 0 : assert(0);
456 : : return;
457 : : }
458 : :
459 : :
460 [ + - + - : 13113 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + - +
- + - +
- ]
461 [ + + + - : 13113 : if (ehdlr->fd == efd) {
+ + ]
462 : 7123 : break;
463 : : }
464 : 83 : }
465 : :
466 [ + + ]: 7123 : if (ehdlr == NULL) {
467 : 0 : SPDK_ERRLOG("fd: %d doesn't exist in fd group(%p)\n", efd, fgrp);
468 : 0 : return;
469 : : }
470 : :
471 [ + + + - : 7123 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
+ - # # ]
472 : 7123 : root = fd_group_get_root(fgrp);
473 : :
474 [ + - + - : 7123 : rc = epoll_ctl(root->epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
+ - + - ]
475 [ + + ]: 7123 : if (rc < 0) {
476 [ # # # # : 0 : SPDK_ERRLOG("Failed to remove fd: %d from fd group(%p): %s\n",
# # ]
477 : : ehdlr->fd, fgrp, strerror(errno));
478 : 0 : return;
479 : : }
480 : :
481 [ + + + - : 7123 : assert(root->num_fds > 0);
+ - # # ]
482 [ + - ]: 7123 : root->num_fds--;
483 [ + + + - : 7123 : TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
484 : :
485 : : /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
486 [ + + + - : 7123 : if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
- + ]
487 [ # # # # ]: 179 : ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
488 : 0 : } else {
489 : 6944 : free(ehdlr);
490 : : }
491 : 166 : }
492 : :
493 : : int
494 : 3 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
495 : : int efd, int event_types)
496 : : {
497 : 3 : struct epoll_event epevent;
498 : : struct event_handler *ehdlr;
499 : :
500 [ + - - + ]: 3 : if (fgrp == NULL || efd < 0) {
501 : 0 : return -EINVAL;
502 : : }
503 : :
504 [ + - # # : 3 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
# # # # #
# # # #
# ]
505 [ + - # # : 3 : if (ehdlr->fd == efd) {
# # ]
506 : 3 : break;
507 : : }
508 : 0 : }
509 : :
510 [ - + ]: 3 : if (ehdlr == NULL) {
511 : 0 : return -EINVAL;
512 : : }
513 : :
514 [ - + # # : 3 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
# # # # ]
515 : :
516 [ # # # # ]: 3 : ehdlr->events = event_types;
517 : :
518 [ # # # # ]: 3 : epevent.events = ehdlr->events;
519 [ # # ]: 3 : epevent.data.ptr = ehdlr;
520 : :
521 [ # # # # : 3 : return epoll_ctl(fd_group_get_root(fgrp)->epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
# # # # ]
522 : 0 : }
523 : :
524 : : int
525 : 5056 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
526 : : {
527 : : struct spdk_fd_group *fgrp;
528 : :
529 [ + + ]: 5056 : if (_egrp == NULL) {
530 : 0 : return -EINVAL;
531 : : }
532 : :
533 : 5056 : fgrp = calloc(1, sizeof(*fgrp));
534 [ + + ]: 5056 : if (fgrp == NULL) {
535 : 0 : return -ENOMEM;
536 : : }
537 : :
538 : : /* init the event source head */
539 [ + - + - : 5056 : TAILQ_INIT(&fgrp->event_handlers);
+ - + - +
- + - + -
+ - ]
540 [ + - + - : 5056 : TAILQ_INIT(&fgrp->children);
+ - + - +
- + - + -
+ - ]
541 : :
542 [ + - + - ]: 5056 : fgrp->num_fds = 0;
543 [ + - + - ]: 5056 : fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
544 [ + + + - : 5056 : if (fgrp->epfd < 0) {
+ - ]
545 : 0 : free(fgrp);
546 [ # # # # ]: 0 : return -errno;
547 : : }
548 : :
549 [ + - ]: 5056 : *_egrp = fgrp;
550 : :
551 : 5056 : return 0;
552 : 85 : }
553 : :
554 : : void
555 : 5050 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
556 : : {
557 [ + - + + : 5050 : if (fgrp == NULL || fgrp->num_fds > 0) {
+ - ]
558 [ # # ]: 0 : if (!fgrp) {
559 : 0 : SPDK_ERRLOG("fd_group doesn't exist.\n");
560 : 0 : } else {
561 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot delete fd group(%p) as (%u) fds are still registered to it.\n",
562 : : fgrp, fgrp->num_fds);
563 : : }
564 [ # # ]: 0 : assert(0);
565 : : return;
566 : : }
567 : :
568 : : /* Check if someone tried to delete the fd group before unnesting it */
569 [ + + + - : 5050 : if (!TAILQ_EMPTY(&fgrp->event_handlers)) {
+ - + - ]
570 : 0 : SPDK_ERRLOG("Interrupt sources list not empty.\n");
571 [ # # ]: 0 : assert(0);
572 : : return;
573 : : }
574 : :
575 [ + + + - : 5050 : assert(fgrp->parent == NULL);
+ - # # ]
576 [ + + + - : 5050 : assert(TAILQ_EMPTY(&fgrp->children));
+ - + - #
# ]
577 [ + - + - ]: 5050 : close(fgrp->epfd);
578 : 5050 : free(fgrp);
579 : :
580 : 5050 : return;
581 : : }
582 : :
583 : : int
584 : 70748763 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
585 : 70744221 : {
586 [ + - + - ]: 70748763 : uint32_t totalfds = fgrp->num_fds;
587 [ + + ]: 70748763 : struct epoll_event events[totalfds];
588 : : struct event_handler *ehdlr;
589 : 27580 : uint64_t count;
590 : : int n;
591 : : int nfds;
592 : : int bytes_read;
593 : : int read_errno;
594 : :
595 [ + + + - : 70748763 : if (fgrp->parent != NULL) {
- + ]
596 [ # # ]: 0 : if (timeout < 0) {
597 : 0 : SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
598 [ # # ]: 0 : assert(false);
599 : : return -EINVAL;
600 : : } else {
601 : 0 : SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events.\n");
602 : 0 : return 0;
603 : : }
604 : : }
605 : :
606 [ + + + - : 70748763 : nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
+ - ]
607 [ + + ]: 70748757 : if (nfds < 0) {
608 [ - + # # ]: 15 : if (errno != EINTR) {
609 [ # # ]: 0 : SPDK_ERRLOG("fd group(%p) epoll_wait failed: %s\n",
610 : : fgrp, strerror(errno));
611 : 0 : }
612 : :
613 [ # # # # ]: 15 : return -errno;
614 [ + + ]: 70748742 : } else if (nfds == 0) {
615 : 586 : return 0;
616 : : }
617 : :
618 [ + + + - ]: 192692044 : for (n = 0; n < nfds; n++) {
619 : : /* find the event_handler */
620 [ + - + - : 121943888 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
621 : :
622 [ + + ]: 121943888 : if (ehdlr == NULL) {
623 : 0 : continue;
624 : : }
625 : :
626 : : /* Tag ehdlr as running state in case that it is removed
627 : : * during this wait loop but before or when it get executed.
628 : : */
629 [ + + + - : 121943888 : assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
+ - # # ]
630 [ + - + - ]: 121943888 : ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
631 : 4545 : }
632 : :
633 [ + + + - ]: 192692044 : for (n = 0; n < nfds; n++) {
634 : : /* find the event_handler */
635 [ + - + - : 121943888 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
636 : :
637 [ + - + + : 121943888 : if (ehdlr == NULL || ehdlr->fn == NULL) {
+ - - + ]
638 : 0 : continue;
639 : : }
640 : :
641 : : /* It is possible that the ehdlr was removed
642 : : * during this wait loop but before it get executed.
643 : : */
644 [ + + + - : 121943888 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
645 : 13 : free(ehdlr);
646 : 13 : continue;
647 : : }
648 : :
649 [ + - + - ]: 121943875 : g_event = &events[n];
650 : :
651 : : /* read fd to reset the internal eventfd object counter value to 0 */
652 [ + + + - : 121943875 : if (ehdlr->fd_type == SPDK_FD_TYPE_EVENTFD) {
+ - ]
653 [ # # # # ]: 152732 : bytes_read = read(ehdlr->fd, &count, sizeof(count));
654 [ - + ]: 152732 : if (bytes_read < 0) {
655 : 0 : g_event = NULL;
656 [ # # # # : 0 : if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
# # # # #
# # # ]
657 : 0 : continue;
658 : : }
659 [ # # ]: 0 : read_errno = errno;
660 : : /* TODO: Device is buggy. Handle this properly */
661 [ # # # # : 0 : SPDK_ERRLOG("Failed to read fd (%d) %s\n",
# # ]
662 : : ehdlr->fd, strerror(errno));
663 [ # # ]: 0 : return -read_errno;
664 [ - + ]: 152732 : } else if (bytes_read == 0) {
665 [ # # # # ]: 0 : SPDK_ERRLOG("Read nothing from fd (%d)\n", ehdlr->fd);
666 : 0 : g_event = NULL;
667 : 0 : return -EINVAL;
668 : : }
669 : 0 : }
670 : :
671 : : /* call the interrupt response function */
672 [ + - + - : 121943875 : ehdlr->fn(ehdlr->fn_arg);
- + + - +
- + - ]
673 : 121943875 : g_event = NULL;
674 : :
675 : : /* It is possible that the ehdlr was removed
676 : : * during this wait loop when it get executed.
677 : : */
678 [ + + + - : 121943875 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
679 : 166 : free(ehdlr);
680 : 0 : } else {
681 [ + - + - ]: 121943709 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
682 : : }
683 : 4545 : }
684 : :
685 : 70748156 : return nfds;
686 : 4542 : }
687 : :
688 : : #else /* !__linux__ */
689 : :
690 : : int
691 : 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
692 : : {
693 : 0 : return -ENOTSUP;
694 : : }
695 : :
696 : : int
697 : 0 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
698 : : void *arg, const char *name)
699 : : {
700 : 0 : return -ENOTSUP;
701 : : }
702 : :
703 : : int
704 : 0 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events, spdk_fd_fn fn,
705 : : void *arg, const char *name)
706 : : {
707 : 0 : return -ENOTSUP;
708 : : }
709 : :
710 : : int
711 : 0 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
712 : : const char *name, struct spdk_event_handler_opts *opts)
713 : : {
714 : 0 : return -ENOTSUP;
715 : : }
716 : :
717 : : void
718 : 0 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
719 : : size_t opts_size)
720 : : {
721 : 0 : assert(false);
722 : : }
723 : :
724 : : void
725 : 0 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
726 : : {
727 : 0 : }
728 : :
729 : : int
730 : 0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
731 : : int efd, int event_types)
732 : : {
733 : 0 : return -ENOTSUP;
734 : : }
735 : :
736 : : int
737 : 30 : spdk_fd_group_create(struct spdk_fd_group **fgrp)
738 : : {
739 : 30 : return -ENOTSUP;
740 : : }
741 : :
742 : : void
743 : 0 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
744 : : {
745 : 0 : }
746 : :
747 : : int
748 : 0 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
749 : : {
750 : 0 : return -ENOTSUP;
751 : : }
752 : :
753 : : int
754 : 0 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
755 : : {
756 : 0 : return -ENOTSUP;
757 : : }
758 : :
759 : : int
760 : 0 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
761 : : {
762 : 0 : return -ENOTSUP;
763 : : }
764 : :
765 : : #endif /* __linux__ */
|