tevent: In epoll_event_loop() ensure we trigger the right handler for a multiplexed...
authorStefan Metzmacher <metze@samba.org>
Wed, 20 Feb 2013 13:49:17 +0000 (14:49 +0100)
committerJeremy Allison <jra@samba.org>
Fri, 1 Mar 2013 20:01:19 +0000 (12:01 -0800)
Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/tevent/tevent_epoll.c

index 3e3ddf9d3f3e488ab79a9c76f13adbeaf24fdc24..41415b06e9aaf520ea90258a80b77946ef72cbc5 100644 (file)
@@ -665,27 +665,56 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
                struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
                                                       struct tevent_fd);
                uint16_t flags = 0;
+               struct tevent_fd *mpx_fde = NULL;
 
                if (fde == NULL) {
                        epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
                        return -1;
                }
-               if (events[i].events & (EPOLLHUP|EPOLLERR)) {
-                       fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+               if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
                        /*
-                        * if we only wait for TEVENT_FD_WRITE, we should not tell the
-                        * event handler about it, and remove the epoll_event,
-                        * as we only report errors when waiting for read events,
-                        * to match the select() behavior
+                        * Save off the multiplexed event in case we need
+                        * to use it to call the handler function.
                         */
-                       if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+                       mpx_fde = talloc_get_type_abort(fde->additional_data,
+                                                       struct tevent_fd);
+               }
+               if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+                       bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde);
+                       bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde);
+
+                       if (handled_fde && handled_mpx) {
                                epoll_update_event(epoll_ev, fde);
                                continue;
                        }
+
+                       if (!handled_mpx) {
+                               /*
+                                * If the mpx event was the one that needs
+                                * further handling, it's the TEVENT_FD_READ
+                                * event so switch over and call that handler.
+                                */
+                               fde = mpx_fde;
+                               mpx_fde = NULL;
+                       }
                        flags |= TEVENT_FD_READ;
                }
                if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
                if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+
+               if (mpx_fde) {
+                       /* Ensure we got the right fde. */
+                       if ((flags & fde->flags) == 0) {
+                               fde = mpx_fde;
+                               mpx_fde = NULL;
+                       }
+               }
+
+               /*
+                * make sure we only pass the flags
+                * the handler is expecting.
+                */
+               flags &= fde->flags;
                if (flags) {
                        fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
                        break;