Scheduler: Implement SignalDispatcher
g0dil [Wed, 2 Jul 2008 13:27:03 +0000 (13:27 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@887 270642c3-0616-0410-b53a-bc976706d245

Scheduler/FdDispatcher.test.cc
Scheduler/Scheduler.hh
Scheduler/SignalDispatcher.cc [new file with mode: 0644]
Scheduler/SignalDispatcher.cci [new file with mode: 0644]
Scheduler/SignalDispatcher.hh [new file with mode: 0644]
Scheduler/SignalDispatcher.test.cc [new file with mode: 0644]

index 62a6187..2a87e71 100644 (file)
@@ -28,7 +28,6 @@
 
 // Custom includes
 #include <sys/types.h>
-#include <signal.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <sys/socket.h>
@@ -166,6 +165,7 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher)
     senf::scheduler::FdManager manager;
     senf::scheduler::FIFORunner runner;
     senf::scheduler::FdDispatcher dispatcher (manager, runner);
+    manager.timeout(1000);
 
     int pid (start_server());
     BOOST_REQUIRE( pid );
@@ -187,7 +187,6 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher)
 
     SENF_CHECK_NO_THROW( dispatcher.add(sock, boost::bind(&callback, sock, _1),
                                         senf::scheduler::FdDispatcher::EV_READ) );
-    manager.timeout(1000);
     event = 0;
     SENF_CHECK_NO_THROW( manager.processOnce() );
     SENF_CHECK_NO_THROW( runner.run() );
index 0d8a149..695e9b3 100644 (file)
@@ -29,7 +29,6 @@
 
 // Custom includes
 #include <signal.h>
-#include <setjmp.h>
 #include <map>
 #include <queue>
 #include <boost/function.hpp>
