diff --git a/fs/vfs/fs_epoll.c b/fs/vfs/fs_epoll.c index 0a74780c4a..b5085bfc0b 100644 --- a/fs/vfs/fs_epoll.c +++ b/fs/vfs/fs_epoll.c @@ -69,6 +69,12 @@ struct epoll_head_s * these epoll node should be setup again * to check the pending poll notification. */ + struct list_node oneshot; /* The oneshot list, store all the epoll + * node notified after epoll_wait and with + * EPOLLONESHOT events, these oneshot epoll + * nodes can be reset by epoll_ctl (Move + * from oneshot list to the setup list). + */ struct list_node free; /* The free list, store all the freed epoll * node. */ @@ -232,6 +238,7 @@ static int epoll_do_create(int size, int flags) list_initialize(&eph->setup); list_initialize(&eph->teardown); + list_initialize(&eph->oneshot); list_initialize(&eph->extend); list_initialize(&eph->free); for (i = 0; i < size; i++) @@ -307,7 +314,7 @@ static int epoll_teardown(FAR epoll_head_t *eph, FAR struct epoll_event *evs, list_delete(&epn->node); if ((epn->pfd.events & EPOLLONESHOT) != 0) { - list_add_tail(&eph->free, &epn->node); + list_add_tail(&eph->oneshot, &epn->node); } else { @@ -428,6 +435,15 @@ int epoll_ctl(int epfd, int op, int fd, FAR struct epoll_event *ev) } } + list_for_every_entry(&eph->oneshot, epn, epoll_node_t, node) + { + if (epn->pfd.fd == fd) + { + ret = -EEXIST; + goto err; + } + } + if (list_is_empty(&eph->free)) { /* Malloc new epoll node, insert the first list_node to the @@ -494,6 +510,16 @@ int epoll_ctl(int epfd, int op, int fd, FAR struct epoll_event *ev) } } + list_for_every_entry(&eph->oneshot, epn, epoll_node_t, node) + { + if (epn->pfd.fd == fd) + { + list_delete(&epn->node); + list_add_tail(&eph->free, &epn->node); + goto out; + } + } + break; case EPOLL_CTL_MOD: @@ -543,6 +569,27 @@ int epoll_ctl(int epfd, int op, int fd, FAR struct epoll_event *ev) list_add_tail(&eph->setup, &epn->node); } + goto out; + } + } + + list_for_every_entry(&eph->oneshot, epn, epoll_node_t, node) + { + if (epn->pfd.fd == fd) + { + epn->data = ev->data; + epn->pfd.events = ev->events; + epn->pfd.fd = fd; + epn->pfd.revents = 0; + + ret = poll_fdsetup(fd, &epn->pfd, true); + if (ret < 0) + { + goto err; + } + + list_delete(&epn->node); + list_add_tail(&eph->setup, &epn->node); break; } }