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 char name[SPDK_MAX_EVENT_NAME_LEN + 1]; 45 }; 46 47 struct spdk_fd_group { 48 int epfd; 49 int num_fds; /* Number of fds registered in this group. */ 50 51 /* interrupt sources list */ 52 TAILQ_HEAD(, event_handler) event_handlers; 53 }; 54 55 int 56 spdk_fd_group_get_fd(struct spdk_fd_group *fgrp) 57 { 58 return fgrp->epfd; 59 } 60 61 #ifdef __linux__ 62 63 static __thread struct epoll_event *g_event = NULL; 64 65 int 66 spdk_fd_group_get_epoll_event(struct epoll_event *event) 67 { 68 if (g_event == NULL) { 69 return -EINVAL; 70 } 71 *event = *g_event; 72 return 0; 73 } 74 75 int 76 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, 77 void *arg, const char *name) 78 { 79 struct event_handler *ehdlr = NULL; 80 struct epoll_event epevent = {0}; 81 int rc; 82 83 /* parameter checking */ 84 if (fgrp == NULL || efd < 0 || fn == NULL) { 85 return -EINVAL; 86 } 87 88 /* check if there is already one function registered for this fd */ 89 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 90 if (ehdlr->fd == efd) { 91 return -EEXIST; 92 } 93 } 94 95 /* create a new event src */ 96 ehdlr = calloc(1, sizeof(*ehdlr)); 97 if (ehdlr == NULL) { 98 return -errno; 99 } 100 101 ehdlr->fd = efd; 102 ehdlr->fn = fn; 103 ehdlr->fn_arg = arg; 104 ehdlr->state = EVENT_HANDLER_STATE_WAITING; 105 snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name); 106 107 epevent.events = EPOLLIN; 108 epevent.data.ptr = ehdlr; 109 rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_ADD, efd, &epevent); 110 if (rc < 0) { 111 free(ehdlr); 112 return -errno; 113 } 114 115 TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next); 116 fgrp->num_fds++; 117 118 return 0; 119 } 120 121 void 122 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd) 123 { 124 struct event_handler *ehdlr; 125 int rc; 126 127 if (fgrp == NULL || efd < 0) { 128 SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp); 129 assert(0); 130 return; 131 } 132 133 134 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 135 if (ehdlr->fd == efd) { 136 break; 137 } 138 } 139 140 if (ehdlr == NULL) { 141 SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp); 142 return; 143 } 144 145 assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED); 146 147 rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL); 148 if (rc < 0) { 149 SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp); 150 return; 151 } 152 153 assert(fgrp->num_fds > 0); 154 fgrp->num_fds--; 155 TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next); 156 157 /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */ 158 if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) { 159 ehdlr->state = EVENT_HANDLER_STATE_REMOVED; 160 } else { 161 free(ehdlr); 162 } 163 } 164 165 int 166 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp, 167 int efd, int event_types) 168 { 169 struct epoll_event epevent; 170 struct event_handler *ehdlr; 171 172 if (fgrp == NULL || efd < 0) { 173 return -EINVAL; 174 } 175 176 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 177 if (ehdlr->fd == efd) { 178 break; 179 } 180 } 181 182 if (ehdlr == NULL) { 183 return -EINVAL; 184 } 185 186 assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED); 187 188 epevent.events = event_types; 189 epevent.data.ptr = ehdlr; 190 191 return epoll_ctl(fgrp->epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent); 192 } 193 194 int 195 spdk_fd_group_create(struct spdk_fd_group **_egrp) 196 { 197 struct spdk_fd_group *fgrp; 198 199 if (_egrp == NULL) { 200 return -EINVAL; 201 } 202 203 fgrp = calloc(1, sizeof(*fgrp)); 204 if (fgrp == NULL) { 205 return -ENOMEM; 206 } 207 208 /* init the event source head */ 209 TAILQ_INIT(&fgrp->event_handlers); 210 211 fgrp->num_fds = 0; 212 fgrp->epfd = epoll_create1(EPOLL_CLOEXEC); 213 if (fgrp->epfd < 0) { 214 free(fgrp); 215 return -errno; 216 } 217 218 *_egrp = fgrp; 219 220 return 0; 221 } 222 223 void 224 spdk_fd_group_destroy(struct spdk_fd_group *fgrp) 225 { 226 if (fgrp == NULL || fgrp->num_fds > 0) { 227 SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp); 228 assert(0); 229 return; 230 } 231 232 close(fgrp->epfd); 233 free(fgrp); 234 235 return; 236 } 237 238 int 239 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout) 240 { 241 int totalfds = fgrp->num_fds; 242 struct epoll_event events[totalfds]; 243 struct event_handler *ehdlr; 244 int n; 245 int nfds; 246 247 nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout); 248 if (nfds < 0) { 249 if (errno != EINTR) { 250 SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno); 251 } 252 253 return -errno; 254 } else if (nfds == 0) { 255 return 0; 256 } 257 258 for (n = 0; n < nfds; n++) { 259 /* find the event_handler */ 260 ehdlr = events[n].data.ptr; 261 262 if (ehdlr == NULL) { 263 continue; 264 } 265 266 /* Tag ehdlr as running state in case that it is removed 267 * during this wait loop but before or when it get executed. 268 */ 269 assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING); 270 ehdlr->state = EVENT_HANDLER_STATE_RUNNING; 271 } 272 273 for (n = 0; n < nfds; n++) { 274 /* find the event_handler */ 275 ehdlr = events[n].data.ptr; 276 277 if (ehdlr == NULL || ehdlr->fn == NULL) { 278 continue; 279 } 280 281 /* It is possible that the ehdlr was removed 282 * during this wait loop but before it get executed. 283 */ 284 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) { 285 free(ehdlr); 286 continue; 287 } 288 289 SPDK_DTRACE_PROBE4(interrupt_fd_process, ehdlr->name, ehdlr->fd, 290 ehdlr->fn, ehdlr->fn_arg); 291 292 g_event = &events[n]; 293 /* call the interrupt response function */ 294 ehdlr->fn(ehdlr->fn_arg); 295 g_event = NULL; 296 297 /* It is possible that the ehdlr was removed 298 * during this wait loop when it get executed. 299 */ 300 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) { 301 free(ehdlr); 302 } else { 303 ehdlr->state = EVENT_HANDLER_STATE_WAITING; 304 } 305 } 306 307 return nfds; 308 } 309 310 #else 311 312 int 313 spdk_fd_group_get_epoll_event(struct epoll_event *event) 314 { 315 return -ENOTSUP; 316 } 317 318 int 319 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, 320 void *arg, const char *name) 321 { 322 return -ENOTSUP; 323 } 324 325 void 326 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd) 327 { 328 } 329 330 int 331 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp, 332 int efd, int event_types) 333 { 334 return -ENOTSUP; 335 } 336 337 int 338 spdk_fd_group_create(struct spdk_fd_group **fgrp) 339 { 340 return -ENOTSUP; 341 } 342 343 void 344 spdk_fd_group_destroy(struct spdk_fd_group *fgrp) 345 { 346 } 347 348 int 349 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout) 350 { 351 return -ENOTSUP; 352 } 353 354 #endif 355