diff --git a/Scheduler/SignalDispatcher.cc b/Scheduler/SignalDispatcher.cc
new file mode 100644 (file)
index 0000000..df23c1c
--- /dev/null
@@ -0,0 +1,137 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher non-inline non-template implementation */
+
+#include "SignalDispatcher.hh"
+//#include "SignalDispatcher.ih"
+
+// Custom includes
+#include "../Utils/senfassert.hh"
+
+//#include "SignalDispatcher.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+senf::scheduler::SignalDispatcher * senf::scheduler::SignalDispatcher::instance_ = 0;
+
+prefix_ senf::scheduler::SignalDispatcher::SignalDispatcher(FdManager & manager,
+                                                            FIFORunner & runner)
+    : manager_ (manager), runner_ (runner), blocked_ (true)
+{
+    SENF_ASSERT( !instance_ );
+    if (pipe(sigPipe_) <0)
+        throw SystemException("pipe()");
+    sigemptyset(&sigSet_);
+    instance_ = this;
+    manager_.set(sigPipe_[0], FdManager::EV_READ, this);
+}
+
+prefix_ senf::scheduler::SignalDispatcher::~SignalDispatcher()
+{
+    sigprocmask(SIG_UNBLOCK, & sigSet_, 0);
+    for (HandlerMap::iterator i (handlers_.begin()); i != handlers_.end(); ++i) {
+        ::signal(i->first, SIG_DFL);
+        runner_.dequeue(&i->second);
+    }
+    manager_.remove(sigPipe_[0]);
+    close(sigPipe_[0]);
+    close(sigPipe_[1]);
+    instance_ = 0;
+}
+
+prefix_ void senf::scheduler::SignalDispatcher::add(int signal, Callback const & cb)
+{
+    HandlerMap::iterator i (handlers_.find(signal));
+    if (i != handlers_.end()) {
+        i->second.cb = cb;
+        return;
+    }
+
+    i = handlers_.insert(std::make_pair(signal, SignalEvent(cb))).first;
+    sigaddset(&sigSet_, signal);
+    runner_.enqueue(&i->second);
+
+    sigset_t sig;
+    sigemptyset(&sig);
+    sigaddset(&sig, signal);
+    sigprocmask(blocked_ ? SIG_BLOCK : SIG_UNBLOCK, &sig, 0);
+
+    // Need to re-register all handlers to update sa_mask
+    for (HandlerMap::iterator j (handlers_.begin()); i != handlers_.end(); ++i) {
+        struct sigaction act;
+        act.sa_sigaction = &sigHandler;
+        act.sa_mask = sigSet_;
+        act.sa_flags = SA_SIGINFO | SA_RESTART;
+        if (j->first == SIGCLD)
+            act.sa_flags |= SA_NOCLDSTOP;
+        if (sigaction(j->first, &act, 0) < 0)
+            throw SystemException("sigaction()");
+    }
+}
+
+prefix_ void senf::scheduler::SignalDispatcher::remove(int signal)
+{
+    ::signal(signal, SIG_DFL);
+    sigset_t sig;
+    sigemptyset(&sig);
+    sigaddset(&sig, signal);
+    sigprocmask(SIG_UNBLOCK, &sig, 0);
+}
+
+prefix_ void senf::scheduler::SignalDispatcher::signal(int events)
+{
+    siginfo_t info;
+    if (read(sigPipe_[0], &info, sizeof(info)) < int(sizeof(info)))
+        return;
+    HandlerMap::iterator i (handlers_.find(info.si_signo));
+    if (i == handlers_.end())
+        return;
+    i->second.siginfo = info;
+    i->second.runnable = true;
+}
+
+prefix_ void senf::scheduler::SignalDispatcher::sigHandler(int signal, ::siginfo_t * siginfo,
+                                                           void *)
+{
+    SENF_ASSERT( instance_ );
+    // The manpage says, si_signo is unused in linux so we set it here
+    siginfo->si_signo = signal; 
+    // We can't do much on error anyway so we ignore errors here
+    write(instance_->sigPipe_[1], siginfo, sizeof(*siginfo));
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "SignalDispatcher.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/SignalDispatcher.cci b/Scheduler/SignalDispatcher.cci
new file mode 100644 (file)
index 0000000..b590200
--- /dev/null
@@ -0,0 +1,75 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher inline non-template implementation */
+
+//#include "SignalDispatcher.ih"
+
+// Custom includes
+#include <unistd.h>
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ void senf::scheduler::SignalDispatcher::blockSignals()
+{
+    if (blocked_) return;
+    sigprocmask(SIG_BLOCK, &sigSet_, 0);
+    blocked_ = true;
+}
+
+prefix_ void senf::scheduler::SignalDispatcher::unblockSignals()
+{
+    if (!blocked_) return;
+    sigprocmask(SIG_UNBLOCK, &sigSet_, 0);
+    blocked_ = false;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::SignalDispatcher::SignalEvent
+
+prefix_ senf::scheduler::SignalDispatcher::SignalEvent::SignalEvent(Callback cb_)
+    : cb (cb_)
+{}
+
+prefix_ senf::scheduler::SignalDispatcher::SignalEvent::~SignalEvent()
+{}
+
+prefix_ void senf::scheduler::SignalDispatcher::SignalEvent::run()
+{
+    cb(siginfo);
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/SignalDispatcher.hh b/Scheduler/SignalDispatcher.hh
new file mode 100644 (file)
index 0000000..752f063
--- /dev/null
@@ -0,0 +1,117 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher public header */
+
+#ifndef HH_SignalDispatcher_
+#define HH_SignalDispatcher_ 1
+
+// Custom includes
+#include <signal.h>
+#include <map>
+#include "FdManager.hh"
+#include "FIFORunner.hh"
+
+//#include "SignalDispatcher.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace scheduler {
+
+    /** \brief
+      */
+    class SignalDispatcher
+        : public FdManager::Event
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void (siginfo_t const &)> Callback;
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        explicit SignalDispatcher(FdManager & manager, FIFORunner & runner);
+        ~SignalDispatcher();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        void add(int signal, Callback const & cb);
+        void remove(int signal);
+
+        void blockSignals();
+        void unblockSignals();
+
+    protected:
+
+    private:
+        struct SignalEvent
+            : public FIFORunner::TaskInfo
+        {
+            explicit SignalEvent(Callback cb_);
+            virtual ~SignalEvent();
+            virtual void run();
+
+            siginfo_t siginfo;
+            Callback cb;
+        };
+
+        virtual void signal(int events);
+        static void sigHandler(int signal, ::siginfo_t * siginfo, void *);
+
+        FdManager & manager_;
+        FIFORunner & runner_;
+
+        typedef std::map<int, SignalEvent> HandlerMap;
+        HandlerMap handlers_;
+
+        int sigPipe_[2];
+
+        bool blocked_;
+        sigset_t sigSet_;
+
+        static SignalDispatcher * instance_;
+    };
+
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "SignalDispatcher.cci"
+//#include "SignalDispatcher.ct"
+//#include "SignalDispatcher.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/SignalDispatcher.test.cc b/Scheduler/SignalDispatcher.test.cc
new file mode 100644 (file)
index 0000000..0b97e18
--- /dev/null
@@ -0,0 +1,79 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief SignalDispatcher.test unit tests */
+
+//#include "SignalDispatcher.test.hh"
+//#include "SignalDispatcher.test.ih"
+
+// Custom includes
+#include "SignalDispatcher.hh"
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+    
+    bool called = false;
+    void handler(siginfo_t const &)
+    {
+        called = true;
+    }
+}
+
+BOOST_AUTO_UNIT_TEST(signalDispatcher)
+{
+    senf::scheduler::FdManager manager;
+    senf::scheduler::FIFORunner runner;
+    senf::scheduler::SignalDispatcher dispatcher (manager, runner);
+    manager.timeout(1000);
+
+    SENF_CHECK_NO_THROW( dispatcher.add(SIGUSR1, &handler) );
+    BOOST_CHECK( ! called );
+    ::kill(::getpid(), SIGUSR1);
+    sleep(1);
+    SENF_CHECK_NO_THROW( dispatcher.unblockSignals() );
+    SENF_CHECK_NO_THROW( manager.processOnce() );
+    SENF_CHECK_NO_THROW( dispatcher.blockSignals() );
+    SENF_CHECK_NO_THROW( runner.run() );
+    BOOST_CHECK( called );
+
+    SENF_CHECK_NO_THROW( dispatcher.remove(SIGUSR1) );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End: