M Michael Kerrisk (man-pages) #
Message details and related content
[CC += linux-api@] Hello Paton, On Thu, Aug 23, 2012 at 11:15 PM, Paton J. Lewis [off-list ref] wrote:
From: "Paton J. Lewis" <redacted> Enhanced epoll_ctl to support EPOLL_CTL_DISABLE, which disables an epoll item. If epoll_ctl doesn't return -EBUSY in this case, it is then safe to delete the epoll item in a multi-threaded environment. Also added a new test_epoll self- test app to both demonstrate the need for this feature and test it.
(There's a lot of background missing from this version of the patch that was included in the previous version [http://thread.gmane.org/gmane.linux.kernel/1311457]. It helps to include the full rationale with a revised patch--best not to assume that someone has the context of past mails when reading a revised patch.) I've taken a look at this patch as it currently stands in 3.7-rc1, and done a bit of testing. (By the way, the test program tools/testing/selftests/epoll/test_epoll.c does not compile...) There are one or two places where the behavior seems a little strange, so I have a question or two at the end of this mail. But other than that, I want to check my understanding so that the interface can be correctly documented. Just to go though my understanding, the problem is the following scenario in a multithreaded application: 1. Multiple threads are performing epoll_wait() operations, and maintaining a user-space cache that contains information corresponding to each file descriptor being monitored by epoll_wait(). 2. At some point, a thread wants to delete (EPOLL_CTL_DEL) a file descriptor from the epoll interest list, and delete the corresponding record from the user-space cache. 3. The problem with (2) is that some other thread may have previously done an epoll_wait() that retrieved information about the fd in question, and may be in the middle of using information in the cache that relates to that fd. Thus, there is a potential race. 4. The race can't solved purely in user space, because doing so would require applying a mutex across the epoll_wait() call, which would of course blow thread concurrency. Right?
quoted hunk
Signed-off-by: Paton J. Lewis <redacted> --- fs/eventpoll.c | 38 ++- include/linux/eventpoll.h | 1 + tools/testing/selftests/Makefile | 2 +- tools/testing/selftests/epoll/Makefile | 11 + tools/testing/selftests/epoll/test_epoll.c | 344 ++++++++++++++++++++++++++++ 5 files changed, 392 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/epoll/Makefile create mode 100644 tools/testing/selftests/epoll/test_epoll.cdiff --git a/fs/eventpoll.c b/fs/eventpoll.c index 739b098..1c47bbd 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c@@ -339,7 +339,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p) /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ static inline int ep_op_has_event(int op) { - return op != EPOLL_CTL_DEL; + return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD; } /* Initialize the poll safe wake up structure */@@ -664,6 +664,34 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) return 0; } +/* + * Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item + * had no event flags set, indicating that another thread may be currently + * handling that item's events (in the case that EPOLLONESHOT was being + * used). Otherwise a zero result indicates that the item has been disabled + * from receiving events. A disabled item may be re-enabled via + * EPOLL_CTL_MOD. Must be called with "mtx" held. + */ +static int ep_disable(struct eventpoll *ep, struct epitem *epi) +{ + int result = 0; + unsigned long flags;
-- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Author of "The Linux Programming Interface"; http://man7.org/tlpi/