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