int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) { struct fdtab_entry *mye = fdtab_get(epfd); assert(mye->type == FDTAB_TYPE_EPOLL_INSTANCE); struct _epoll_fd *efd = mye->handle; struct monitor_binding *mb = get_monitor_binding(); errval_t err; /* waitset_init(&efd->ws); */ assert(maxevents >= 1); for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) { struct fdtab_entry *e = fdtab_get(i->fd); struct epoll_event *event = &i->event; switch (e->type) { case FDTAB_TYPE_LWIP_SOCKET: { int retval; lwip_mutex_lock(); if(event->events & EPOLLIN) { retval = lwip_sock_waitset_register_read(e->fd, &efd->ws); assert(retval == 0); } if(event->events & EPOLLOUT) { retval = lwip_sock_waitset_register_write(e->fd, &efd->ws); assert(retval == 0); } lwip_mutex_unlock(); } break; case FDTAB_TYPE_UNIX_SOCKET: { struct _unix_socket *us = e->handle; if(event->events & EPOLLIN) { if (us->passive) { /* passive side */ int j; /* Check for pending connection requests. */ for (j = 0; j < us->u.passive.max_backlog; j++) { if (us->u.passive.backlog[j] != NULL) { break; } } /* * If there are not pending connection request * wait on monitor binding. */ if (j == us->u.passive.max_backlog) { /* wait on monitor */ err = mb->change_waitset(mb, &efd->ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "change_waitset"); } } } } if(event->events & EPOLLOUT) { assert(!us->passive); if(us->u.active.mode == _UNIX_SOCKET_MODE_CONNECTING) { /* wait on monitor */ err = mb->change_waitset(mb, &efd->ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "change_waitset"); } } } assert(event->events & (EPOLLIN | EPOLLOUT)); // Change waitset err = us->u.active.binding->change_waitset (us->u.active.binding, &efd->ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "change waitset"); } } break; default: { fprintf(stderr, "change waitset on FD type %d NYI.\n", e->type); assert(!"NYI"); errno = EBADF; return -1; } } } // Timeout handling struct timeout_event toe = { .fired = false }; struct deferred_event timeout_event; if (timeout > 0) { deferred_event_init(&timeout_event); err = deferred_event_register(&timeout_event, &efd->ws, timeout, MKCLOSURE(timeout_fired, &toe)); if (err_is_fail(err)) { errno = EINVAL; return -1; } } int retevents = 0; while(!toe.fired && retevents == 0) { if(timeout == 0) { // Just poll once, don't block err = event_dispatch_non_block(&efd->ws); assert(err_is_ok(err) || err_no(err) == LIB_ERR_NO_EVENT); toe.fired = true; } else { err = event_dispatch(&efd->ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Error in event_dispatch."); } } // Return ready file descriptors for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) { struct epoll_event *event = &i->event; struct fdtab_entry *e = fdtab_get(i->fd); assert(retevents < maxevents); events[retevents] = *event; events[retevents].events = 0; // Check errors (hangup) { switch (e->type) { case FDTAB_TYPE_LWIP_SOCKET: { lwip_mutex_lock(); if (!lwip_sock_is_open(e->fd)) { events[retevents].events |= EPOLLHUP; } lwip_mutex_unlock(); } break; default: // No-Op break; } } // Check readable FDs if(event->events & EPOLLIN) { switch (e->type) { case FDTAB_TYPE_LWIP_SOCKET: { lwip_mutex_lock(); if (lwip_sock_ready_read(e->fd)) { events[retevents].events |= EPOLLIN; } lwip_mutex_unlock(); } break; case FDTAB_TYPE_UNIX_SOCKET: { struct _unix_socket *us = e->handle; if (us->passive) { /* passive side */ /* Check for pending connection requests. */ for (int j = 0; j < us->u.passive.max_backlog; j++) { if (us->u.passive.backlog[j] != NULL) { events[retevents].events |= EPOLLIN; break; } } } else { /* active side */ /* Check for incoming data. */ if (us->recv_buf_valid > 0) { events[retevents].events |= EPOLLIN; } } } break; default: { fprintf(stderr, "epoll_wait() on FD type %d NYI.\n", e->type); assert(!"NYI"); errno = EBADF; return -1; } } } // Check writeable FDs if(event->events & EPOLLOUT) { switch (e->type) { case FDTAB_TYPE_LWIP_SOCKET: { lwip_mutex_lock(); if (lwip_sock_ready_write(e->fd)) { events[retevents].events |= EPOLLOUT; } lwip_mutex_unlock(); } break; case FDTAB_TYPE_UNIX_SOCKET: { struct _unix_socket *us = e->handle; assert(!us->passive); switch (us->u.active.mode) { case _UNIX_SOCKET_MODE_CONNECTING: break; case _UNIX_SOCKET_MODE_CONNECTED: if (us->send_buf == NULL) { events[retevents].events |= EPOLLOUT; } break; } } break; default: { fprintf(stderr, "epoll_wait() on FD type %d NYI.\n", e->type); assert(!"NYI"); errno = EBADF; return -1; } } } // If any events were returned, go to next entry in array if(events[retevents].events != 0) { retevents++; } } } // Remove timeout from waitset if it was set and not fired if(timeout > 0 && !toe.fired) { deferred_event_cancel(&timeout_event); } // Restore old waitsets for(struct _epoll_events_list *i = efd->events; i != NULL; i = i->next) { struct fdtab_entry *e = fdtab_get(i->fd); struct epoll_event *event = &i->event; switch (e->type) { case FDTAB_TYPE_LWIP_SOCKET: { lwip_mutex_lock(); if(event->events & EPOLLIN) { err = lwip_sock_waitset_deregister_read(e->fd); if (err_is_fail(err) && err_no(err) != LIB_ERR_CHAN_NOT_REGISTERED) { USER_PANIC_ERR(err, "error deregister read channel for " "lwip socket"); } } if(event->events & EPOLLOUT) { err = lwip_sock_waitset_deregister_write(e->fd); if (err_is_fail(err) && err_no(err) != LIB_ERR_CHAN_NOT_REGISTERED) { USER_PANIC_ERR(err, "error deregister write channel for " "lwip socket"); } } lwip_mutex_unlock(); } break; case FDTAB_TYPE_UNIX_SOCKET: { // NYI } break; default: { fprintf(stderr, "change waitset on FD type %d NYI.\n", e->type); assert(!"NYI"); errno = EBADF; return -1; } } } return retevents; } int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask) { assert(!"NYI"); }
/// Cancel a periodic event errval_t periodic_event_cancel(struct periodic_event *event) { return deferred_event_cancel(&event->de); }