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