From: g0dil Date: Wed, 2 Jul 2008 13:27:03 +0000 (+0000) Subject: Scheduler: Implement SignalDispatcher X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=7a02284399aee1039c67aea3691b4899d8fa10d4;p=senf.git Scheduler: Implement SignalDispatcher git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@887 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Scheduler/FdDispatcher.test.cc b/Scheduler/FdDispatcher.test.cc index 62a6187..2a87e71 100644 --- a/Scheduler/FdDispatcher.test.cc +++ b/Scheduler/FdDispatcher.test.cc @@ -28,7 +28,6 @@ // Custom includes #include -#include #include #include #include @@ -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() ); diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index 0d8a149..695e9b3 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -29,7 +29,6 @@ // Custom includes #include -#include #include #include #include diff --git a/Scheduler/SignalDispatcher.cc b/Scheduler/SignalDispatcher.cc new file mode 100644 index 0000000..df23c1c --- /dev/null +++ b/Scheduler/SignalDispatcher.cc @@ -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 +// +// 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" + + +// 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 index 0000000..b590200 --- /dev/null +++ b/Scheduler/SignalDispatcher.cci @@ -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 +// +// 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 + +#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_ + + +// 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 index 0000000..752f063 --- /dev/null +++ b/Scheduler/SignalDispatcher.hh @@ -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 +// +// 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 +#include +#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 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 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 + + +// 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 index 0000000..0b97e18 --- /dev/null +++ b/Scheduler/SignalDispatcher.test.cc @@ -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 +// +// 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 + +#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_ + + +// 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: