inline std::ostream & operator<<(std::ostream & os, Parse_UInt32 const & i)
{ os << i.value(); return os; }
- template <int X, int Y>
- struct ctime_pow {
- static const int result = X * ctime_pow<X,Y-1>::result;
- };
- template<int X>
- struct ctime_pow<X,0> {
- static const int result = 1;
- };
-
/** \brief Parse signed bitfield with up to 32bit's
This parser will parse a bitfield beginning at the bit \a Start and ending \e before \a
static size_type const start_bit = Start;
static size_type const end_bit = End;
static size_type const fixed_bytes = (End-1)/8+1;
- static value_type const min_value = -ctime_pow<2,(End-Start)-1>::result;
- static value_type const max_value = ctime_pow<2,(End-Start)-1>::result - 1;
+ static value_type const max_value = boost::low_bits_mask_t<End-Start-1>::sig_bits;
+ static value_type const min_value = - max_value - 1;
value_type value() const {
static size_type const start_bit = Start;
static size_type const end_bit = End;
static size_type const fixed_bytes = (End-1)/8+1;
- static value_type const min_value = 0;
- static value_type const max_value = ctime_pow<2,(End-Start)>::result - 1;
+ static value_type const min_value = 0u;
+ static value_type const max_value = boost::low_bits_mask_t<End-Start>::sig_bits;
value_type value() const { return detail::packet::parse_bitfield<Start,End>::parse(i()); }
void value(value_type v) { detail::packet::parse_bitfield<Start,End>::write(i(),v); }
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+// 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 Daemon non-inline non-template implementation */
+
+#include "Daemon.hh"
+#include "Daemon.ih"
+
+// Custom includes
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include "../Utils/Exception.hh"
+#include "../Utils/membind.hh"
+
+//#include "Daemon.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+#define LIBC_CALL(fn, args) if (fn args < 0) throwErrno(#fn "()")
+#define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throwErrno(#fn "()")
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Daemon
+
+prefix_ senf::Daemon::~Daemon()
+{}
+
+prefix_ void senf::Daemon::daemonize(bool v)
+{
+ daemonize_ = v;
+}
+
+prefix_ bool senf::Daemon::daemon()
+{
+ return daemonize_;
+}
+
+prefix_ void senf::Daemon::consoleLog(std::string path, StdStream which)
+{
+ int fd (-1);
+ if (! path.empty()) {
+ int fd (::open(path.c_str(), O_WRONLY | O_APPEND));
+ if (fd < 0)
+ throwErrno("::open()");
+ }
+ switch (which) {
+ case StdOut:
+ stdout_ = fd;
+ break;
+ case StdErr:
+ stderr_ = fd;
+ break;
+ case Both:
+ stdout_ = fd;
+ stderr_ = fd;
+ break;
+ }
+}
+
+prefix_ void senf::Daemon::pidFile(std::string f, bool unique)
+{
+ pidfile_ = f;
+ unique_ = unique;
+}
+
+prefix_ void senf::Daemon::detach()
+{
+ LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
+ LIBC_CALL( ::dup2, (nul, 1) );
+ LIBC_CALL( ::dup2, (nul, 2) );
+ LIBC_CALL( ::close, (nul) );
+}
+
+prefix_ int senf::Daemon::start(int argc, char const ** argv)
+{
+ argc_ = argc;
+ argv_ = argv;
+
+# ifdef NDEBUG
+ try {
+# endif
+
+ configure();
+ if (daemonize_)
+ fork();
+ if (! pidfile_.empty())
+ pidfileCreate();
+ main();
+
+# ifdef NDEBUG
+ }
+ catch (std::exception & e) {
+ std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
+ return 1;
+ }
+ catch (...) {
+ std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
+ return 1;
+ }
+# endif
+
+ return 0;
+}
+
+////////////////////////////////////////
+// protected members
+
+prefix_ senf::Daemon::Daemon()
+ : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""), unique_(true),
+ detached_(false)
+{}
+
+////////////////////////////////////////
+// private members
+
+prefix_ void senf::Daemon::configure()
+{}
+
+prefix_ void senf::Daemon::main()
+{
+ init();
+ detach();
+ run();
+}
+
+prefix_ void senf::Daemon::init()
+{}
+
+prefix_ void senf::Daemon::run()
+{}
+
+prefix_ void senf::Daemon::fork()
+{
+ int coutpipe[2];
+ int cerrpipe[2];
+
+ LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
+ LIBC_CALL( ::dup2, (nul, 0) );
+ LIBC_CALL( ::close, (nul) );
+ LIBC_CALL( ::pipe, (coutpipe) );
+ LIBC_CALL( ::pipe, (cerrpipe) );
+
+ // We need to block the SIGCHLD signal here so we don't miss it, if the child
+ // dies immediately
+ ::sigset_t oldsig;
+ ::sigset_t cldsig;
+ ::sigemptyset(&cldsig);
+ LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
+ LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
+
+ LIBC_CALL_RV( pid, ::fork, () );
+
+ if (pid == 0) {
+ // Daemon process
+
+ LIBC_CALL( ::dup2, (coutpipe[1],1) );
+ LIBC_CALL( ::dup2, (cerrpipe[1],2) );
+ LIBC_CALL( ::close, (coutpipe[0]) );
+ LIBC_CALL( ::close, (coutpipe[1]) );
+ LIBC_CALL( ::close, (cerrpipe[0]) );
+ LIBC_CALL( ::close, (cerrpipe[1]) );
+ LIBC_CALL( ::setsid, () );
+ LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
+ return;
+ }
+
+ LIBC_CALL( ::close, (coutpipe[1]) );
+ LIBC_CALL( ::close, (cerrpipe[1]) );
+
+ detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0]);
+ watcher.run();
+
+ ::exit(0);
+
+}
+
+prefix_ void senf::Daemon::pidfileCreate()
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::DaemonWatcher
+
+prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe)
+ : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe),
+ coutForwarder_(coutpipe_, 1, senf::membind(&DaemonWatcher::pipeClosed, this)),
+ cerrForwarder_(cerrpipe_, 2, senf::membind(&DaemonWatcher::pipeClosed, this))
+{}
+
+prefix_ void senf::detail::DaemonWatcher::run()
+{
+ Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::childDied, this));
+ Scheduler::instance().process();
+}
+
+////////////////////////////////////////
+// private members
+
+prefix_ void senf::detail::DaemonWatcher::pipeClosed()
+{
+ if (! timerRunning_) {
+ Scheduler::instance().timeout(Scheduler::instance().eventTime() + ClockService::seconds(1),
+ senf::membind(&DaemonWatcher::childOk, this));
+ timerRunning_ = true;
+ }
+}
+
+prefix_ void senf::detail::DaemonWatcher::childDied()
+{
+ int status (0);
+ if (::waitpid(childPid_,&status,0) < 0) throwErrno("::waitpid()");
+ if (WIFSIGNALED(status)) {
+ ::signal(WTERMSIG(status),SIG_DFL);
+ ::kill(::getpid(), WTERMSIG(status));
+ // should not be reached
+ ::exit(1);
+ }
+ if (WEXITSTATUS(status) == 0)
+ ::exit(1);
+ ::exit(WEXITSTATUS(status));
+}
+
+prefix_ void senf::detail::DaemonWatcher::childOk()
+{
+ Scheduler::instance().terminate();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::DaemonWatcher::Forwarder
+
+prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, int dst, Callback cb)
+ : src_(src), dst_(dst), cb_(cb)
+{
+ Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
+ Scheduler::EV_READ);
+}
+
+prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
+{
+ if (src_ != -1)
+ Scheduler::instance().remove(src_);
+ if (dst_ != -1 && ! buffer_.empty())
+ Scheduler::instance().remove(dst_);
+}
+
+prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
+{
+ char buf[1024];
+ int n (0);
+ while (1) {
+ n = ::read(src_,buf,1024);
+ if (n<0) {
+ if (errno != EINTR) throwErrno("::read()");
+ } else
+ break;
+ }
+ if (n == 0) {
+ // Hangup
+ Scheduler::instance().remove(src_);
+ if (buffer_.empty())
+ cb_();
+ src_ = -1;
+ return;
+ }
+ if (dst_ == -1)
+ // There was an error writing data -> drop it
+ return;
+ if (buffer_.empty())
+ Scheduler::instance().add(dst_, senf::membind(&Forwarder::writeData, this),
+ Scheduler::EV_WRITE);
+ buffer_.insert(buffer_.end(), buf, buf+n);
+}
+
+prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event)
+{
+ if (event != Scheduler::EV_WRITE) {
+ // Broken pipe while writing data ? Not much, we can do here, we just drop the data
+ Scheduler::instance().remove(dst_);
+ dst_ = -1;
+ if (src_ == -1) cb_();
+ return;
+ }
+ char buf[1024];
+ int n (buffer_.size() > 1024 ? 1024 : buffer_.size());
+ std::copy(buffer_.begin(), buffer_.begin() + n, buf);
+ int w (::write(dst_, buf, n));
+ if (w < 0) {
+ if (errno != EINTR) throwErrno("::write()");
+ return;
+ }
+ buffer_.erase(buffer_.begin(), buffer_.begin()+w);
+ if (buffer_.empty()) {
+ Scheduler::instance().remove(dst_);
+ if (src_ == -1)
+ cb_();
+ }
+}
+
+#undef LIBC_CALL
+#undef LIBC_CALL_RV
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "Daemon.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+// 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 Daemon public header */
+
+#ifndef HH_Daemon_
+#define HH_Daemon_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+
+//#include "Daemon.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \brief Daemon process
+
+ This class provides the infrastructure to implement robust daemon processes. A daemon
+ process is implemented by deriving from senf::Daemon and implementing the necessary
+ (virtual) member functions.
+ \code
+ class MyDaemon : public senf::Daemon
+ {
+ void configure() {
+ // Set configuration parameters like daemonize(), pidFile() etc.
+ }
+
+ void init() {
+ // Initialize application. Setup all necessary objects. After init()
+ // has completed, is startup should not fail anymore
+ }
+
+ void run() {
+ // Main application code should be called here.
+ }
+ };
+ \endcode
+
+ The startup procedure is divided into three steps:
+ \li First, configure() is called. configure() should be as simple as possible. It just needs
+ to set the daemon parameters. No further setup should be done here.
+ \li init() is called after fork() but while still connected to the terminal. init() should
+ do all necessary application setup. Here, all configuration or user errors should be
+ detected and properly diagnosed.
+ \li After init() returns, the application will detach from the terminal. Now run() is called
+ to enter the application main loop.
+
+ Since there are times, where separating init() and run() into two separate functions is
+ difficult, instead of defining init() and run(), the member main() may be defined. This
+ member must call detach() as soon as initialization is completed to detach from the
+ foreground terminal.
+ */
+ class Daemon : boost::noncopyable
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ /// Select standard stream to redirect
+ enum StdStream {
+ StdOut /** Standard output stream */
+ , StdErr /** Standard error stream */
+ , Both /** Both, standard output and error stream */
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///\{
+
+ virtual ~Daemon();
+
+ ///\}
+ ///\name Parameters
+ ///\{
+
+ void daemonize(bool); ///< Configure whether to run in fore- or background
+ bool daemon(); ///< \c true, if running as daemon
+
+ void consoleLog(std::string, StdStream which = Both); ///< Configure console log file
+ /**< May be called multiple times to set the log file
+ for stdout and stderr seperately. Any standard stream
+ not assigned to a log file will be redirected to
+ <tt>/dev/null</tt>.
+
+ When running in the foreground, the log files will be
+ ignored. */
+
+ void pidFile(std::string, bool unique = true); ///< Configure pid file
+
+ ///\}
+ ///\name Auxiliary helpers
+ ///\{
+
+ void detach(); ///< Detach into background now
+ /**< This is \e not the same as forking. The process will
+ already have forked into the background but until
+ detach() is called (either automatically after init()
+ returns or manually), the front end (foreground)
+ process will wait for the background process to ensure
+ successful startup. */
+
+ int argc(); ///< Access command line parameter count
+ char const ** argv(); ///< Access command line parameters
+
+ void fail(int code=1); ///< Terminate startup with failure
+
+ ///\}
+
+ int start(int argc, char const ** argv); ///< Called from main() to launch daemon.
+ /**< Normally not called directly but from the
+ \ref SENF_DAEMON_MAIN macro. */
+
+ protected:
+ Daemon();
+
+# ifdef DOXYGEN
+ protected:
+# else
+ private:
+# endif
+
+ virtual void configure(); ///< Called before forking to configure the daemon class
+ virtual void main(); ///< Called after forking to execute the main application
+ /**< The default implementation will call init(), detach()
+ and then run(). It is preferred to override init() and
+ run() if possible. */
+ virtual void init(); ///< Called to initialize the main application
+ /**< While init() is running, the application still is
+ connected to the controlling terminal. Error messages
+ will be shown to the user.
+
+ This member is only called, if the default main()
+ implementation is not overridden. */
+ virtual void run(); ///< Called to execute main application
+ /**< Called after detaching from the controlling
+ terminal.
+
+ This member is only called, if the default main()
+ implementation is not overridden. */
+ private:
+
+ void fork();
+ void pidfileCreate();
+
+ int argc_;
+ char const ** argv_;
+
+ bool daemonize_;
+ int stdout_;
+ int stderr_;
+ std::string pidfile_;
+ bool unique_;
+
+ bool detached_;
+ };
+
+ /** \brief Provide \c main() function
+
+ This macro will provide a \c main() function to launch the daemon process defined in \a
+ klass. \a klass must be a class derived from senf::Daemon.
+
+ \ingroup process
+ */
+# define SENF_DAEMON_MAIN(klass) \
+ int main(int argc, char const ** argv) \
+ { \
+ klass instance; \
+ return instance.start(argc, argv); \
+ }
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "Daemon.cci"
+//#include "Daemon.ct"
+//#include "Daemon.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) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+// 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 Daemon internal header */
+
+#ifndef IH_Daemon_
+#define IH_Daemon_ 1
+
+// Custom includes
+#include <deque>
+#include <boost/utility.hpp>
+#include <boost/function.hpp>
+#include "../Scheduler/Scheduler.hh"
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace detail {
+
+ /** \brief Internal: Watch daemon process for successful startup */
+ class DaemonWatcher
+ : boost::noncopyable
+ {
+ public:
+
+ DaemonWatcher(int pid, int coutpipe, int cerrpipe);
+
+ void run();
+
+ private:
+
+ class Forwarder
+ {
+ public:
+ typedef boost::function<void ()> Callback;
+
+ Forwarder(int src, int dst, Callback cb);
+ ~Forwarder();
+
+ private:
+
+ void readData(Scheduler::EventId event);
+ void writeData(Scheduler::EventId event);
+
+ typedef std::deque<char> Buffer;
+ Buffer buffer_;
+ int src_;
+ int dst_;
+ Callback cb_;
+ };
+
+ void pipeClosed();
+ void childDied();
+ void childOk();
+
+ int childPid_;
+ int coutpipe_;
+ int cerrpipe_;
+
+ Forwarder coutForwarder_;
+ Forwarder cerrForwarder_;
+
+ bool timerRunning_;
+ };
+
+}}
+
+///////////////////////////////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:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+// 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 Daemon.test unit tests */
+
+//#include "Daemon.test.hh"
+//#include "Daemon.test.ih"
+
+// Custom includes
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include "Daemon.hh"
+#include "../Utils/Exception.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+ void delay(unsigned long milliseconds)
+ {
+ struct timespec ts;
+ ts.tv_sec = milliseconds / 1000;
+ ts.tv_nsec = (milliseconds % 1000) * 1000000;
+ while (nanosleep(&ts,&ts) < 0 && errno == EINTR) ;
+ }
+
+ class MyDaemon : public senf::Daemon
+ {
+ void configure() { std::cout << "Running configure()" << std::endl; }
+ void init() { std::cout << "Running init()" << std::endl; }
+ void run() {
+ delay(2000);
+ std::cout << "Running run()" << std::endl;
+ }
+ };
+
+ int myMain(int argc, char const ** argv)
+ {
+ MyDaemon instance;
+ return instance.start(argc, argv);
+ }
+
+ int run(int argc, char const ** argv)
+ {
+ int pid (::fork());
+ if (pid < 0) senf::throwErrno("::fork()");
+ if (pid == 0) {
+ ::_exit(myMain(argc, argv));
+ }
+ int status;
+ if (::waitpid(pid, &status, 0) < 0) senf::throwErrno("::waitpid()");
+ return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+ }
+
+}
+
+BOOST_AUTO_UNIT_TEST(testDaemon)
+{
+ char const * args[] = { "run", 0 };
+ BOOST_CHECK_EQUAL( run(1,args), 0 );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
// queue. Since signals are only unblocked during epoll_wait, we even wouldn't need to
// synchronize access to that queue any further.
- ::write(instance().sigpipe_[1], siginfo, sizeof(siginfo));
+ ::write(instance().sigpipe_[1], siginfo, sizeof(*siginfo));
// We ignore errors. The file handle is set to non-blocking IO. If any failure occurs (pipe
// full), the signal will be dropped. That's like kernel signal handling which may also drop
// Check the signal queue
if (ev.data.fd == sigpipe_[0]) {
::siginfo_t siginfo;
- if (::read(sigpipe_[0], &siginfo, sizeof(siginfo)) < int(sizeof(siginfo)))
+ if (::read(sigpipe_[0], &siginfo, sizeof(siginfo)) < int(sizeof(siginfo))) {
// We ignore truncated records which may only occur if the signal
// queue became filled up
+ SENF_LOG((senf::log::IMPORTANT)("Truncated signal record!"));
continue;
+ }
if (siginfo.si_signo < int(sigHandlers_.size()) && sigHandlers_[siginfo.si_signo])
sigHandlers_[siginfo.si_signo]();
continue;
#include <boost/call_traits.hpp>
#include <boost/integer.hpp>
#include "ClockService.hh"
-#include "../Utils/Logger/Target.hh"
+#include "../Utils/Logger.hh"
//#include "scheduler.mpp"
///////////////////////////////hh.p////////////////////////////////////////
: boost::noncopyable
{
public:
+
+ SENF_LOG_CLASS_AREA();
+
///////////////////////////////////////////////////////////////////////////
// Types
BOOST_REQUIRE_EQUAL( size, 2 );
buffer[size]=0;
BOOST_CHECK_EQUAL( buffer, "OK" );
+ BOOST_CHECK_NO_THROW( Scheduler::instance().remove(handle) );
- BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(
- ClockService::now()+ClockService::milliseconds(200),&timeout) );
+ unsigned tid (Scheduler::instance().timeout(
+ ClockService::now()+ClockService::milliseconds(200),&timeout));
BOOST_CHECK_NO_THROW( Scheduler::instance().registerSignal(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(100)) );
+ BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(100)) );
+ Scheduler::instance().cancelTimeout(tid);
+ BOOST_CHECK_NO_THROW( Scheduler::instance().unregisterSignal(SIGUSR1) );
///////////////////////////////////////////////////////////////////////////
//#include "DaemonTools.ih"
// Custom includes
-#include <sys/types.h>
+#include <errno.h>
#include <sys/stat.h>
-#include <unistd.h>
+#include <sys/types.h>
#include <fcntl.h>
-#include <errno.h>
#include "Exception.hh"
//#include "DaemonTools.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-// senf::Daemon
-
-prefix_ senf::Daemon::~Daemon()
-{}
-
-prefix_ void senf::Daemon::daemonize(bool v)
-{
- daemonize_ = v;
-}
-
-prefix_ bool senf::Daemon::daemon()
-{
- return daemonize_;
-}
-
-prefix_ void senf::Daemon::consoleLog(std::string path, StdStream which)
-{
- int fd (-1);
- if (! path.empty()) {
- int fd (::open(path.c_str(), O_WRONLY | O_APPEND));
- if (fd < 0)
- throwErrno("open()");
- }
- switch (which) {
- case StdOut:
- stdout_ = fd;
- break;
- case StdErr:
- stderr_ = fd;
- break;
- case Both:
- stdout_ = fd;
- stderr_ = fd;
- break;
- }
-}
-
-prefix_ void senf::Daemon::pidFile(std::string f, bool unique)
-{
- pidfile_ = f;
- unique_ = unique;
-}
-
-prefix_ void senf::Daemon::detach()
-{}
-
-prefix_ int senf::Daemon::start(int argc, char const ** argv)
-{
- argc_ = argc;
- argv_ = argv;
-
-# ifdef NDEBUG
- try {
-# endif
-
- configure();
- if (daemonize_)
- fork();
- if (! pidfile_.empty())
- pidfileCreate();
- main();
-
-# ifdef NDEBUG
- }
- catch (std::exception & e) {
- std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
- return 1;
- }
- catch (...) {
- std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
- return 1;
- }
-# endif
-
- return 0;
-}
-
-////////////////////////////////////////
-// protected members
-
-prefix_ senf::Daemon::Daemon()
- : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""), unique_(true),
- detached_(false)
-{}
-
-////////////////////////////////////////
-// private members
-
-prefix_ void senf::Daemon::configure()
-{}
-
-prefix_ void senf::Daemon::main()
-{
- init();
- detach();
- run();
-}
-
-prefix_ void senf::Daemon::init()
-{}
-
-prefix_ void senf::Daemon::run()
-{}
-
-prefix_ void senf::Daemon::fork()
-{
-
-}
-
-prefix_ void senf::Daemon::pidfileCreate()
-{}
-
-///////////////////////////////////////////////////////////////////////////
-
prefix_ void senf::daemonize()
{
int pid = fork();
// Custom includes
#include <string>
-#include <boost/utility.hpp>
//#include "DaemonTools.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
- /** \brief Daemon process
-
- This class provides the infrastructure to implement robust daemon processes. A daemon
- process is implemented by deriving from senf::Daemon and implementing the necessary
- (virtual) member functions.
- \code
- class MyDaemon : public senf::Daemon
- {
- void configure() {
- // Set configuration parameters like daemonize(), pidFile() etc.
- }
-
- void init() {
- // Initialize application. Setup all necessary objects. After init()
- // has completed, is startup should not fail anymore
- }
-
- void run() {
- // Main application code should be called here.
- }
- };
- \endcode
-
- The startup procedure is divided into three steps:
- \li First, configure() is called. configure() should be as simple as possible. It just needs
- to set the daemon parameters. No further setup should be done here.
- \li init() is called after fork() but while still connected to the terminal. init() should
- do all necessary application setup. Here, all configuration or user errors should be
- detected and properly diagnosed.
- \li After init() returns, the application will detach from the terminal. Now run() is called
- to enter the application main loop.
-
- Since there are times, where separating init() and run() into two separate functions is
- difficult, instead of defining init() and run(), the member main() may be defined. This
- member must call detach() as soon as initialization is completed to detach from the
- foreground terminal.
-
-
-
- \ingroup process
- */
- class Daemon : boost::noncopyable
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- /// Select standard stream to redirect
- enum StdStream {
- StdOut /** Standard output stream */
- , StdErr /** Standard error stream */
- , Both /** Both, standard output and error stream */
- };
-
- ///////////////////////////////////////////////////////////////////////////
- ///\name Structors and default members
- ///\{
-
- virtual ~Daemon();
-
- ///\}
- ///\name Parameters
- ///\{
-
- void daemonize(bool); ///< Configure whether to run in fore- or background
- bool daemon(); ///< \c true, if running as daemon
-
- void consoleLog(std::string, StdStream which = Both); ///< Configure console log file
- /**< May be called multiple times to set the log file
- for stdout and stderr seperately. Any standard stream
- not assigned to a log file will be redirected to
- <tt>/dev/null</tt>.
-
- When running in the foreground, the log files will be
- ignored. */
-
- void pidFile(std::string, bool unique = true); ///< Configure pid file
-
- ///\}
- ///\name Auxiliary helpers
- ///\{
-
- void detach(); ///< Detach into background now
- /**< This is \e not the same as forking. The process will
- already have forked into the background but until
- detach() is called (either automatically after init()
- returns or manually), the front end (foreground)
- process will wait for the background process to ensure
- successful startup. */
-
- int argc(); ///< Access command line parameter count
- char const ** argv(); ///< Access command line parameters
-
- void fail(int code=1); ///< Terminate startup with failure
-
- ///\}
-
- int start(int argc, char const ** argv); ///< Called from main() to launch daemon.
- /**< Normally not called directly but from the
- \ref SENF_DAEMON_MAIN macro. */
-
- protected:
- Daemon();
-
-# ifdef DOXYGEN
- protected:
-# else
- private:
-# endif
-
- virtual void configure(); ///< Called before forking to configure the daemon class
- virtual void main(); ///< Called after forking to execute the main application
- /**< The default implementation will call init(), detach()
- and then run(). It is preferred to override init() and
- run() if possible. */
- virtual void init(); ///< Called to initialize the main application
- /**< While init() is running, the application still is
- connected to the controlling terminal. Error messages
- will be shown to the user.
-
- This member is only called, if the default main()
- implementation is not overridden. */
- virtual void run(); ///< Called to execute main application
- /**< Called after detaching from the controlling
- terminal.
-
- This member is only called, if the default main()
- implementation is not overridden. */
- private:
-
- void fork();
- void pidfileCreate();
-
- int argc_;
- char const ** argv_;
-
- bool daemonize_;
- int stdout_;
- int stderr_;
- std::string pidfile_;
- bool unique_;
-
- bool detached_;
- };
-
- /** \brief Provide \c main() function
-
- This macro will provide a \c main() function to launch the daemon process defined in \a
- klass. \a klass must be a class derived from senf::Daemon.
-
- \ingroup process
- */
-# define SENF_DAEMON_MAIN(klass) \
- int main(int argc, char const ** argv) \
- { \
- klass instance; \
- return instance.start(argc, argv); \
- }
-
/// \addtogroup process
/// @{
#include <boost/type_traits/is_convertible.hpp>
#include "../mpl.hh"
#include "Config.hh"
+#include "Target.hh"
///////////////////////////////ih.p////////////////////////////////////////
static bool enabled() {
return compileEnabled
- && Base::area::instance().limit(Base::stream::instance()) <= level::value;
+ && ( senf::log::detail::TargetRegistry::instance().fallbackRouting() ||
+ Base::area::instance().limit(Base::stream::instance()) <= level::value );
}
};
fallbackRouting_ = false;
}
+prefix_ bool senf::log::detail::TargetRegistry::fallbackRouting()
+{
+ return fallbackRouting_;
+}
+
////////////////////////////////////////
// private members
void timeSource(std::auto_ptr<TimeSource> source);
void routed();
+ bool fallbackRouting();
private:
TargetRegistry();
// Custom includes
+#ifdef SENF_LOG_CONF
+#undef SENF_LOG_CONF
+#endif
+
#define SENF_LOG_CONF (( (senf)(log)(Debug), (_), NOTICE )) \
(( (senf)(log)(test)(myStream), (senf)(log)(test)(Foo), VERBOSE ))