/* io-epoll.c - epoll(7) based file descriptor monitoring * * Copyright (C) 2009 Timo Teräs * All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 or later as * published by the Free Software Foundation. * * See http://www.gnu.org/ for details. */ #include #include #include #include #include #include #define TF_FD_AUTOCLOSE 1 #define TF_FD_RESTORE_BLOCKING 2 #define TF_FD_STREAM_ORIENTED 4 static int tf_fd_init(struct tf_fd *fd, int kfd, int flags) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; struct epoll_event ev; int r; ev.events = EPOLLIN | EPOLLOUT | EPOLLET; ev.data.ptr = fd; r = epoll_ctl(pd->epoll_fd, EPOLL_CTL_ADD, kfd, &ev); if (r < 0) { TF_BUG_ON(errno == EEXIST); return -errno; } fd->fd = kfd; fd->flags = flags; fd->waiting_fiber = NULL; return 0; } static void tf_fd_wait(struct tf_fd *fd, int events) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; TF_BUG_ON(fd->waiting_fiber != NULL); fd->events = events | EPOLLERR | EPOLLHUP; fd->waiting_fiber = tf_get_fiber(); pd->num_waiters++; } static void tf_fd_release(struct tf_fd *fd) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; fd->waiting_fiber = NULL; fd->events = 0; pd->num_waiters--; } void tf_poll_init(void) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; pd->epoll_fd = epoll_create1(EPOLL_CLOEXEC); pd->num_waiters = 0; TF_BUG_ON(pd->epoll_fd < 0); } int tf_poll(tf_mtime_diff_t timeout) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; struct epoll_event events[64]; struct tf_fd *fd; int ret = (timeout == 0) ? TF_WAKEUP_TIMEOUT : TF_WAKEUP_FD; int r, i; if (timeout == 0 && pd->num_waiters == 0) return ret; do { r = epoll_wait(pd->epoll_fd, events, array_size(events), timeout); for (i = 0; i < r; i++) { fd = (struct tf_fd *) events[i].data.ptr; if (likely(fd->events & events[i].events)) tf_wakeup(fd->waiting_fiber, TF_WAKEUP_FD); } if (timeout != 0) ret = TF_WAKEUP_FD; timeout = 0; } while (unlikely(r == array_size(events))); return ret; } void tf_poll_close(void) { struct tf_poll_data *pd = &tf_get_scheduler()->poll_data; close(pd->epoll_fd); } #include "io-unix.c"