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 : 274 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
83 : : {
84 : 274 : struct event_handler *ehdlr = NULL;
85 : 274 : struct epoll_event epevent = {0};
86 : : int rc;
87 : 274 : int ret = 0;
88 : :
89 [ + + # # : 575 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
90 [ # # # # ]: 301 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
91 [ - + ]: 301 : 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 [ # # ]: 301 : ret++;
105 : 0 : }
106 : :
107 : 274 : 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 : 274 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
134 : : {
135 : 274 : struct event_handler *ehdlr = NULL;
136 : 274 : struct epoll_event epevent = {0};
137 : : int rc;
138 : 274 : int ret = 0;
139 : :
140 : : /* Hoist the fds from the child up into the parent */
141 [ + + # # : 575 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
# # # # #
# # # #
# ]
142 [ # # # # ]: 301 : epevent.events = ehdlr->events;
143 [ # # ]: 301 : epevent.data.ptr = ehdlr;
144 [ # # # # ]: 301 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
145 [ - + ]: 301 : 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 [ # # ]: 301 : ret++;
157 : 0 : }
158 : :
159 : 274 : 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 : : int
183 : 140 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
184 : : {
185 : : int rc;
186 : :
187 [ + - - + ]: 140 : if (parent == NULL || child == NULL) {
188 : 0 : return -EINVAL;
189 : : }
190 : :
191 [ + + # # : 140 : if (child->parent != parent) {
# # ]
192 : 3 : return -EINVAL;
193 : : }
194 : :
195 [ # # # # ]: 137 : rc = _fd_group_del_all(parent->epfd, child);
196 [ - + ]: 137 : if (rc < 0) {
197 : 0 : return rc;
198 : : } else {
199 [ - + # # : 137 : assert(parent->num_fds >= (uint32_t)rc);
# # # # ]
200 [ # # # # ]: 137 : parent->num_fds -= rc;
201 : : }
202 : :
203 [ # # # # ]: 137 : child->parent = NULL;
204 [ - + # # : 137 : TAILQ_REMOVE(&parent->children, child, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
205 : :
206 [ # # # # ]: 137 : rc = _fd_group_add_all(child->epfd, child);
207 [ - + ]: 137 : if (rc < 0) {
208 : 0 : return rc;
209 : : } else {
210 [ # # # # ]: 137 : child->num_fds += rc;
211 : : }
212 : :
213 : 137 : return 0;
214 : 0 : }
215 : :
216 : : int
217 : 137 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
218 : : {
219 : : int rc;
220 : :
221 [ + - - + ]: 137 : if (parent == NULL || child == NULL) {
222 : 0 : return -EINVAL;
223 : : }
224 : :
225 [ - + # # : 137 : if (child->parent) {
# # ]
226 : 0 : return -EINVAL;
227 : : }
228 : :
229 [ - + # # : 137 : if (parent->parent) {
# # ]
230 : : /* More than one layer of nesting is currently not supported */
231 [ # # ]: 0 : assert(false);
232 : : return -ENOTSUP;
233 : : }
234 : :
235 [ # # # # ]: 137 : rc = _fd_group_del_all(child->epfd, child);
236 [ - + ]: 137 : if (rc < 0) {
237 : 0 : return rc;
238 : : } else {
239 [ - + # # : 137 : assert(child->num_fds >= (uint32_t)rc);
# # # # ]
240 [ # # # # ]: 137 : child->num_fds -= rc;
241 : : }
242 : :
243 [ # # # # ]: 137 : rc = _fd_group_add_all(parent->epfd, child);
244 [ - + ]: 137 : if (rc < 0) {
245 : 0 : return rc;
246 : : } else {
247 [ # # # # ]: 137 : parent->num_fds += rc;
248 : : }
249 : :
250 [ # # # # ]: 137 : child->parent = parent;
251 [ # # # # : 137 : TAILQ_INSERT_TAIL(&parent->children, child, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
252 : :
253 : 137 : return 0;
254 : 0 : }
255 : :
256 : : void
257 : 18138 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
258 : : size_t opts_size)
259 : : {
260 [ + + ]: 18138 : if (!opts) {
261 : 0 : SPDK_ERRLOG("opts should not be NULL\n");
262 : 0 : return;
263 : : }
264 : :
265 [ + + ]: 18138 : if (!opts_size) {
266 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
267 : 0 : return;
268 : : }
269 : :
270 [ + + ]: 18138 : memset(opts, 0, opts_size);
271 [ + - + - ]: 18138 : opts->opts_size = opts_size;
272 : :
273 : : #define FIELD_OK(field) \
274 : : offsetof(struct spdk_event_handler_opts, field) + sizeof(opts->field) <= opts_size
275 : :
276 : : #define SET_FIELD(field, value) \
277 : : if (FIELD_OK(field)) { \
278 : : opts->field = value; \
279 : : } \
280 : :
281 [ + + + - : 18138 : SET_FIELD(events, EPOLLIN);
+ - ]
282 [ + + + - : 18138 : SET_FIELD(fd_type, SPDK_FD_TYPE_DEFAULT);
+ - ]
283 : :
284 : : #undef FIELD_OK
285 : : #undef SET_FIELD
286 : 332 : }
287 : :
288 : : static void
289 : 9069 : event_handler_opts_copy(const struct spdk_event_handler_opts *src,
290 : : struct spdk_event_handler_opts *dst)
291 : : {
292 [ + + + - : 9069 : if (!src->opts_size) {
+ - ]
293 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
294 [ # # ]: 0 : assert(false);
295 : : }
296 : :
297 : : #define FIELD_OK(field) \
298 : : offsetof(struct spdk_event_handler_opts, field) + sizeof(src->field) <= src->opts_size
299 : :
300 : : #define SET_FIELD(field) \
301 : : if (FIELD_OK(field)) { \
302 : : dst->field = src->field; \
303 : : } \
304 : :
305 [ + - + - : 9069 : SET_FIELD(events);
- + + - +
- + - +
- ]
306 [ + - + - : 9069 : SET_FIELD(fd_type);
- + + - +
- + - +
- ]
307 : :
308 [ + - + - : 9069 : dst->opts_size = src->opts_size;
+ - + - ]
309 : :
310 : : /* You should not remove this statement, but need to update the assert statement
311 : : * if you add a new field, and also add a corresponding SET_FIELD statement */
312 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_event_handler_opts) == 16, "Incorrect size");
313 : :
314 : : #undef FIELD_OK
315 : : #undef SET_FIELD
316 : 9069 : }
317 : :
318 : : int
319 : 7140 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
320 : : void *arg, const char *name)
321 : : {
322 : 7140 : return spdk_fd_group_add_for_events(fgrp, efd, EPOLLIN, fn, arg, name);
323 : : }
324 : :
325 : : int
326 : 7140 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events,
327 : : spdk_fd_fn fn, void *arg, const char *name)
328 : : {
329 : 7140 : struct spdk_event_handler_opts opts = {};
330 : :
331 : 7140 : spdk_fd_group_get_default_event_handler_opts(&opts, sizeof(opts));
332 [ + - ]: 7140 : opts.events = events;
333 [ + - ]: 7140 : opts.fd_type = SPDK_FD_TYPE_DEFAULT;
334 : :
335 : 7140 : return spdk_fd_group_add_ext(fgrp, efd, fn, arg, name, &opts);
336 : : }
337 : :
338 : : int
339 : 9069 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
340 : : const char *name, struct spdk_event_handler_opts *opts)
341 : : {
342 : 9069 : struct event_handler *ehdlr = NULL;
343 : 9069 : struct epoll_event epevent = {0};
344 : 9069 : struct spdk_event_handler_opts eh_opts = {};
345 : : int rc;
346 : : int epfd;
347 : :
348 : : /* parameter checking */
349 [ + - + - : 9069 : if (fgrp == NULL || efd < 0 || fn == NULL) {
- + ]
350 : 0 : return -EINVAL;
351 : : }
352 : :
353 : 9069 : spdk_fd_group_get_default_event_handler_opts(&eh_opts, sizeof(eh_opts));
354 [ + - ]: 9069 : if (opts) {
355 : 9069 : event_handler_opts_copy(opts, &eh_opts);
356 : 166 : }
357 : :
358 : : /* check if there is already one function registered for this fd */
359 [ + + + - : 21565 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + + +
- + - +
- ]
360 [ + + + - : 12496 : if (ehdlr->fd == efd) {
+ - ]
361 : 0 : return -EEXIST;
362 : : }
363 : 83 : }
364 : :
365 : : /* create a new event src */
366 : 9069 : ehdlr = calloc(1, sizeof(*ehdlr));
367 [ + + ]: 9069 : if (ehdlr == NULL) {
368 [ # # # # ]: 0 : return -errno;
369 : : }
370 : :
371 [ + - + - ]: 9069 : ehdlr->fd = efd;
372 [ + - + - ]: 9069 : ehdlr->fn = fn;
373 [ + - + - ]: 9069 : ehdlr->fn_arg = arg;
374 [ + - + - ]: 9069 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
375 [ + - + - : 9069 : ehdlr->events = eh_opts.events;
+ - ]
376 [ + - + - : 9069 : ehdlr->fd_type = eh_opts.fd_type;
+ - ]
377 [ + - ]: 9069 : snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
378 : :
379 [ + + + - : 9069 : if (fgrp->parent) {
- + ]
380 [ # # # # : 1928 : epfd = fgrp->parent->epfd;
# # # # ]
381 : 0 : } else {
382 [ + - + - ]: 7141 : epfd = fgrp->epfd;
383 : : }
384 : :
385 [ + - + - ]: 9069 : epevent.events = ehdlr->events;
386 [ + - ]: 9069 : epevent.data.ptr = ehdlr;
387 : 9069 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
388 [ + + ]: 9069 : if (rc < 0) {
389 [ # # ]: 0 : SPDK_ERRLOG("Failed to add fd: %d to fd group(%p): %s\n",
390 : : efd, fgrp, strerror(errno));
391 : 0 : free(ehdlr);
392 [ # # # # ]: 0 : return -errno;
393 : : }
394 : :
395 [ + - + - : 9069 : TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
396 [ + + + - : 9069 : if (fgrp->parent) {
- + ]
397 [ # # # # : 1928 : fgrp->parent->num_fds++;
# # ]
398 : 0 : } else {
399 [ - + ]: 7141 : fgrp->num_fds++;
400 : : }
401 : :
402 : 9069 : return 0;
403 : 166 : }
404 : :
405 : : void
406 : 9032 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
407 : : {
408 : : struct event_handler *ehdlr;
409 : : int rc;
410 : : int epfd;
411 : :
412 [ + - - + ]: 9032 : if (fgrp == NULL || efd < 0) {
413 : 0 : SPDK_ERRLOG("Cannot remove fd: %d from fd group(%p)\n", efd, fgrp);
414 [ # # ]: 0 : assert(0);
415 : : return;
416 : : }
417 : :
418 : :
419 [ + - + - : 20307 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
+ - + - +
- + - +
- ]
420 [ + + + - : 20307 : if (ehdlr->fd == efd) {
+ + ]
421 : 9032 : break;
422 : : }
423 : 83 : }
424 : :
425 [ + + ]: 9032 : if (ehdlr == NULL) {
426 : 0 : SPDK_ERRLOG("fd: %d doesn't exist in fd group(%p)\n", efd, fgrp);
427 : 0 : return;
428 : : }
429 : :
430 [ + + + - : 9032 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
+ - # # ]
431 : :
432 [ + + + - : 9032 : if (fgrp->parent) {
- + ]
433 [ # # # # : 1925 : epfd = fgrp->parent->epfd;
# # # # ]
434 : 0 : } else {
435 [ + - + - ]: 7107 : epfd = fgrp->epfd;
436 : : }
437 : :
438 [ + - + - ]: 9032 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
439 [ + + ]: 9032 : if (rc < 0) {
440 [ # # # # : 0 : SPDK_ERRLOG("Failed to remove fd: %d from fd group(%p): %s\n",
# # ]
441 : : ehdlr->fd, fgrp, strerror(errno));
442 : 0 : return;
443 : : }
444 : :
445 [ + + + - : 9032 : if (fgrp->parent) {
- + ]
446 [ - + # # : 1925 : assert(fgrp->parent->num_fds > 0);
# # # # #
# # # ]
447 [ # # # # : 1925 : fgrp->parent->num_fds--;
# # ]
448 : 0 : } else {
449 [ + + + - : 7107 : assert(fgrp->num_fds > 0);
+ - # # ]
450 [ + - ]: 7107 : fgrp->num_fds--;
451 : : }
452 [ + + + - : 9032 : TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
+ - - + #
# # # # #
# # # # #
# # # # #
# # + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
453 : :
454 : : /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
455 [ + + + - : 9032 : if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
- + ]
456 [ # # # # ]: 692 : ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
457 : 0 : } else {
458 : 8340 : free(ehdlr);
459 : : }
460 : 166 : }
461 : :
462 : : int
463 : 3 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
464 : : int efd, int event_types)
465 : : {
466 : 3 : struct epoll_event epevent;
467 : : struct event_handler *ehdlr;
468 : : int epfd;
469 : :
470 [ + - - + ]: 3 : if (fgrp == NULL || efd < 0) {
471 : 0 : return -EINVAL;
472 : : }
473 : :
474 [ + - # # : 3 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
# # # # #
# # # #
# ]
475 [ + - # # : 3 : if (ehdlr->fd == efd) {
# # ]
476 : 3 : break;
477 : : }
478 : 0 : }
479 : :
480 [ - + ]: 3 : if (ehdlr == NULL) {
481 : 0 : return -EINVAL;
482 : : }
483 : :
484 [ - + # # : 3 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
# # # # ]
485 : :
486 [ # # # # ]: 3 : ehdlr->events = event_types;
487 : :
488 [ - + # # : 3 : if (fgrp->parent) {
# # ]
489 [ # # # # : 0 : epfd = fgrp->parent->epfd;
# # # # ]
490 : 0 : } else {
491 [ # # # # ]: 3 : epfd = fgrp->epfd;
492 : : }
493 : :
494 [ # # # # ]: 3 : epevent.events = ehdlr->events;
495 [ # # ]: 3 : epevent.data.ptr = ehdlr;
496 : :
497 [ # # # # ]: 3 : return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
498 : 0 : }
499 : :
500 : : int
501 : 5886 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
502 : : {
503 : : struct spdk_fd_group *fgrp;
504 : :
505 [ + + ]: 5886 : if (_egrp == NULL) {
506 : 0 : return -EINVAL;
507 : : }
508 : :
509 : 5886 : fgrp = calloc(1, sizeof(*fgrp));
510 [ + + ]: 5886 : if (fgrp == NULL) {
511 : 0 : return -ENOMEM;
512 : : }
513 : :
514 : : /* init the event source head */
515 [ + - + - : 5886 : TAILQ_INIT(&fgrp->event_handlers);
+ - + - +
- + - + -
+ - ]
516 [ + - + - : 5886 : TAILQ_INIT(&fgrp->children);
+ - + - +
- + - + -
+ - ]
517 : :
518 [ + - + - ]: 5886 : fgrp->num_fds = 0;
519 [ + - + - ]: 5886 : fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
520 [ + + + - : 5886 : if (fgrp->epfd < 0) {
+ - ]
521 : 0 : free(fgrp);
522 [ # # # # ]: 0 : return -errno;
523 : : }
524 : :
525 [ + - ]: 5886 : *_egrp = fgrp;
526 : :
527 : 5886 : return 0;
528 : 84 : }
529 : :
530 : : void
531 : 5880 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
532 : : {
533 [ + - + + : 5880 : if (fgrp == NULL || fgrp->num_fds > 0) {
+ - ]
534 [ # # ]: 0 : if (!fgrp) {
535 : 0 : SPDK_ERRLOG("fd_group doesn't exist.\n");
536 : 0 : } else {
537 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot delete fd group(%p) as (%u) fds are still registered to it.\n",
538 : : fgrp, fgrp->num_fds);
539 : : }
540 [ # # ]: 0 : assert(0);
541 : : return;
542 : : }
543 : :
544 : : /* Check if someone tried to delete the fd group before unnesting it */
545 [ + + + - : 5880 : if (!TAILQ_EMPTY(&fgrp->event_handlers)) {
+ - + - ]
546 : 0 : SPDK_ERRLOG("Interrupt sources list not empty.\n");
547 [ # # ]: 0 : assert(0);
548 : : return;
549 : : }
550 : :
551 [ + + + - : 5880 : assert(fgrp->parent == NULL);
+ - # # ]
552 [ + + + - : 5880 : assert(TAILQ_EMPTY(&fgrp->children));
+ - + - #
# ]
553 [ + - + - ]: 5880 : close(fgrp->epfd);
554 : 5880 : free(fgrp);
555 : :
556 : 5880 : return;
557 : : }
558 : :
559 : : int
560 : 132333142 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
561 : 132328828 : {
562 [ + - + - ]: 132333142 : uint32_t totalfds = fgrp->num_fds;
563 [ + + ]: 132333142 : struct epoll_event events[totalfds];
564 : : struct event_handler *ehdlr;
565 : 32602 : uint64_t count;
566 : : int n;
567 : : int nfds;
568 : : int bytes_read;
569 : : int read_errno;
570 : :
571 [ + + + - : 132333142 : if (fgrp->parent != NULL) {
- + ]
572 [ # # ]: 0 : if (timeout < 0) {
573 : 0 : SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
574 [ # # ]: 0 : assert(false);
575 : : return -EINVAL;
576 : : } else {
577 : 0 : SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events.\n");
578 : 0 : return 0;
579 : : }
580 : : }
581 : :
582 [ + + + - : 132333142 : nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
+ - ]
583 [ + + ]: 132333136 : if (nfds < 0) {
584 [ - + # # ]: 16 : if (errno != EINTR) {
585 [ # # ]: 0 : SPDK_ERRLOG("fd group(%p) epoll_wait failed: %s\n",
586 : : fgrp, strerror(errno));
587 : 0 : }
588 : :
589 [ # # # # ]: 16 : return -errno;
590 [ + + ]: 132333120 : } else if (nfds == 0) {
591 : 578 : return 0;
592 : : }
593 : :
594 [ + + + - ]: 360478850 : for (n = 0; n < nfds; n++) {
595 : : /* find the event_handler */
596 [ + - + - : 228146308 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
597 : :
598 [ + + ]: 228146308 : if (ehdlr == NULL) {
599 : 0 : continue;
600 : : }
601 : :
602 : : /* Tag ehdlr as running state in case that it is removed
603 : : * during this wait loop but before or when it get executed.
604 : : */
605 [ + + + - : 228146308 : assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
+ - # # ]
606 [ + - + - ]: 228146308 : ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
607 : 4317 : }
608 : :
609 [ + + + - ]: 360478850 : for (n = 0; n < nfds; n++) {
610 : : /* find the event_handler */
611 [ + - + - : 228146308 : ehdlr = events[n].data.ptr;
+ - + - +
- ]
612 : :
613 [ + - + + : 228146308 : if (ehdlr == NULL || ehdlr->fn == NULL) {
+ - - + ]
614 : 0 : continue;
615 : : }
616 : :
617 : : /* It is possible that the ehdlr was removed
618 : : * during this wait loop but before it get executed.
619 : : */
620 [ + + + - : 228146308 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
621 : 21 : free(ehdlr);
622 : 21 : continue;
623 : : }
624 : :
625 [ + - + - ]: 228146287 : g_event = &events[n];
626 : :
627 : : /* read fd to reset the internal eventfd object counter value to 0 */
628 [ + + + - : 228146287 : if (ehdlr->fd_type == SPDK_FD_TYPE_EVENTFD) {
+ - ]
629 [ # # # # ]: 157582 : bytes_read = read(ehdlr->fd, &count, sizeof(count));
630 [ - + ]: 157582 : if (bytes_read < 0) {
631 : 0 : g_event = NULL;
632 [ # # # # : 0 : if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
# # # # #
# # # ]
633 : 0 : continue;
634 : : }
635 [ # # ]: 0 : read_errno = errno;
636 : : /* TODO: Device is buggy. Handle this properly */
637 [ # # # # : 0 : SPDK_ERRLOG("Failed to read fd (%d) %s\n",
# # ]
638 : : ehdlr->fd, strerror(errno));
639 [ # # ]: 0 : return -read_errno;
640 [ - + ]: 157582 : } else if (bytes_read == 0) {
641 [ # # # # ]: 0 : SPDK_ERRLOG("Read nothing from fd (%d)\n", ehdlr->fd);
642 : 0 : g_event = NULL;
643 : 0 : return -EINVAL;
644 : : }
645 : 0 : }
646 : :
647 : : /* call the interrupt response function */
648 [ + - + - : 228146287 : ehdlr->fn(ehdlr->fn_arg);
- + + - +
- + - ]
649 : 228146287 : g_event = NULL;
650 : :
651 : : /* It is possible that the ehdlr was removed
652 : : * during this wait loop when it get executed.
653 : : */
654 [ + + + - : 228146287 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
- + ]
655 : 671 : free(ehdlr);
656 : 0 : } else {
657 [ + - + - ]: 228145616 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
658 : : }
659 : 4317 : }
660 : :
661 : 132332542 : return nfds;
662 : 4314 : }
663 : :
664 : : #else /* !__linux__ */
665 : :
666 : : int
667 : 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
668 : : {
669 : 0 : return -ENOTSUP;
670 : : }
671 : :
672 : : int
673 : 0 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
674 : : void *arg, const char *name)
675 : : {
676 : 0 : return -ENOTSUP;
677 : : }
678 : :
679 : : int
680 : 0 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events, spdk_fd_fn fn,
681 : : void *arg, const char *name)
682 : : {
683 : 0 : return -ENOTSUP;
684 : : }
685 : :
686 : : int
687 : 0 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
688 : : const char *name, struct spdk_event_handler_opts *opts)
689 : : {
690 : 0 : return -ENOTSUP;
691 : : }
692 : :
693 : : void
694 : 0 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
695 : : size_t opts_size)
696 : : {
697 : 0 : assert(false);
698 : : }
699 : :
700 : : void
701 : 0 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
702 : : {
703 : 0 : }
704 : :
705 : : int
706 : 0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
707 : : int efd, int event_types)
708 : : {
709 : 0 : return -ENOTSUP;
710 : : }
711 : :
712 : : int
713 : 30 : spdk_fd_group_create(struct spdk_fd_group **fgrp)
714 : : {
715 : 30 : return -ENOTSUP;
716 : : }
717 : :
718 : : void
719 : 0 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
720 : : {
721 : 0 : }
722 : :
723 : : int
724 : 0 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
725 : : {
726 : 0 : return -ENOTSUP;
727 : : }
728 : :
729 : : int
730 : 0 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
731 : : {
732 : 0 : return -ENOTSUP;
733 : : }
734 : :
735 : : int
736 : 0 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
737 : : {
738 : 0 : return -ENOTSUP;
739 : : }
740 : :
741 : : #endif /* __linux__ */
|