Update dasynq to latest HEAD
authorDavin McCall <davmac@davmac.org>
Thu, 16 Jun 2016 07:27:22 +0000 (08:27 +0100)
committerDavin McCall <davmac@davmac.org>
Thu, 16 Jun 2016 07:27:22 +0000 (08:27 +0100)
src/dasync/dasync-childproc.h
src/dasync/dasync-epoll.h
src/dasync/dasync-kqueue.h
src/dasync/dasync.h

index f92d4c6a5758509131bd8d962948fcec2592ad6d..990fbb1537785b5e643df8035baf3b86aeeedddf 100644 (file)
@@ -74,6 +74,17 @@ class pid_map
     }
 };
 
+namespace {
+    void sigchld_handler(int signum)
+    {
+        // If SIGCHLD has no handler (is ignored), SIGCHLD signals will
+        // not be queued for terminated child processes. (On Linux, the
+        // default disposition for SIGCHLD is to be ignored but *not* have
+        // this behavior, which seems inconsistent. Setting a handler doesn't
+        // hurt in any case).
+    }
+}
+
 template <class Base> class ChildProcEvents : public Base
 {
     private:
@@ -118,6 +129,11 @@ template <class Base> class ChildProcEvents : public Base
     template <typename T> void init(T *loop_mech)
     {
         loop_mech->addSignalWatch(SIGCHLD, nullptr);
+        struct sigaction chld_action;
+        chld_action.sa_handler = sigchld_handler;
+        sigemptyset(&chld_action.sa_mask);
+        chld_action.sa_flags = 0;
+        sigaction(SIGCHLD, &chld_action, nullptr);
     }
 };
 
index 5bd3e5e85f520732325edde6e3ba7b1521f27c9e..05cf5aa058713ccf7a62dbc4ae68bb1ea293b0cf 100644 (file)
@@ -167,14 +167,14 @@ template <class Base> class EpollLoop : public Base
         }
     }
     
-    void removeFdWatch(int fd) noexcept
+    void removeFdWatch(int fd, int flags) noexcept
     {
         epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nullptr);
     }
     
-    void removeFdWatch_nolock(int fd) noexcept
+    void removeFdWatch_nolock(int fd, int flags) noexcept
     {
-        removeFdWatch(fd);
+        removeFdWatch(fd, flags);
     }
     
     // Note this will *replace* the old flags with the new, that is,
@@ -207,7 +207,7 @@ template <class Base> class EpollLoop : public Base
         enableFdWatch(fd, userdata, flags);
     }
     
-    void disableFdWatch(int fd) noexcept
+    void disableFdWatch(int fd, int flags) noexcept
     {
         struct epoll_event epevent;
         // epevent.data.fd = fd;
@@ -223,9 +223,9 @@ template <class Base> class EpollLoop : public Base
         }
     }
     
-    void disableFdWatch_nolock(int fd) noexcept
+    void disableFdWatch_nolock(int fd, int flags) noexcept
     {
-        disableFdWatch(fd);
+        disableFdWatch(fd, flags);
     }
     
     // Note signal should be masked before call.
index 5dab0c546e284bbe6bc073beb4c49d415553cfcf..fb6d9da6693beb826c7f48f1ac36a978aace8eb1 100644 (file)
@@ -64,6 +64,9 @@ class KqueueTraits
         {
             return fd;
         }
+        FD_r(int nfd) : fd(nfd)
+        {
+        }
     };
     
     const static bool has_separate_rw_fd_watches = true;
@@ -139,13 +142,14 @@ template <class Base> class KqueueLoop : public Base
                     events[i].flags = EV_ENABLE;
                 }
             }
+            else if (events[i].filter == EVFILT_READ || events[i].filter == EVFILT_WRITE) {
+                int flags = events[i].filter == EVFILT_READ ? in_events : out_events;
+                Base::receiveFdEvent(*this, FD_r(events[i].ident), events[i].udata, flags);
+                events[i].flags = EV_DISABLE | EV_CLEAR;
+                // we use EV_CLEAR to clear the EOF status of fifos/pipes (and wait for
+                // another connection).
+            }
             else {
-            //    int flags = 0;
-            //    (events[i].events & EPOLLIN) && (flags |= in_events);
-            //    (events[i].events & EPOLLHUP) && (flags |= in_events);
-            //    (events[i].events & EPOLLOUT) && (flags |= out_events);
-            //    (events[i].events & EPOLLERR) && (flags |= err_events);
-            //    Base::receiveFdEvent(*this, FD_r(), ptr, flags);
                 events[i].flags = EV_DISABLE;
             }
         }
@@ -176,68 +180,47 @@ template <class Base> class KqueueLoop : public Base
         close(kqfd);
     }
     
-    void disableFilter(short filterType, uintptr_t ident)
+    void setFilterEnabled(short filterType, uintptr_t ident, bool enable)
     {
         struct kevent kev;
-        EV_SET(&kev, ident, filterType, EV_DISABLE, 0, 0, 0);
+        EV_SET(&kev, ident, filterType, enable ? EV_ENABLE : EV_DISABLE, 0, 0, 0);
         kevent(kqfd, &kev, 1, nullptr, 0, nullptr);
     }
     
+    void removeFilter(short filterType, uintptr_t ident)
+    {
+        struct kevent kev;
+        EV_SET(&kev, ident, filterType, EV_DELETE, 0, 0, 0);
+        kevent(kqfd, &kev, 1, nullptr, 0, nullptr);    
+    }
+    
     // flags:  in_events | out_events
     void addFdWatch(int fd, void *userdata, int flags)
     {
-        //struct epoll_event epevent;
-        // epevent.data.fd = fd;
-        //epevent.data.ptr = userdata;
-        //epevent.events = 0;
+        // TODO kqueue doesn't support EVFILE_WRITE on file fd's :/
         
-        //if (flags & one_shot) {
-        //    epevent.events = EPOLLONESHOT;
-        //}
-        //if (flags & in_events) {
-        //    epevent.events |= EPOLLIN;
-        //}
-        //if (flags & out_events) {
-        //    epevent.events |= EPOLLOUT;
-        //}
-
-        //if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == -1) {
-        //    throw new std::system_error(errno, std::system_category());        
-        //}
+        short filter = (flags & in_events) ? EVFILT_READ : EVFILT_WRITE;
+        
+        struct kevent kev;
+        EV_SET(&kev, fd, filter, EV_ADD, 0, 0, userdata);
+        if (kevent(kqfd, &kev, 1, nullptr, 0, nullptr) == -1) {
+            throw new std::system_error(errno, std::system_category());
+        }
     }
     
-    void removeFdWatch(int fd)
-    {
-        //epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nullptr);
+    void removeFdWatch(int fd, int flags)
+    {        
+        removeFilter((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd);
     }
     
-    void removeFdWatch_nolock(int fd)
+    void removeFdWatch_nolock(int fd, int flags)
     {
-        removeFdWatch(fd);
+        removeFdWatch(fd, flags);
     }
     
-    // Note this will *replace* the old flags with the new, that is,
-    // it can enable *or disable* read/write events.
     void enableFdWatch(int fd, void *userdata, int flags)
     {
-        //struct epoll_event epevent;
-        // epevent.data.fd = fd;
-        //epevent.data.ptr = userdata;
-        //epevent.events = 0;
-        
-        //if (flags & one_shot) {
-        //    epevent.events = EPOLLONESHOT;
-        //}
-        //if (flags & in_events) {
-        //    epevent.events |= EPOLLIN;
-        //}
-        //if (flags & out_events) {
-        //    epevent.events |= EPOLLOUT;
-        //}
-
-        //if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &epevent) == -1) {
-        //    throw new std::system_error(errno, std::system_category());        
-        //}
+        setFilterEnabled((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd, true);
     }
     
     void enableFdWatch_nolock(int fd, void *userdata, int flags)
@@ -245,24 +228,14 @@ template <class Base> class KqueueLoop : public Base
         enableFdWatch(fd, userdata, flags);
     }
     
-    void disableFdWatch(int fd)
+    void disableFdWatch(int fd, int flags)
     {
-        //struct epoll_event epevent;
-        // epevent.data.fd = fd;
-        //epevent.data.ptr = nullptr;
-        //epevent.events = 0;
-        
-        // Epoll documentation says that hangup will still be reported, need to check
-        // whether this is really the case. Suspect it is really only the case if
-        // EPOLLIN is set.
-        //if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &epevent) == -1) {
-        //    throw new std::system_error(errno, std::system_category());        
-        //}
+        setFilterEnabled((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd, false);
     }
     
-    void disableFdWatch_nolock(int fd)
+    void disableFdWatch_nolock(int fd, int flags)
     {
-        // TODO
+        disableFdWatch(fd, flags);
     }
     
     // Note signal should be masked before call.
@@ -345,7 +318,7 @@ template <class Base> class KqueueLoop : public Base
                     sigdelset(&sigmask, rsigno);
                     // TODO accumulate and disable multiple filters with a single kevents call
                     //      rather than disabling each individually
-                    disableFilter(EVFILT_SIGNAL, rsigno);
+                    setFilterEnabled(EVFILT_SIGNAL, rsigno, false);
                 }
                 Base::receiveSignal(siginfo, sigdataMap[rsigno]);
                 rsigno = sigtimedwait(&sigmask, &siginfo.info, &timeout);
index 807f88e1310d1b63f588d31a854efc007c05fe33..3602f01df21ca64d26fdce20a2c1d6752336de8b 100644 (file)
@@ -571,7 +571,7 @@ template <typename T_Mutex> class EventLoop
         loop_mech.removeSignalWatch(signo);
         
         waitqueue_node<T_Mutex> qnode;
-        getAttnLock(qnode);        
+        getAttnLock(qnode);
         
         EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
         ed.issueDelete(callBack);
@@ -600,7 +600,7 @@ template <typename T_Mutex> class EventLoop
             loop_mech.enableFdWatch(fd, watcher, watch_flags | one_shot);
         }
         else {
-            loop_mech.disableFdWatch(fd);
+            loop_mech.disableFdWatch(fd, watch_flags);
         }
     }
 
@@ -610,16 +610,16 @@ template <typename T_Mutex> class EventLoop
             loop_mech.enableFdWatch_nolock(fd, watcher, watch_flags | one_shot);
         }
         else {
-            loop_mech.disableFdWatch_nolock(fd);
+            loop_mech.disableFdWatch_nolock(fd, watch_flags);
         }
     }
     
     void deregister(BaseFdWatcher *callback, int fd)
     {
-        loop_mech.removeFdWatch(fd);
+        loop_mech.removeFdWatch(fd, callback->watch_flags);
         
         waitqueue_node<T_Mutex> qnode;
-        getAttnLock(qnode);        
+        getAttnLock(qnode);
         
         EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
         ed.issueDelete(callback);
@@ -633,11 +633,11 @@ template <typename T_Mutex> class EventLoop
             // TODO
         }
         else {
-            loop_mech.removeFdWatch(fd);
+            loop_mech.removeFdWatch(fd, callback->watch_flags);
         }
         
         waitqueue_node<T_Mutex> qnode;
-        getAttnLock(qnode);        
+        getAttnLock(qnode);
         
         EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
         ed.issueDelete(callback);
@@ -743,14 +743,14 @@ template <typename T_Mutex> class EventLoop
                     }
                     else {
                         // both removed: actually remove
-                        loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+                        loop_mech.removeFdWatch_nolock(bdfw->watch_fd, 0 /* not used */);
                         return Rearm::REMOVE;
                     }
                 }
                 else {
                     // TODO this will need flags for such a loop, since it can't
                     // otherwise distinguish which channel watch to remove
-                    loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+                    loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags);
                 }
             }
             else if (rearmType == Rearm::DISARM) {
@@ -777,7 +777,7 @@ template <typename T_Mutex> class EventLoop
                         (bfw->watch_flags & (in_events | out_events)) | one_shot);
             }
             else if (rearmType == Rearm::REMOVE) {
-                loop_mech.removeFdWatch_nolock(bfw->watch_fd);
+                loop_mech.removeFdWatch_nolock(bfw->watch_fd, bfw->watch_flags);
             }
             return rearmType;
         }
@@ -793,7 +793,7 @@ template <typename T_Mutex> class EventLoop
             if (LoopTraits::has_separate_rw_fd_watches) {
                 // TODO this will need flags for such a loop, since it can't
                 // otherwise distinguish which channel watch to remove
-                loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+                loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags);
                 return bdfw->read_removed ? Rearm::REMOVE : Rearm::NOOP;
             }
             else {
@@ -802,7 +802,7 @@ template <typename T_Mutex> class EventLoop
                 }
                 else {
                     // both removed: actually remove
-                    loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+                    loop_mech.removeFdWatch_nolock(bdfw->watch_fd, 0 /* not used */);
                     return Rearm::REMOVE;
                 }
             }
@@ -846,6 +846,8 @@ template <typename T_Mutex> class EventLoop
             bool is_multi_watch = false;
             BaseBidiFdWatcher *bbfw = nullptr;
             
+            // (Above variables are initialised only to silence compiler warnings).
+            
             // Read/manipulate watch_flags (if necessary) *before* we release the lock:
             if (pqueue->watchType == WatchType::FD) {
                 BaseFdWatcher *bfw = static_cast<BaseFdWatcher *>(pqueue);
@@ -868,8 +870,6 @@ template <typename T_Mutex> class EventLoop
             
             ed.lock.unlock();
             
-            // (Above variables are initialised only to silence compiler warnings).
-            
             // Note that we select actions based on the type of the watch, as determined by the watchType
             // member. In some ways this screams out for polmorphism; a virtual function could be overridden
             // by each of the watcher types. I've instead used switch/case because I think it will perform
@@ -933,9 +933,7 @@ template <typename T_Mutex> class EventLoop
                 default: ;
                 }
                 
-                if (pqueue->deleteme) rearmType = Rearm::REMOVE; // makes the watchRemoved() callback get called.
-                
-                if (rearmType == Rearm::REMOVE) {
+                if (pqueue->deleteme || rearmType == Rearm::REMOVE) {
                     ed.lock.unlock();
                     (is_multi_watch ? bbfw : pqueue)->watchRemoved();
                     ed.lock.lock();