From: g0dil Date: Wed, 17 Sep 2008 07:49:08 +0000 (+0000) Subject: Utils: Add singleton alive test member X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=925317c7f45c32b01ab9292023db3f372b74bf0f;hp=46ce25973f087d30ca10eebdad6e3bfa7586ecc9;p=senf.git Utils: Add singleton alive test member Scheduler: Fix FIFORunner exception safety Scheduler: Implement new signal event API Migrate SENF to use new signal API git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@906 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/SConstruct b/SConstruct index 0e0f4d7..3ae0d5e 100644 --- a/SConstruct +++ b/SConstruct @@ -173,6 +173,21 @@ env.Append( 'config.hh', 'local_config.hh' ], ) +def parseLogOption(value): + stream, area, level = ( x.strip() for x in value.strip().split('|') ) + if stream : stream = ''.join('(%s)' % x for x in stream.split('::') ) + else : stream = '(_)' + if area : area = ''.join( '(%s)' % x for x in area.split('::') ) + else : area = '(_)' + return '(( %s,%s,%s ))' % (stream,area,level) + +def expandLogOption(target, source, env, for_signature): + return ' '.join( parseLogOption(x) for x in env.subst('$LOGLEVELS').split() ) + +if env.subst('$LOGLEVELS'): + env.Append( expandLogOption=expandLogOption ) + env.Append( CPPDEFINES = { 'SENF_LOG_CONF': '$expandLogOption' } ) + env.SetDefault( LIBSENF = "senf" ) diff --git a/Scheduler/FIFORunner.cc b/Scheduler/FIFORunner.cc index ffaf11e..7fbd9df 100644 --- a/Scheduler/FIFORunner.cc +++ b/Scheduler/FIFORunner.cc @@ -30,6 +30,7 @@ #include #include #include "../Utils/Exception.hh" +#include "../Utils/senfassert.hh" //#include "FIFORunner.mpp" #define prefix_ @@ -116,32 +117,45 @@ prefix_ void senf::scheduler::FIFORunner::run() // - We keep the next to-be-processed node in a class variable which is checked and updated // whenever a node is removed. NullTask null; - tasks_.push_back(null); - TaskList::iterator end (TaskList::current(null)); - next_ = tasks_.begin(); struct itimerspec timer; timer.it_interval.tv_sec = watchdogMs_ / 1000; timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul; timer.it_value.tv_sec = timer.it_interval.tv_sec; timer.it_value.tv_nsec = timer.it_interval.tv_nsec; - if (timer_settime(watchdogId_, 0, &timer, 0) < 0) - SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); - while (next_ != end) { - TaskInfo & task (*next_); - if (task.runnable) { - task.runnable = false; - runningName_ = task.name; -# ifdef SENF_DEBUG - runningBacktrace_ = task.backtrace; -# endif - TaskList::iterator i (next_); - ++ next_; - tasks_.splice(tasks_.end(), tasks_, i); - watchdogCount_ = 1; - task.run(); + tasks_.push_back(null); + TaskList::iterator end (TaskList::current(null)); + next_ = tasks_.begin(); + try { + if (timer_settime(watchdogId_, 0, &timer, 0) < 0) + SENF_THROW_SYSTEM_EXCEPTION("timer_settime()"); + while (next_ != end) { + TaskInfo & task (*next_); + if (task.runnable) { + task.runnable = false; + runningName_ = task.name; +# ifdef SENF_DEBUG + runningBacktrace_ = task.backtrace; +# endif + TaskList::iterator i (next_); + ++ next_; + tasks_.splice(tasks_.end(), tasks_, i); + watchdogCount_ = 1; + task.run(); + } + else + ++ next_; } - else - ++ next_; + } + catch (...) { + watchdogCount_ = 0; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + timer.it_value.tv_sec = 0; + timer.it_value.tv_nsec = 0; + timer_settime(watchdogId_, 0, &timer, 0); + tasks_.erase(end); + next_ = tasks_.end(); + throw; } watchdogCount_ = 0; timer.it_interval.tv_sec = 0; diff --git a/Scheduler/FIFORunner.hh b/Scheduler/FIFORunner.hh index 464d4f4..756f07f 100644 --- a/Scheduler/FIFORunner.hh +++ b/Scheduler/FIFORunner.hh @@ -31,11 +31,15 @@ #include #include "../boost/intrusive/ilist.hpp" #include "../boost/intrusive/ilist_hook.hpp" +#include "../Utils/singleton.hh" //#include "FIFORunner.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + + class Scheduler; + namespace scheduler { /** \brief Task execution scheduler @@ -48,7 +52,7 @@ namespace scheduler { is posted for the task. */ class FIFORunner - : boost::noncopyable + : public singleton { public: struct TaskInfo; @@ -56,8 +60,7 @@ namespace scheduler { private: struct TaskListTag; typedef boost::intrusive::ilist_base_hook TaskListBase; - typedef TaskListBase::value_traits TaskListType; - typedef boost::intrusive::ilist TaskList; + typedef boost::intrusive::ilist, false> TaskList; public: /////////////////////////////////////////////////////////////////////////// @@ -89,8 +92,8 @@ namespace scheduler { ///\name Structors and default members ///@{ - FIFORunner(); - ~FIFORunner(); + using singleton::instance; + using singleton::alive; ///@} /////////////////////////////////////////////////////////////////////////// @@ -112,6 +115,9 @@ namespace scheduler { protected: private: + FIFORunner(); + ~FIFORunner(); + static void watchdog(int, siginfo_t *, void *); TaskList tasks_; @@ -124,6 +130,9 @@ namespace scheduler { # endif unsigned watchdogCount_; unsigned hangCount_; + + friend class singleton; + friend class senf::Scheduler; }; diff --git a/Scheduler/FdDispatcher.test.cc b/Scheduler/FdDispatcher.test.cc index 853d862..6e20cc8 100644 --- a/Scheduler/FdDispatcher.test.cc +++ b/Scheduler/FdDispatcher.test.cc @@ -162,10 +162,8 @@ namespace { BOOST_AUTO_UNIT_TEST(fdDispatcher) { - senf::scheduler::FdManager manager; - senf::scheduler::FIFORunner runner; - senf::scheduler::FdDispatcher dispatcher (manager, runner); - manager.timeout(1000); + senf::scheduler::FdDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance()); + senf::scheduler::FdManager::instance().timeout(1000); int pid (start_server()); BOOST_REQUIRE( pid ); @@ -188,8 +186,8 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher) BOOST_CHECK( dispatcher.add("testHandler", sock, boost::bind(&callback, sock, _1), senf::scheduler::FdDispatcher::EV_READ) ); event = 0; - SENF_CHECK_NO_THROW( manager.processOnce() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_READ ); BOOST_CHECK_EQUAL( size, 4 ); buffer[size] = 0; @@ -201,29 +199,29 @@ BOOST_AUTO_UNIT_TEST(fdDispatcher) senf::scheduler::FdDispatcher::EV_WRITE) ); event = 0; sleep(1); - SENF_CHECK_NO_THROW( manager.processOnce() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_WRITE ); SENF_CHECK_NO_THROW( dispatcher.remove(sock, senf::scheduler::FdDispatcher::EV_WRITE) ); event = 0; sleep(1); - SENF_CHECK_NO_THROW( manager.processOnce() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_HUP | senf::scheduler::FdDispatcher::EV_READ ); BOOST_CHECK_EQUAL( size, 2 ); buffer[size]=0; BOOST_CHECK_EQUAL( buffer, "OK" ); BOOST_CHECK_EQUAL( calls, 3 ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_EQUAL( calls, 3 ); // Ensure, removing an already closed file-descriptor doesn't wreak havoc close(sock); SENF_CHECK_NO_THROW( dispatcher.remove(sock) ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_EQUAL( calls, 3 ); diff --git a/Scheduler/FdManager.hh b/Scheduler/FdManager.hh index 4d7b05e..4845233 100644 --- a/Scheduler/FdManager.hh +++ b/Scheduler/FdManager.hh @@ -29,11 +29,15 @@ // Custom includes #include "Poller.hh" #include "ClockService.hh" +#include "../Utils/singleton.hh" //#include "FdManager.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + + class Scheduler; + namespace scheduler { /** \brief Manage file descriptor event processing @@ -53,6 +57,7 @@ namespace scheduler { \implementation */ class FdManager + : public singleton { public: /////////////////////////////////////////////////////////////////////////// @@ -73,7 +78,8 @@ namespace scheduler { ///\name Structors and default members ///@{ - FdManager(); + using singleton::instance; + using singleton::alive; ///@} /////////////////////////////////////////////////////////////////////////// @@ -106,8 +112,13 @@ namespace scheduler { protected: private: + FdManager(); + Poller poller_; senf::ClockService::clock_type eventTime_; + + friend class singleton; + friend class senf::Scheduler; }; }} diff --git a/Scheduler/FileDispatcher.test.cc b/Scheduler/FileDispatcher.test.cc index f923616..b3c2bcd 100644 --- a/Scheduler/FileDispatcher.test.cc +++ b/Scheduler/FileDispatcher.test.cc @@ -56,9 +56,7 @@ namespace { BOOST_AUTO_UNIT_TEST(fileDispatcher) { - senf::scheduler::FdManager manager; - senf::scheduler::FIFORunner runner; - senf::scheduler::FileDispatcher dispatcher (manager, runner); + senf::scheduler::FileDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance()); dispatcher.timeout(500); // It's not necessary for the cb to be a real file .. it can be anything. The only thing is, @@ -68,9 +66,9 @@ BOOST_AUTO_UNIT_TEST(fileDispatcher) senf::ClockService::clock_type t (senf::ClockService::now()); SENF_CHECK_NO_THROW( dispatcher.add("testHandler", fd, &handler, senf::scheduler::FileDispatcher::EV_READ) ); - SENF_CHECK_NO_THROW( manager.processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); SENF_CHECK_NO_THROW( dispatcher.prepareRun() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK( called ); BOOST_CHECK_PREDICATE( is_close, (t)(senf::ClockService::now()) ); @@ -80,9 +78,9 @@ BOOST_AUTO_UNIT_TEST(fileDispatcher) called = false; t = senf::ClockService::now(); - SENF_CHECK_NO_THROW( manager.processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); SENF_CHECK_NO_THROW( dispatcher.prepareRun() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK( ! called ); BOOST_CHECK_PREDICATE( diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 02364a4..1bfd963 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -35,6 +35,7 @@ //#include "Scheduler.ih" // Custom includes +#include "SignalEvent.hh" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// @@ -45,16 +46,40 @@ prefix_ void senf::Scheduler::process() while(! terminate_ && ! (fdDispatcher_.empty() && timerDispatcher_.empty() && fileDispatcher_.empty())) { - signalDispatcher_.unblockSignals(); + scheduler::detail::SignalDispatcher::instance().unblockSignals(); timerDispatcher_.unblockSignals(); - manager_.processOnce(); + scheduler::FdManager::instance().processOnce(); timerDispatcher_.blockSignals(); - signalDispatcher_.blockSignals(); + scheduler::detail::SignalDispatcher::instance().blockSignals(); fileDispatcher_.prepareRun(); - runner_.run(); + scheduler::FIFORunner::instance().run(); } } +prefix_ void senf::Scheduler::restart() +{ + scheduler::FdManager* fdm (&scheduler::FdManager::instance()); + scheduler::FIFORunner* ffr (&scheduler::FIFORunner::instance()); + scheduler::FdDispatcher* fdd (&fdDispatcher_); + scheduler::TimerDispatcher* td (&timerDispatcher_); + scheduler::detail::SignalDispatcher* sd (&scheduler::detail::SignalDispatcher::instance()); + scheduler::FileDispatcher* fld (&fileDispatcher_); + + fld->~FileDispatcher(); + sd->~SignalDispatcher(); + td->~TimerDispatcher(); + fdd->~FdDispatcher(); + ffr->~FIFORunner(); + fdm->~FdManager(); + + new (fdm) scheduler::FdManager(); + new (ffr) scheduler::FIFORunner(); + new (fdd) scheduler::FdDispatcher(*fdm, *ffr); + new (td) scheduler::TimerDispatcher(*fdm, *ffr); + new (sd) scheduler::detail::SignalDispatcher(); + new (fld) scheduler::FileDispatcher(*fdm, *ffr); +} + /////////////////////////////////////////////////////////////////////////// // senf::SchedulerLogTimeSource diff --git a/Scheduler/Scheduler.cci b/Scheduler/Scheduler.cci index 5379b6f..94cd693 100644 --- a/Scheduler/Scheduler.cci +++ b/Scheduler/Scheduler.cci @@ -113,16 +113,6 @@ prefix_ void senf::Scheduler::timeoutAdjust(ClockService::clock_type v) ("timeoutAdjust() is deprecated and a no-op. It will be removed") ); } -prefix_ void senf::Scheduler::registerSignal(unsigned signal, SignalCallback const & cb) -{ - signalDispatcher_.add(signal, cb); -} - -prefix_ void senf::Scheduler::unregisterSignal(unsigned signal) -{ - signalDispatcher_.remove(signal); -} - prefix_ void senf::Scheduler::terminate() { terminate_ = true; @@ -131,32 +121,31 @@ prefix_ void senf::Scheduler::terminate() prefix_ senf::ClockService::clock_type senf::Scheduler::eventTime() const { - return manager_.eventTime(); + return scheduler::FdManager::instance().eventTime(); } prefix_ void senf::Scheduler::taskTimeout(unsigned ms) { - runner_.taskTimeout(ms); + scheduler::FIFORunner::instance().taskTimeout(ms); } prefix_ unsigned senf::Scheduler::taskTimeout() const { - return runner_.taskTimeout(); + return scheduler::FIFORunner::instance().taskTimeout(); } prefix_ unsigned senf::Scheduler::hangCount() const { - return runner_.hangCount(); + return scheduler::FIFORunner::instance().hangCount(); } prefix_ senf::Scheduler::Scheduler() : terminate_ (false), - fdDispatcher_ (manager_, runner_), - timerDispatcher_ (manager_, runner_), - signalDispatcher_ (manager_, runner_), - fileDispatcher_ (manager_, runner_) + fdDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()), + timerDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()), + fileDispatcher_ (scheduler::FdManager::instance(), scheduler::FIFORunner::instance()) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index 4a7a74d..7c4dbcb 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -31,7 +31,7 @@ #include "../Utils/Logger/SenfLog.hh" #include "FdDispatcher.hh" #include "TimerDispatcher.hh" -#include "SignalDispatcher.hh" +#include "SignalEvent.hh" #include "FileDispatcher.hh" #include "../Utils/Logger/SenfLog.hh" @@ -282,20 +282,6 @@ namespace senf { ///\} - ///\name Signal handlers - ///\{ - - void registerSignal(unsigned signal, SignalCallback const & cb); - ///< Add signal handler - /**< \param[in] signal signal number to register handler for - \param[in] cb callback to call whenever \a signal is - delivered. */ - - void unregisterSignal(unsigned signal); - ///< Remove signal handler for \a signal - - ///\} - void process(); ///< Event handler main loop /**< This member must be called at some time to enter the event handler main loop. Only while this function is @@ -318,6 +304,8 @@ namespace senf { unsigned taskTimeout() const; unsigned hangCount() const; + void restart(); + protected: private: @@ -329,12 +317,9 @@ namespace senf { void do_remove(int fd, int eventMask); bool terminate_; - scheduler::FdManager manager_; - scheduler::FIFORunner runner_; scheduler::FdDispatcher fdDispatcher_; scheduler::TimerDispatcher timerDispatcher_; - scheduler::SignalDispatcher signalDispatcher_; scheduler::FileDispatcher fileDispatcher_; }; diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index b45b1a3..3bd241d 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -265,6 +265,7 @@ BOOST_AUTO_UNIT_TEST(testScheduler) BOOST_CHECK( timeoutCalled ); BOOST_CHECK_EQUAL( event, Scheduler::EV_NONE ); + BOOST_WARN_MESSAGE( false, "A 'Scheduler task hanging' error is expected to be signaled here." ); BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(ClockService::now(), &blockingHandler) ); BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); BOOST_CHECK_EQUAL( Scheduler::instance().hangCount(), 1u ); @@ -291,15 +292,18 @@ BOOST_AUTO_UNIT_TEST(testScheduler) unsigned tid (Scheduler::instance().timeout( ClockService::now()+ClockService::milliseconds(400),&timeout)); - BOOST_CHECK_NO_THROW( Scheduler::instance().registerSignal(SIGUSR1, &sigusr) ); - t = ClockService::now(); - ::kill(::getpid(), SIGUSR1); - delay(100); + { + senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr); + + t = ClockService::now(); + ::kill(::getpid(), SIGUSR1); + delay(100); + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) ); + BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) ); + } BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) ); - BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) ); - Scheduler::instance().cancelTimeout(tid); - BOOST_CHECK_NO_THROW( Scheduler::instance().unregisterSignal(SIGUSR1) ); + BOOST_CHECK_NO_THROW( Scheduler::instance().cancelTimeout(tid) ); /////////////////////////////////////////////////////////////////////////// diff --git a/Scheduler/SignalDispatcher.hh b/Scheduler/SignalDispatcher.hh deleted file mode 100644 index 2c2b7ae..0000000 --- a/Scheduler/SignalDispatcher.hh +++ /dev/null @@ -1,133 +0,0 @@ -// $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 Scheduler dispatcher managing UNIX signals - - This dispatcher supports registering UNIX signals with the Scheduler. - - \implementation SignalDispatcher provides a single signal handler which all registered - signals are assigned to. When a signal is received, data is written to a pipe which has - been added to the FdManager and this signals the event. - - \todo Add signal block/unblock management to the FdManager to reduce the number of - setprocmask() calls - */ - class SignalDispatcher - : public FdManager::Event - { - public: - /////////////////////////////////////////////////////////////////////////// - // Types - - typedef boost::function Callback; - - /////////////////////////////////////////////////////////////////////////// - ///\name Structors and default members - ///@{ - - SignalDispatcher(FdManager & manager, FIFORunner & runner); - ~SignalDispatcher(); - - ///@} - /////////////////////////////////////////////////////////////////////////// - - void add(int signal, Callback const & cb); ///< Add signal event - /**< \param[in] signal signal number - \param[in] cb Callback */ - - void remove(int signal); ///< Unregister signal event - - void unblockSignals(); ///< Unblock registered signals - /**< Must be called before waiting for an event */ - void blockSignals(); ///< Block registered signals - /**< Must be called directly after FdManager returns */ - - bool empty() const; ///< \c true, if no signal is registered. - - protected: - - private: - ///< Internal: UNIX signal event - struct SignalEvent - : public FIFORunner::TaskInfo - { - SignalEvent(int signal, Callback cb_); - 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.cc b/Scheduler/SignalEvent.cc similarity index 54% rename from Scheduler/SignalDispatcher.cc rename to Scheduler/SignalEvent.cc index 69d72bc..f083852 100644 --- a/Scheduler/SignalDispatcher.cc +++ b/Scheduler/SignalEvent.cc @@ -23,107 +23,105 @@ /** \file \brief SignalDispatcher non-inline non-template implementation */ -#include "SignalDispatcher.hh" -//#include "SignalDispatcher.ih" +#include "SignalEvent.hh" +#include "SignalEvent.ih" // Custom includes #include "../Utils/senfassert.hh" +#include "../Utils/signalnames.hh" -//#include "SignalDispatcher.mpp" +//#include "SignalEvent.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) +prefix_ senf::scheduler::detail::SignalDispatcher::SignalDispatcher() + : blocked_ (true) { - SENF_ASSERT( !instance_ ); if (pipe(sigPipe_) <0) SENF_THROW_SYSTEM_EXCEPTION("pipe()"); sigemptyset(&sigSet_); - instance_ = this; - manager_.set(sigPipe_[0], FdManager::EV_READ, this); + FdManager::instance().set(sigPipe_[0], FdManager::EV_READ, this); } -prefix_ senf::scheduler::SignalDispatcher::~SignalDispatcher() +prefix_ senf::scheduler::detail::SignalDispatcher::~SignalDispatcher() { - for (HandlerMap::iterator i (handlers_.begin()); i != handlers_.end(); ++i) { - ::signal(i->first, SIG_DFL); - runner_.dequeue(&i->second); + for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) { + ::signal(i->signal_, SIG_DFL); + FIFORunner::instance().dequeue(&(*i)); } sigprocmask(SIG_UNBLOCK, &sigSet_, 0); - manager_.remove(sigPipe_[0]); + FdManager::instance().remove(sigPipe_[0]); close(sigPipe_[0]); close(sigPipe_[1]); - instance_ = 0; } -prefix_ void senf::scheduler::SignalDispatcher::add(int signal, Callback const & cb) +prefix_ void senf::scheduler::detail::SignalDispatcher::add(SignalEvent & event) { - HandlerMap::iterator i (handlers_.find(signal)); - if (i != handlers_.end()) { - i->second.cb = cb; - return; - } + SignalSet::iterator i (handlers_.find(event)); + if (i != handlers_.end()) + throw DuplicateSignalRegistrationException() + << " for signal " << signalName(event.signal_) << " (" << event.signal_ << ")"; - i = handlers_.insert(std::make_pair(signal, SignalEvent(signal, cb))).first; - sigaddset(&sigSet_, signal); - runner_.enqueue(&i->second); + handlers_.insert(event); + sigaddset(&sigSet_, event.signal_); + FIFORunner::instance().enqueue(&event); sigset_t sig; sigemptyset(&sig); - sigaddset(&sig, signal); + sigaddset(&sig, event.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) + struct sigaction act; + act.sa_sigaction = &sigHandler; + act.sa_mask = sigSet_; + act.sa_flags = SA_SIGINFO | SA_RESTART; + for (SignalSet::iterator i (handlers_.begin()); i != handlers_.end(); ++i) { + if (i->signal_ == SIGCLD) act.sa_flags |= SA_NOCLDSTOP; - if (sigaction(j->first, &act, 0) < 0) + else + act.sa_flags &= ~SA_NOCLDSTOP; + if (sigaction(i->signal_, &act, 0) < 0) SENF_THROW_SYSTEM_EXCEPTION("sigaction()"); } } -prefix_ void senf::scheduler::SignalDispatcher::remove(int signal) +prefix_ void senf::scheduler::detail::SignalDispatcher::remove(SignalEvent & event) { - ::signal(signal, SIG_DFL); + ::signal(event.signal_, SIG_DFL); + FIFORunner::instance().dequeue(&event); + handlers_.erase(event); sigset_t sig; sigemptyset(&sig); - sigaddset(&sig, signal); + sigaddset(&sig, event.signal_); sigprocmask(SIG_UNBLOCK, &sig, 0); } -prefix_ void senf::scheduler::SignalDispatcher::signal(int events) +prefix_ void senf::scheduler::detail::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)); + SignalSet::iterator i (handlers_.find(info.si_signo, FindNumericSignal())); if (i == handlers_.end()) return; - i->second.siginfo = info; - i->second.runnable = true; + i->siginfo_ = info; + i->runnable = true; } -prefix_ void senf::scheduler::SignalDispatcher::sigHandler(int signal, ::siginfo_t * siginfo, +prefix_ void senf::scheduler::detail::SignalDispatcher::sigHandler(int signal, ::siginfo_t * siginfo, void *) { - SENF_ASSERT( instance_ ); + SENF_ASSERT( alive() ); // 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)); + write(instance().sigPipe_[1], siginfo, sizeof(*siginfo)); } ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ -//#include "SignalDispatcher.mpp" +//#include "SignalEvent.mpp" // Local Variables: diff --git a/Scheduler/SignalDispatcher.cci b/Scheduler/SignalEvent.cci similarity index 56% rename from Scheduler/SignalDispatcher.cci rename to Scheduler/SignalEvent.cci index 84fe9ab..3a0407e 100644 --- a/Scheduler/SignalDispatcher.cci +++ b/Scheduler/SignalEvent.cci @@ -23,47 +23,84 @@ /** \file \brief SignalDispatcher inline non-template implementation */ -//#include "SignalDispatcher.ih" +#include "SignalEvent.ih" // Custom includes #include #include "../Utils/signalnames.hh" +#include "../Utils/senfassert.hh" #define prefix_ inline ///////////////////////////////cci.p/////////////////////////////////////// -prefix_ void senf::scheduler::SignalDispatcher::blockSignals() +prefix_ void senf::scheduler::detail::SignalDispatcher::blockSignals() { if (blocked_) return; sigprocmask(SIG_BLOCK, &sigSet_, 0); blocked_ = true; } -prefix_ void senf::scheduler::SignalDispatcher::unblockSignals() +prefix_ void senf::scheduler::detail::SignalDispatcher::unblockSignals() { if (!blocked_) return; sigprocmask(SIG_UNBLOCK, &sigSet_, 0); blocked_ = false; } -prefix_ bool senf::scheduler::SignalDispatcher::empty() +prefix_ bool senf::scheduler::detail::SignalDispatcher::empty() const { return handlers_.empty(); } /////////////////////////////////////////////////////////////////////////// -// senf::scheduler::SignalDispatcher::SignalEvent +// senf::scheduler::SignalEvent -prefix_ senf::scheduler::SignalDispatcher::SignalEvent::SignalEvent(int signal, Callback cb_) - : cb (cb_) +prefix_ senf::scheduler::SignalEvent::SignalEvent(int signal, Callback cb, + bool initiallyEnabled) + : signal_ (signal), enabled_ (initiallyEnabled), cb_ (cb) { name = signalName(signal); + if (enabled_) + senf::scheduler::detail::SignalDispatcher::instance().add(*this); } -prefix_ void senf::scheduler::SignalDispatcher::SignalEvent::run() +prefix_ senf::scheduler::SignalEvent::~SignalEvent() { - cb(siginfo); + if (senf::scheduler::detail::SignalDispatcher::alive()) + senf::scheduler::detail::SignalDispatcher::instance().remove(*this); +} + +prefix_ void senf::scheduler::SignalEvent::disable() +{ + if (enabled_) { + senf::scheduler::detail::SignalDispatcher::instance().remove(*this); + enabled_ = false; + } +} + +prefix_ void senf::scheduler::SignalEvent::enable() +{ + if (! enabled_) { + senf::scheduler::detail::SignalDispatcher::instance().add(*this); + enabled_ = true; + } +} + +prefix_ bool senf::scheduler::SignalEvent::enabled() + const +{ + return enabled_; +} + +prefix_ void senf::scheduler::SignalEvent::action(Callback cb) +{ + cb_ = cb; +} + +prefix_ void senf::scheduler::SignalEvent::run() +{ + cb_(siginfo_); } ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/Scheduler/SignalEvent.hh b/Scheduler/SignalEvent.hh new file mode 100644 index 0000000..a21c460 --- /dev/null +++ b/Scheduler/SignalEvent.hh @@ -0,0 +1,129 @@ +// $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 "FIFORunner.hh" +#include "../boost/intrusive/iset_hook.hpp" + +//#include "SignalEvent.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { + + class Scheduler; + +namespace scheduler { + + namespace detail { + struct SignalSetTag; + typedef boost::intrusive::iset_base_hook SignalSetBase; + struct SignalSetCompare; + struct FindNumericSignal; + struct SignalDispatcher; + } + + /** \brief UNIX signal event + + The SignalEvent class registers a callback for UNIX signals. The callback will be called \e + synchronously (not from within the UNIX signal handler) by the scheduler. + + The SignalEvent class is an implementation of the RAII idiom: The event will be + automatically unregistered in the SignalEvent destructor. The SignalEvent instance should be + created within the same scope or on a scope below where the callback is defined (e.g. if the + callback is a member function it should be defined as a class member). + */ + class SignalEvent + : public FIFORunner::TaskInfo, + public detail::SignalSetBase + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::function Callback; + ///< Callback type + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + SignalEvent(int signal, Callback cb, bool initiallyEnabled=true); + ///< Register a signal event + /**< Registers \a cb as callback for the UNIX signal \a + signal. If \a initiallyEnabled is set \c false, the + callback will not be enabled automatically. Use + enable() to do so. + \param[in] signal UNIX signal to register callback for + \param[in] cb Callback to call + \param[in] initiallyEnabled if set \c false, do not + enable callback automatically. */ + ~SignalEvent(); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + void disable(); ///< Enable signal event registration + void enable(); ///< Disable the signal event registration + bool enabled() const; ///< \c true, if event enabled, \c false otherwise + void action(Callback cb); ///< Change signal event callback + + private: + virtual void run(); + + int signal_; + bool enabled_; + Callback cb_; + siginfo_t siginfo_; + + friend class detail::SignalSetCompare; + friend class detail::FindNumericSignal; + friend class detail::SignalDispatcher; + friend class senf::Scheduler; + }; + + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "SignalEvent.cci" +//#include "SignalEvent.ct" +//#include "SignalEvent.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/SignalEvent.ih b/Scheduler/SignalEvent.ih new file mode 100644 index 0000000..7e96134 --- /dev/null +++ b/Scheduler/SignalEvent.ih @@ -0,0 +1,114 @@ +// $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 internal header */ + +#ifndef IH_SignalDispatcher_ +#define IH_SignalDispatcher_ 1 + +// Custom includes +#include "FdManager.hh" +#include "../boost/intrusive/iset.hpp" +#include "../Utils/Exception.hh" +#include "../Utils/singleton.hh" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { + + class Scheduler; + +namespace scheduler { +namespace detail { + + struct SignalSetCompare { + bool operator()(SignalEvent const & a, SignalEvent const & b) const + { return a.signal_ < b.signal_; } + }; + + struct FindNumericSignal { + bool operator()(SignalEvent const & a, int b) const + { return a.signal_ < b; } + bool operator()(int a, SignalEvent const & b) const + { return a < b.signal_; } + }; + + class SignalDispatcher + : public FdManager::Event, + public singleton + { + typedef boost::intrusive::iset< SignalSetBase::value_traits, + SignalSetCompare, + false > SignalSet; + public: + using singleton::instance; + using singleton::alive; + + void add(SignalEvent & event); + void remove(SignalEvent & event); + + void unblockSignals(); + void blockSignals(); + + bool empty() const; + + struct DuplicateSignalRegistrationException : public Exception + { DuplicateSignalRegistrationException() + : Exception("duplicate signal registration") {} }; + + protected: + + private: + SignalDispatcher(); + ~SignalDispatcher(); + + virtual void signal(int events); + static void sigHandler(int signal, ::siginfo_t * siginfo, void *); + + SignalSet handlers_; + + int sigPipe_[2]; + + bool blocked_; + sigset_t sigSet_; + + friend class senf::scheduler::SignalEvent; + friend class singleton; + friend class senf::Scheduler; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#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/SignalEvent.test.cc similarity index 67% rename from Scheduler/SignalDispatcher.test.cc rename to Scheduler/SignalEvent.test.cc index 7531aae..d579acb 100644 --- a/Scheduler/SignalDispatcher.test.cc +++ b/Scheduler/SignalEvent.test.cc @@ -21,13 +21,13 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief SignalDispatcher.test unit tests */ + \brief SignalEvent.test unit tests */ -//#include "SignalDispatcher.test.hh" -//#include "SignalDispatcher.test.ih" +//#include "SignalEvent.test.hh" +//#include "SignalEvent.test.ih" // Custom includes -#include "SignalDispatcher.hh" +#include "SignalEvent.hh" #include "../Utils/auto_unit_test.hh" #include @@ -45,32 +45,25 @@ namespace { } -#if 0 -// We can't test this when testing the Scheduler since the Scheduler instance -// already uses the only SignalDispatcher instance allowed ... - BOOST_AUTO_UNIT_TEST(signalDispatcher) { - senf::scheduler::FdManager manager; - senf::scheduler::FIFORunner runner; - senf::scheduler::SignalDispatcher dispatcher (manager, runner); - manager.timeout(1000); + senf::scheduler::FdManager::instance().timeout(1000); + senf::scheduler::SignalEvent sig (SIGUSR1, &handler); - SENF_CHECK_NO_THROW( dispatcher.add(SIGUSR1, &handler) ); + SENF_CHECK_NO_THROW( sig.disable() ); + SENF_CHECK_NO_THROW( sig.enable() ); + SENF_CHECK_NO_THROW( sig.action(&handler) ); + BOOST_CHECK( sig.enabled() ); 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() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::SignalDispatcher::instance().unblockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::detail::SignalDispatcher::instance().blockSignals() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK( called ); - - SENF_CHECK_NO_THROW( dispatcher.remove(SIGUSR1) ); } -#endif - ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ diff --git a/Scheduler/TimerDispatcher.test.cc b/Scheduler/TimerDispatcher.test.cc index 9f0599c..2795a8a 100644 --- a/Scheduler/TimerDispatcher.test.cc +++ b/Scheduler/TimerDispatcher.test.cc @@ -52,19 +52,17 @@ namespace { BOOST_AUTO_UNIT_TEST(timerDispatcher) { - senf::scheduler::FdManager manager; - senf::scheduler::FIFORunner runner; - senf::scheduler::TimerDispatcher dispatcher (manager, runner); - manager.timeout(1000); + senf::scheduler::TimerDispatcher dispatcher (senf::scheduler::FdManager::instance(), senf::scheduler::FIFORunner::instance()); + senf::scheduler::FdManager::instance().timeout(1000); senf::ClockService::clock_type t (senf::ClockService::now()); senf::scheduler::TimerDispatcher::timer_id id; SENF_CHECK_NO_THROW( id = dispatcher.add( "testTimer", t + senf::ClockService::milliseconds(500), &handler ) ); SENF_CHECK_NO_THROW( dispatcher.unblockSignals() ); - SENF_CHECK_NO_THROW( manager.processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); SENF_CHECK_NO_THROW( dispatcher.blockSignals() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); senf::ClockService::clock_type t2 (senf::ClockService::now()); BOOST_CHECK( called ); BOOST_CHECK_PREDICATE( is_close, (t2-t)(senf::ClockService::milliseconds(500)) ); @@ -75,9 +73,9 @@ BOOST_AUTO_UNIT_TEST(timerDispatcher) t = senf::ClockService::now(); SENF_CHECK_NO_THROW( dispatcher.add( "testTimer", t, &handler ) ); SENF_CHECK_NO_THROW( dispatcher.unblockSignals() ); - SENF_CHECK_NO_THROW( manager.processOnce() ); + SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() ); SENF_CHECK_NO_THROW( dispatcher.blockSignals() ); - SENF_CHECK_NO_THROW( runner.run() ); + SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() ); BOOST_CHECK_PREDICATE( is_close, (t) (senf::ClockService::now()) ); BOOST_CHECK( called ); } diff --git a/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index 708faca..19673af 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -377,6 +377,8 @@ prefix_ void senf::Daemon::fork() LIBC_CALL( ::close, (cerrpipe[1]) ); LIBC_CALL( ::setsid, () ); LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) ); + + senf::Scheduler::instance().restart(); return; } @@ -386,6 +388,8 @@ prefix_ void senf::Daemon::fork() LIBC_CALL( ::close, (coutpipe[1]) ); LIBC_CALL( ::close, (cerrpipe[1]) ); + senf::Scheduler::instance().restart(); + detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_); watcher.run(); @@ -558,6 +562,7 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce int stdout, int stderr) : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout), stderr_(stderr), sigChld_(false), + cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)), coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) { @@ -571,7 +576,6 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce prefix_ void senf::detail::DaemonWatcher::run() { - Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)); Scheduler::instance().process(); } @@ -588,8 +592,8 @@ prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id) if (coutpipe_ == -1 && cerrpipe_ == -1) { if (sigChld_) childDied(); // does not return - if (::kill(childPid_, SIGUSR1) < 0) - if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()"); + if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH) + SENF_THROW_SYSTEM_EXCEPTION("::kill()"); Scheduler::instance().timeout( Scheduler::instance().eventTime() + ClockService::seconds(1), senf::membind(&DaemonWatcher::childOk, this)); @@ -611,10 +615,10 @@ prefix_ void senf::detail::DaemonWatcher::childDied() ::signal(WTERMSIG(status),SIG_DFL); ::kill(::getpid(), WTERMSIG(status)); // should not be reached - ::_exit(1); + ::_exit(126); } if (WEXITSTATUS(status) == 0) - ::_exit(1); + ::_exit(127); ::_exit(WEXITSTATUS(status)); } diff --git a/Utils/Daemon/Daemon.ih b/Utils/Daemon/Daemon.ih index 0cc5c17..3dec5e2 100644 --- a/Utils/Daemon/Daemon.ih +++ b/Utils/Daemon/Daemon.ih @@ -32,6 +32,7 @@ #include #include #include "../../Scheduler/Scheduler.hh" +#include "../../Scheduler/SignalEvent.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -93,6 +94,7 @@ namespace detail { int stderr_; bool sigChld_; + scheduler::SignalEvent cldSignal_; Forwarder coutForwarder_; Forwarder cerrForwarder_; }; diff --git a/Utils/Daemon/Daemon.test.cc b/Utils/Daemon/Daemon.test.cc index 7591434..cdf74b8 100644 --- a/Utils/Daemon/Daemon.test.cc +++ b/Utils/Daemon/Daemon.test.cc @@ -36,6 +36,7 @@ #include "Daemon.hh" #include "../Utils/Exception.hh" #include "../Utils/Backtrace.hh" +#include "../Scheduler/Scheduler.hh" #include "../Utils/auto_unit_test.hh" #include @@ -100,11 +101,17 @@ namespace { } catch (...) { std::cerr << "Unexpected exception" << std::endl; } - ::_exit(2); + ::_exit(125); } int status; - if (::waitpid(pid, &status, 0) < 0) throw senf::SystemException("::waitpid()"); - return WIFEXITED(status) ? WEXITSTATUS(status) : -1; + if (::waitpid(pid, &status, 0) < 0) + throw senf::SystemException("::waitpid()"); + if (WIFSIGNALED(status)) + std::cerr << "Terminated with signal " + << senf::signalName(WTERMSIG(status)) << "(" << WTERMSIG(status) << ")\n"; + else if (WIFEXITED(status)) + std::cerr << "Exited normally with exit status " << WEXITSTATUS(status) << "\n"; + return status; } } @@ -112,28 +119,29 @@ namespace { BOOST_AUTO_UNIT_TEST(testDaemon) { char * args[] = { "run", - "--console-log=testDaemon.log,none", + "--console-log=testDaemon.log", "--pid-file=testDaemon.pid" }; BOOST_CHECK_EQUAL( run(sizeof(args)/sizeof(*args),args), 0 ); BOOST_CHECK( ! boost::filesystem::exists("invalid.log") ); BOOST_CHECK( ! boost::filesystem::exists("invalid.pid") ); - BOOST_REQUIRE( boost::filesystem::exists("testDaemon.pid") ); + BOOST_CHECK( boost::filesystem::exists("testDaemon.pid") ); BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log") ); boost::filesystem::rename("testDaemon.log", "testDaemon.log.1"); { std::ifstream pidFile ("testDaemon.pid"); int pid (0); - BOOST_REQUIRE( pidFile >> pid ); - BOOST_REQUIRE( pid != 0 ); - ::kill(pid, SIGHUP); + BOOST_CHECK( pidFile >> pid ); + BOOST_CHECK( pid != 0 ); + if (pid != 0) + ::kill(pid, SIGHUP); } delay(1000); BOOST_CHECK( ! boost::filesystem::exists("testDaemon.pid") ); BOOST_CHECK( boost::filesystem::exists("testDaemon.log") ); - BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log.1") ); + BOOST_CHECK( boost::filesystem::exists("testDaemon.log.1") ); std::ifstream log ("testDaemon.log.1"); std::stringstream data; diff --git a/Utils/singleton.cti b/Utils/singleton.cti index d124468..79dd1f7 100644 --- a/Utils/singleton.cti +++ b/Utils/singleton.cti @@ -31,6 +31,21 @@ ///////////////////////////////cti.p/////////////////////////////////////// template +prefix_ senf::singleton::singleton() +{ + alive_ = true; +} + +template +prefix_ senf::singleton::~singleton() +{ + alive_ = false; +} + +template +bool senf::singleton::alive_ (false); + +template prefix_ Self & senf::singleton::instance() { static Self instance_; @@ -40,6 +55,12 @@ prefix_ Self & senf::singleton::instance() } template +prefix_ bool senf::singleton::alive() +{ + return alive_; +} + +template prefix_ senf::singleton::force_creation::force_creation() { // Force execution of instance() thereby creating instance diff --git a/Utils/singleton.hh b/Utils/singleton.hh index 831e812..dce43c0 100644 --- a/Utils/singleton.hh +++ b/Utils/singleton.hh @@ -88,7 +88,11 @@ namespace senf { : boost::noncopyable { protected: + singleton(); + ~singleton(); + static Self & instance(); ///< Return singleton instance + static bool alive(); ///< Return \c true, if instance ok, \c false otherwise private: /** \brief Internal @@ -101,6 +105,7 @@ namespace senf { }; static force_creation creator_; + static bool alive_; }; } diff --git a/Utils/singleton.test.cc b/Utils/singleton.test.cc index 2d1fedd..781d434 100644 --- a/Utils/singleton.test.cc +++ b/Utils/singleton.test.cc @@ -27,6 +27,7 @@ //#include "singleton.test.ih" // Custom includes +#include #include "singleton.hh" #include "../Utils/auto_unit_test.hh" @@ -47,6 +48,7 @@ namespace { public: using senf::singleton::instance; + using senf::singleton::alive; int foo() { return foo_; } }; @@ -55,6 +57,73 @@ namespace { BOOST_AUTO_UNIT_TEST(sInGlEtOn) { BOOST_CHECK_EQUAL( Test::instance().foo(), 1234 ); + BOOST_CHECK( Test::alive() ); +} + +namespace { + + bool test1Dead (false); + bool test2Dead (false); + + bool test1Alive (false); + bool test2Alive (false); + + struct AliveTest1 : public senf::singleton + { + friend class senf::singleton; + using senf::singleton::alive; + using senf::singleton::instance; + AliveTest1(); + ~AliveTest1(); + }; + + struct AliveTest2 : public senf::singleton + { + friend class senf::singleton; + using senf::singleton::alive; + using senf::singleton::instance; + AliveTest2(); + ~AliveTest2(); + }; + + AliveTest1::AliveTest1() + { + test2Alive = AliveTest2::alive(); + } + + AliveTest1::~AliveTest1() + { + if (test2Dead) { + assert( ! AliveTest2::alive() ); + std::cerr << "singleton alive test ok\n"; + } + test1Dead = true; + } + + AliveTest2::AliveTest2() + { + test1Alive = AliveTest1::alive(); + } + + AliveTest2::~AliveTest2() + { + if (test1Dead) { + assert( ! AliveTest1::alive() ); + std::cerr << "singleton alive test ok\n"; + } + test2Dead = true; + } + +} + +BOOST_AUTO_UNIT_TEST(singletonAlive) +{ + (void) AliveTest1::instance(); + (void) AliveTest2::instance(); + + BOOST_CHECK( (test1Alive && !test2Alive) || (!test1Alive && test2Alive) ); + BOOST_CHECK( AliveTest1::alive() ); + BOOST_CHECK( AliveTest2::alive() ); } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/senfscons/CompileCheck.py b/senfscons/CompileCheck.py index 34d3617..f1037f6 100644 --- a/senfscons/CompileCheck.py +++ b/senfscons/CompileCheck.py @@ -1,4 +1,5 @@ import os, os.path, sys +from cStringIO import StringIO from SCons.Script import * import SCons.Scanner.C @@ -14,13 +15,18 @@ def scanTests(f): elif line.startswith('}') and name and start: tests[name] = (start, linenr) return tests - + def CompileCheck(target, source, env): tests = scanTests(file(source[0].abspath)) - errf = os.popen(env.subst('$CXXCOM -DCOMPILE_CHECK 2>&1', source=source, target=target)) + cenv = env.Clone() + cenv.Append( CPPDEFINES = { 'COMPILE_CHECK': '' } ) + out = StringIO() + cenv['SPAWN'] = lambda sh, escape, cmd, args, env, pspawn=cenv['PSPAWN'], out=out: \ + pspawn(sh, escape, cmd, args, env, out, out) + Action('$CXXCOM').execute(target, source, cenv) passedTests = {} delay_name = None - for error in errf: + for error in out.getvalue().splitlines(): elts = error.split(':',2) if len(elts) != 3 : continue filename, line, message = elts diff --git a/senfscons/SENFSCons.py b/senfscons/SENFSCons.py index 60e175a..15414fd 100644 --- a/senfscons/SENFSCons.py +++ b/senfscons/SENFSCons.py @@ -253,7 +253,7 @@ def MakeEnvironment(): # The boost-regex library is not compiled with _GLIBCXX_DEBUG so this fails: # CPPDEFINES = [ '_GLIBCXX_DEBUG' ], env.Append(CXXFLAGS = [ '-O0', '-g' ], - CPPDEFINES = [ 'SENF_DEBUG' ], + CPPDEFINES = { 'SENF_DEBUG': ''}, LINKFLAGS = [ '-g', '-rdynamic' ]) env.Append(CPPDEFINES = [ '$EXTRA_DEFINES' ], diff --git a/senfscons/senfutil.py b/senfscons/senfutil.py index 249a78d..c704a1f 100644 --- a/senfscons/senfutil.py +++ b/senfscons/senfutil.py @@ -23,7 +23,7 @@ def SetupForSENF(env): def parseLogOption(value): stream, area, level = ( x.strip() for x in value.strip().split('|') ) stream = ''.join('(%s)' % x for x in stream.split('::') ) - if area : area = ''.join( '(%s)' % x for x in elts[1].split('::') ) + if area : area = ''.join( '(%s)' % x for x in area.split('::') ) else : area = '(_)' return '(( %s,%s,%s ))' % (stream,area,level)