1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk_internal/usdt.h" 35 36 #include "spdk/env.h" 37 #include "spdk/log.h" 38 #include "spdk/queue.h" 39 40 #include "spdk/fd_group.h" 41 42 #ifdef __linux__ 43 #include <sys/epoll.h> 44 #endif 45 46 #define SPDK_MAX_EVENT_NAME_LEN 256 47 48 enum event_handler_state { 49 /* The event_handler is added into an fd_group waiting for event, 50 * but not currently in the execution of a wait loop. 51 */ 52 EVENT_HANDLER_STATE_WAITING, 53 54 /* The event_handler is currently in the execution of a wait loop. */ 55 EVENT_HANDLER_STATE_RUNNING, 56 57 /* The event_handler was removed during the execution of a wait loop. */ 58 EVENT_HANDLER_STATE_REMOVED, 59 }; 60 61 /* file descriptor of the interrupt event */ 62 63 /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */ 64 struct event_handler { 65 TAILQ_ENTRY(event_handler) next; 66 enum event_handler_state state; 67 68 spdk_fd_fn fn; 69 void *fn_arg; 70 /* file descriptor of the interrupt event */ 71 int fd; 72 char name[SPDK_MAX_EVENT_NAME_LEN + 1]; 73 }; 74 75 struct spdk_fd_group { 76 int epfd; 77 int num_fds; /* Number of fds registered in this group. */ 78 79 /* interrupt sources list */ 80 TAILQ_HEAD(, event_handler) event_handlers; 81 }; 82 83 int 84 spdk_fd_group_get_fd(struct spdk_fd_group *fgrp) 85 { 86 return fgrp->epfd; 87 } 88 89 #ifdef __linux__ 90 91 int 92 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, 93 void *arg, const char *name) 94 { 95 struct event_handler *ehdlr = NULL; 96 struct epoll_event epevent = {0}; 97 int rc; 98 99 /* parameter checking */ 100 if (fgrp == NULL || efd < 0 || fn == NULL) { 101 return -EINVAL; 102 } 103 104 /* check if there is already one function registered for this fd */ 105 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 106 if (ehdlr->fd == efd) { 107 return -EEXIST; 108 } 109 } 110 111 /* create a new event src */ 112 ehdlr = calloc(1, sizeof(*ehdlr)); 113 if (ehdlr == NULL) { 114 return -errno; 115 } 116 117 ehdlr->fd = efd; 118 ehdlr->fn = fn; 119 ehdlr->fn_arg = arg; 120 ehdlr->state = EVENT_HANDLER_STATE_WAITING; 121 snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name); 122 123 epevent.events = EPOLLIN; 124 epevent.data.ptr = ehdlr; 125 rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_ADD, efd, &epevent); 126 if (rc < 0) { 127 free(ehdlr); 128 return -errno; 129 } 130 131 TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next); 132 fgrp->num_fds++; 133 134 return 0; 135 } 136 137 void 138 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd) 139 { 140 struct event_handler *ehdlr; 141 int rc; 142 143 if (fgrp == NULL || efd < 0) { 144 SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp); 145 assert(0); 146 return; 147 } 148 149 150 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 151 if (ehdlr->fd == efd) { 152 break; 153 } 154 } 155 156 if (ehdlr == NULL) { 157 SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp); 158 return; 159 } 160 161 assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED); 162 163 rc = epoll_ctl(fgrp->epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL); 164 if (rc < 0) { 165 SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp); 166 return; 167 } 168 169 assert(fgrp->num_fds > 0); 170 fgrp->num_fds--; 171 TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next); 172 173 /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */ 174 if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) { 175 ehdlr->state = EVENT_HANDLER_STATE_REMOVED; 176 } else { 177 free(ehdlr); 178 } 179 } 180 181 int 182 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp, 183 int efd, int event_types) 184 { 185 struct epoll_event epevent; 186 struct event_handler *ehdlr; 187 188 if (fgrp == NULL || efd < 0) { 189 return -EINVAL; 190 } 191 192 TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) { 193 if (ehdlr->fd == efd) { 194 break; 195 } 196 } 197 198 if (ehdlr == NULL) { 199 return -EINVAL; 200 } 201 202 assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED); 203 204 epevent.events = event_types; 205 epevent.data.ptr = ehdlr; 206 207 return epoll_ctl(fgrp->epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent); 208 } 209 210 int 211 spdk_fd_group_create(struct spdk_fd_group **_egrp) 212 { 213 struct spdk_fd_group *fgrp; 214 215 if (_egrp == NULL) { 216 return -EINVAL; 217 } 218 219 fgrp = calloc(1, sizeof(*fgrp)); 220 if (fgrp == NULL) { 221 return -ENOMEM; 222 } 223 224 /* init the event source head */ 225 TAILQ_INIT(&fgrp->event_handlers); 226 227 fgrp->num_fds = 0; 228 fgrp->epfd = epoll_create1(EPOLL_CLOEXEC); 229 if (fgrp->epfd < 0) { 230 free(fgrp); 231 return -errno; 232 } 233 234 *_egrp = fgrp; 235 236 return 0; 237 } 238 239 void 240 spdk_fd_group_destroy(struct spdk_fd_group *fgrp) 241 { 242 if (fgrp == NULL || fgrp->num_fds > 0) { 243 SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp); 244 assert(0); 245 return; 246 } 247 248 close(fgrp->epfd); 249 free(fgrp); 250 251 return; 252 } 253 254 int 255 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout) 256 { 257 int totalfds = fgrp->num_fds; 258 struct epoll_event events[totalfds]; 259 struct event_handler *ehdlr; 260 int n; 261 int nfds; 262 263 nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout); 264 if (nfds < 0) { 265 if (errno != EINTR) { 266 SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno); 267 } 268 269 return -errno; 270 } else if (nfds == 0) { 271 return 0; 272 } 273 274 for (n = 0; n < nfds; n++) { 275 /* find the event_handler */ 276 ehdlr = events[n].data.ptr; 277 278 if (ehdlr == NULL) { 279 continue; 280 } 281 282 /* Tag ehdlr as running state in case that it is removed 283 * during this wait loop but before or when it get executed. 284 */ 285 assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING); 286 ehdlr->state = EVENT_HANDLER_STATE_RUNNING; 287 } 288 289 for (n = 0; n < nfds; n++) { 290 /* find the event_handler */ 291 ehdlr = events[n].data.ptr; 292 293 if (ehdlr == NULL || ehdlr->fn == NULL) { 294 continue; 295 } 296 297 /* It is possible that the ehdlr was removed 298 * during this wait loop but before it get executed. 299 */ 300 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) { 301 free(ehdlr); 302 continue; 303 } 304 305 SPDK_DTRACE_PROBE4(interrupt_fd_process, ehdlr->name, ehdlr->fd, 306 ehdlr->fn, ehdlr->fn_arg); 307 308 /* call the interrupt response function */ 309 ehdlr->fn(ehdlr->fn_arg); 310 311 /* It is possible that the ehdlr was removed 312 * during this wait loop when it get executed. 313 */ 314 if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) { 315 free(ehdlr); 316 } else { 317 ehdlr->state = EVENT_HANDLER_STATE_WAITING; 318 } 319 } 320 321 return nfds; 322 } 323 324 #else 325 326 int 327 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, 328 void *arg, const char *name) 329 { 330 return -ENOTSUP; 331 } 332 333 void 334 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd) 335 { 336 } 337 338 int 339 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp, 340 int efd, int event_types) 341 { 342 return -ENOTSUP; 343 } 344 345 int 346 spdk_fd_group_create(struct spdk_fd_group **fgrp) 347 { 348 return -ENOTSUP; 349 } 350 351 void 352 spdk_fd_group_destroy(struct spdk_fd_group *fgrp) 353 { 354 } 355 356 int 357 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout) 358 { 359 return -ENOTSUP; 360 } 361 362 #endif 363