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