From: g0dil Date: Fri, 9 Nov 2007 11:49:53 +0000 (+0000) Subject: Packets: Fix min_value / max_value boundary cases for Parse_(U)IntField X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=17e24d84603667395e9ffa786a9cdbb722bf9c1f;p=senf.git Packets: Fix min_value / max_value boundary cases for Parse_(U)IntField Scheduler: Add debug log message, fix signal handlin bug Scheduler: Remove all registered handlers/callbacks/descriptors at end of unit test Utils/Logger: Undef SENF_LOG_CONF if defined in main.test.hh Scheduler: Moved Daemon class from Utils here. Can't be in Utils since it depends on the Scheduler :-( Scheduler: Daemon class: Implemented correkt fork() and simple log-passing behaviour git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@501 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/ParseInt.hh b/Packets/ParseInt.hh index 367bb1b..32ae476 100644 --- a/Packets/ParseInt.hh +++ b/Packets/ParseInt.hh @@ -284,15 +284,6 @@ namespace senf { inline std::ostream & operator<<(std::ostream & os, Parse_UInt32 const & i) { os << i.value(); return os; } - template - struct ctime_pow { - static const int result = X * ctime_pow::result; - }; - template - struct ctime_pow { - 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 @@ -328,8 +319,8 @@ namespace senf { 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::sig_bits; + static value_type const min_value = - max_value - 1; value_type value() const { @@ -386,8 +377,8 @@ namespace senf { 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::sig_bits; value_type value() const { return detail::packet::parse_bitfield::parse(i()); } void value(value_type v) { detail::packet::parse_bitfield::write(i(),v); } diff --git a/Scheduler/Daemon.cc b/Scheduler/Daemon.cc new file mode 100644 index 0000000..5252dcf --- /dev/null +++ b/Scheduler/Daemon.cc @@ -0,0 +1,339 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// 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 Daemon non-inline non-template implementation */ + +#include "Daemon.hh" +#include "Daemon.ih" + +// Custom includes +#include +#include +#include +#include +#include +#include +#include +#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" + + +// 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/Daemon.hh b/Scheduler/Daemon.hh new file mode 100644 index 0000000..205dcad --- /dev/null +++ b/Scheduler/Daemon.hh @@ -0,0 +1,209 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// 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 Daemon public header */ + +#ifndef HH_Daemon_ +#define HH_Daemon_ 1 + +// Custom includes +#include + +//#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 + /dev/null. + + 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 + + +// 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/Daemon.ih b/Scheduler/Daemon.ih new file mode 100644 index 0000000..23af6ce --- /dev/null +++ b/Scheduler/Daemon.ih @@ -0,0 +1,100 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// 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 Daemon internal header */ + +#ifndef IH_Daemon_ +#define IH_Daemon_ 1 + +// Custom includes +#include +#include +#include +#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 Callback; + + Forwarder(int src, int dst, Callback cb); + ~Forwarder(); + + private: + + void readData(Scheduler::EventId event); + void writeData(Scheduler::EventId event); + + typedef std::deque 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 + + +// 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/Daemon.test.cc b/Scheduler/Daemon.test.cc new file mode 100644 index 0000000..418ea9f --- /dev/null +++ b/Scheduler/Daemon.test.cc @@ -0,0 +1,101 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// 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 Daemon.test unit tests */ + +//#include "Daemon.test.hh" +//#include "Daemon.test.ih" + +// Custom includes +#include +#include +#include +#include +#include "Daemon.hh" +#include "../Utils/Exception.hh" + +#include +#include + +#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_ + + +// 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/Scheduler.cc b/Scheduler/Scheduler.cc index 09628f1..9f222bf 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -170,7 +170,7 @@ prefix_ void senf::Scheduler::sigHandler(int signal, ::siginfo_t * siginfo, void // 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 @@ -250,10 +250,12 @@ prefix_ void senf::Scheduler::process() // 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; diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index 7696a64..1ad6896 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -37,7 +37,7 @@ #include #include #include "ClockService.hh" -#include "../Utils/Logger/Target.hh" +#include "../Utils/Logger.hh" //#include "scheduler.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -158,6 +158,9 @@ namespace senf { : boost::noncopyable { public: + + SENF_LOG_CLASS_AREA(); + /////////////////////////////////////////////////////////////////////////// // Types diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index a9bd18e..c26b640 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -267,15 +267,19 @@ BOOST_AUTO_UNIT_TEST(scheduler) 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) ); /////////////////////////////////////////////////////////////////////////// diff --git a/Utils/DaemonTools.cc b/Utils/DaemonTools.cc index 1896a5c..1d33a6e 100644 --- a/Utils/DaemonTools.cc +++ b/Utils/DaemonTools.cc @@ -24,132 +24,16 @@ //#include "DaemonTools.ih" // Custom includes -#include +#include #include -#include +#include #include -#include #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(); diff --git a/Utils/DaemonTools.hh b/Utils/DaemonTools.hh index 46d510a..466e592 100644 --- a/Utils/DaemonTools.hh +++ b/Utils/DaemonTools.hh @@ -53,172 +53,12 @@ // Custom includes #include -#include //#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 - /dev/null. - - 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 /// @{ diff --git a/Utils/Logger/Parameters.ih b/Utils/Logger/Parameters.ih index 5370f97..213cf03 100644 --- a/Utils/Logger/Parameters.ih +++ b/Utils/Logger/Parameters.ih @@ -38,6 +38,7 @@ #include #include "../mpl.hh" #include "Config.hh" +#include "Target.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -117,7 +118,8 @@ namespace detail { 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 ); } }; diff --git a/Utils/Logger/Target.cci b/Utils/Logger/Target.cci index 5c77795..ed2c0d9 100644 --- a/Utils/Logger/Target.cci +++ b/Utils/Logger/Target.cci @@ -104,6 +104,11 @@ prefix_ void senf::log::detail::TargetRegistry::routed() fallbackRouting_ = false; } +prefix_ bool senf::log::detail::TargetRegistry::fallbackRouting() +{ + return fallbackRouting_; +} + //////////////////////////////////////// // private members diff --git a/Utils/Logger/Target.ih b/Utils/Logger/Target.ih index f6cdc85..668bacc 100644 --- a/Utils/Logger/Target.ih +++ b/Utils/Logger/Target.ih @@ -49,6 +49,7 @@ namespace detail { void timeSource(std::auto_ptr source); void routed(); + bool fallbackRouting(); private: TargetRegistry(); diff --git a/Utils/Logger/main.test.hh b/Utils/Logger/main.test.hh index 799d529..c9bcdeb 100644 --- a/Utils/Logger/main.test.hh +++ b/Utils/Logger/main.test.hh @@ -28,6 +28,10 @@ // 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 ))