'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"
)
#include <signal.h>
#include <time.h>
#include "../Utils/Exception.hh"
+#include "../Utils/senfassert.hh"
//#include "FIFORunner.mpp"
#define prefix_
// - 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;
#include <boost/utility.hpp>
#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
is posted for the task.
*/
class FIFORunner
- : boost::noncopyable
+ : public singleton<FIFORunner>
{
public:
struct TaskInfo;
private:
struct TaskListTag;
typedef boost::intrusive::ilist_base_hook<TaskListTag> TaskListBase;
- typedef TaskListBase::value_traits<TaskInfo> TaskListType;
- typedef boost::intrusive::ilist<TaskListType, false> TaskList;
+ typedef boost::intrusive::ilist<TaskListBase::value_traits<TaskInfo>, false> TaskList;
public:
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
- FIFORunner();
- ~FIFORunner();
+ using singleton<FIFORunner>::instance;
+ using singleton<FIFORunner>::alive;
///@}
///////////////////////////////////////////////////////////////////////////
protected:
private:
+ FIFORunner();
+ ~FIFORunner();
+
static void watchdog(int, siginfo_t *, void *);
TaskList tasks_;
# endif
unsigned watchdogCount_;
unsigned hangCount_;
+
+ friend class singleton<FIFORunner>;
+ friend class senf::Scheduler;
};
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 );
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;
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 );
// 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
\implementation
*/
class FdManager
+ : public singleton<FdManager>
{
public:
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
- FdManager();
+ using singleton<FdManager>::instance;
+ using singleton<FdManager>::alive;
///@}
///////////////////////////////////////////////////////////////////////////
protected:
private:
+ FdManager();
+
Poller<Event> poller_;
senf::ClockService::clock_type eventTime_;
+
+ friend class singleton<FdManager>;
+ friend class senf::Scheduler;
};
}}
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,
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()) );
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(
//#include "Scheduler.ih"
// Custom includes
+#include "SignalEvent.hh"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
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
("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;
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///////////////////////////////////////
#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"
///\}
- ///\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
unsigned taskTimeout() const;
unsigned hangCount() const;
+ void restart();
+
protected:
private:
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_;
};
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 );
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) );
///////////////////////////////////////////////////////////////////////////
+++ /dev/null
-// $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 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<void (siginfo_t const &)> 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<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:
/** \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"
\f
// Local Variables:
/** \file
\brief SignalDispatcher inline non-template implementation */
-//#include "SignalDispatcher.ih"
+#include "SignalEvent.ih"
// Custom includes
#include <unistd.h>
#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///////////////////////////////////////
--- /dev/null
+// $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 <boost/function.hpp>
+#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<SignalSetTag> 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<void (siginfo_t const &)> 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
+
+\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:
--- /dev/null
+// $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 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<SignalDispatcher>
+ {
+ typedef boost::intrusive::iset< SignalSetBase::value_traits<SignalEvent>,
+ SignalSetCompare,
+ false > SignalSet;
+ public:
+ using singleton<SignalDispatcher>::instance;
+ using singleton<SignalDispatcher>::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<SignalDispatcher>;
+ friend class senf::Scheduler;
+ };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#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:
// 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 <boost/test/test_tools.hpp>
}
-#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_
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)) );
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 );
}
LIBC_CALL( ::close, (cerrpipe[1]) );
LIBC_CALL( ::setsid, () );
LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
+
+ senf::Scheduler::instance().restart();
return;
}
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();
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))
{
prefix_ void senf::detail::DaemonWatcher::run()
{
- Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
Scheduler::instance().process();
}
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));
::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));
}
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include "../../Scheduler/Scheduler.hh"
+#include "../../Scheduler/SignalEvent.hh"
///////////////////////////////ih.p////////////////////////////////////////
int stderr_;
bool sigChld_;
+ scheduler::SignalEvent cldSignal_;
Forwarder coutForwarder_;
Forwarder cerrForwarder_;
};
#include "Daemon.hh"
#include "../Utils/Exception.hh"
#include "../Utils/Backtrace.hh"
+#include "../Scheduler/Scheduler.hh"
#include "../Utils/auto_unit_test.hh"
#include <boost/test/test_tools.hpp>
} 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;
}
}
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;
///////////////////////////////cti.p///////////////////////////////////////
template <class Self>
+prefix_ senf::singleton<Self>::singleton()
+{
+ alive_ = true;
+}
+
+template <class Self>
+prefix_ senf::singleton<Self>::~singleton()
+{
+ alive_ = false;
+}
+
+template <class Self>
+bool senf::singleton<Self>::alive_ (false);
+
+template <class Self>
prefix_ Self & senf::singleton<Self>::instance()
{
static Self instance_;
}
template <class Self>
+prefix_ bool senf::singleton<Self>::alive()
+{
+ return alive_;
+}
+
+template <class Self>
prefix_ senf::singleton<Self>::force_creation::force_creation()
{
// Force execution of instance() thereby creating instance
: 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
};
static force_creation creator_;
+ static bool alive_;
};
}
//#include "singleton.test.ih"
// Custom includes
+#include <iostream>
#include "singleton.hh"
#include "../Utils/auto_unit_test.hh"
public:
using senf::singleton<Test>::instance;
+ using senf::singleton<Test>::alive;
int foo() { return foo_; }
};
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<AliveTest1>
+ {
+ friend class senf::singleton<AliveTest1>;
+ using senf::singleton<AliveTest1>::alive;
+ using senf::singleton<AliveTest1>::instance;
+ AliveTest1();
+ ~AliveTest1();
+ };
+
+ struct AliveTest2 : public senf::singleton<AliveTest2>
+ {
+ friend class senf::singleton<AliveTest2>;
+ using senf::singleton<AliveTest2>::alive;
+ using senf::singleton<AliveTest2>::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////////////////////////////////////////
import os, os.path, sys
+from cStringIO import StringIO
from SCons.Script import *
import SCons.Scanner.C
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
# 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' ],
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)