Basic interface that takes a wait_queue_entry rather than post one on the stack, which can be a persistent callback for when new events arrive. Works like regular epoll_wait(), except it doesn't block. If events are available, they are returned. If none are available, the passed in wait_queue_entry is added to the callback list. The wait_queue_entry must be previously initialized, and the callback provided will be called when events are added to the epoll context. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- fs/eventpoll.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/eventpoll.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 14466765b85d..d3ac466ad415 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1996,6 +1996,33 @@ static int ep_try_send_events(struct eventpoll *ep, return res; } +static int ep_poll_queue(struct eventpoll *ep, + struct epoll_event __user *events, int maxevents, + struct wait_queue_entry *wait) +{ + int res = 0, eavail; + + /* See ep_poll() for commentary */ + eavail = ep_events_available(ep); + while (1) { + if (eavail) { + res = ep_try_send_events(ep, events, maxevents); + if (res) + return res; + } + if (!list_empty_careful(&wait->entry)) + break; + write_lock_irq(&ep->lock); + eavail = ep_events_available(ep); + if (!eavail) + __add_wait_queue_exclusive(&ep->wq, wait); + write_unlock_irq(&ep->lock); + if (!eavail) + break; + } + return -EIOCBQUEUED; +} + /** * ep_poll - Retrieves ready events, and delivers them to the caller-supplied * event buffer. @@ -2474,6 +2501,18 @@ static int ep_check_params(struct file *file, struct epoll_event __user *evs, return 0; } +int epoll_queue(struct file *file, struct epoll_event __user *events, + int maxevents, struct wait_queue_entry *wait) +{ + int ret; + + ret = ep_check_params(file, events, maxevents); + if (unlikely(ret)) + return ret; + + return ep_poll_queue(file->private_data, events, maxevents, wait); +} + /* * Implement the event wait interface for the eventpoll file. It is the kernel * part of the user space epoll_wait(2). diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 0c0d00fcd131..8de16374b8fe 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -25,6 +25,10 @@ struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd, unsigned long t /* Used to release the epoll bits inside the "struct file" */ void eventpoll_release_file(struct file *file); +/* Use to reap events, and/or queue for a callback on new events */ +int epoll_queue(struct file *file, struct epoll_event __user *events, + int maxevents, struct wait_queue_entry *wait); + /* * This is called from inside fs/file_table.c:__fput() to unlink files * from the eventpoll interface. We need to have this facility to cleanup -- 2.47.2