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