From 234f947ba394738c9dba4d5067210065133699e2 Mon Sep 17 00:00:00 2001 From: g0dil <g0dil@wiback.org> Date: Fri, 4 Apr 2008 09:34:14 +0000 Subject: [PATCH] Socket: Add a 'facet<>()' member to access protocol-facets from generic socket handles Scheduler: Add ClockService::from_time_t and from_timeval Utils: Implement generic backtrace helper Utils/Daemon: Catch fatal signals (plus SIGUSR2) and show a backtrace in debug builds --- Scheduler/ClockService.cci | 10 +++++ Scheduler/ClockService.hh | 11 +++++ Socket/SocketHandle.cti | 11 +++++ Socket/SocketHandle.hh | 10 +++++ Socket/SocketHandle.test.cc | 2 + Utils/Backtrace.cc | 89 +++++++++++++++++++++++++++++++++++++ Utils/Backtrace.hh | 56 +++++++++++++++++++++++ Utils/Daemon/Daemon.cc | 69 ++++++++++++++++++++++++++++ Utils/Daemon/Daemon.hh | 6 +-- Utils/Exception.cc | 29 ++---------- senf.dict | 30 +++++++++++++ 11 files changed, 294 insertions(+), 29 deletions(-) create mode 100644 Utils/Backtrace.cc create mode 100644 Utils/Backtrace.hh diff --git a/Scheduler/ClockService.cci b/Scheduler/ClockService.cci index 41cc91cd7..a26d937b7 100644 --- a/Scheduler/ClockService.cci +++ b/Scheduler/ClockService.cci @@ -47,6 +47,16 @@ prefix_ senf::ClockService::clock_type senf::ClockService::clock(abstime_type ti return instance().clock_m(time); } +prefix_ senf::ClockService::clock_type senf::ClockService::from_time_t(time_t const & time) +{ + return clock( boost::posix_time::from_time_t(time) ); +} + +prefix_ senf::ClockService::clock_type senf::ClockService::from_timeval(timeval const & time) +{ + return from_time_t(time.tv_sec) + ClockService::microseconds(time.tv_usec); +} + prefix_ senf::ClockService::clock_type senf::ClockService::nanoseconds(clock_type v) { return v; diff --git a/Scheduler/ClockService.hh b/Scheduler/ClockService.hh index ba9b2ac5f..04bcc1a55 100644 --- a/Scheduler/ClockService.hh +++ b/Scheduler/ClockService.hh @@ -27,6 +27,7 @@ #define HH_ClockService_ 1 // Custom includes +#include <sys/time.h> #include <boost/utility.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/scoped_ptr.hpp> @@ -130,6 +131,16 @@ namespace senf { corresponding clock value. \see abstime */ + static clock_type from_time_t(time_t const & time); + ///< Convert legacy time_t to clock value + /**< This member converts an absolute time value + represented as a time_t value into a clock value */ + + static clock_type from_timeval(timeval const & time); + ///< Convert legacy timeval to clock value + /**< This member converts an absolute time value + represented as a timeval value into a clock value */ + static clock_type nanoseconds(clock_type v); static clock_type microseconds(clock_type v); static clock_type milliseconds(clock_type v); diff --git a/Socket/SocketHandle.cti b/Socket/SocketHandle.cti index 39b32734a..cbd908902 100644 --- a/Socket/SocketHandle.cti +++ b/Socket/SocketHandle.cti @@ -187,6 +187,17 @@ prefix_ std::string senf::SocketHandle<SPolicy>::dumpState(unsigned lod) return detail::dumpState(map); } +template <class SPolicy> +template <class Facet> +prefix_ Facet const & senf::SocketHandle<SPolicy>::facet() + +{ + try { + return dynamic_cast<Facet const &>(protocol()); + } + SENF_WRAP_EXC(std::bad_cast) +} + /////////////////////////////////////////////////////////////////////////// // senf::ProtocolSocketBody<SProtocol> diff --git a/Socket/SocketHandle.hh b/Socket/SocketHandle.hh index 6d36be8c2..867d0aad4 100644 --- a/Socket/SocketHandle.hh +++ b/Socket/SocketHandle.hh @@ -147,6 +147,16 @@ namespace senf { every derived class. See the state() documentation. */ + template <class Facet> + Facet const & facet(); ///< Access a protocol facet + /**< This member will try to access the given protocol facet + of the socket. If \a Facet is a valid facet of the + protocol, it is returned, otherwise \c std::bad_cast + will be thrown. + \throws std::bad_cast if \a Facet is not a protocol + facet of this socket + \returns the \a Facet protocol facet of this socket */ + protected: explicit SocketHandle(std::auto_ptr<SocketBody> body); ///< Initialize SocketHandle providing the protocol diff --git a/Socket/SocketHandle.test.cc b/Socket/SocketHandle.test.cc index 63fff9eff..c88c6363d 100644 --- a/Socket/SocketHandle.test.cc +++ b/Socket/SocketHandle.test.cc @@ -94,6 +94,8 @@ BOOST_AUTO_UNIT_TEST(socketHandle) "socket.protocol: senf::test::SomeSocketProtocol\n" "socket.protocol.policy: senf::SocketPolicy<senf::test::SomeAddressingPolicy, senf::test::SomeFramingPolicy, senf::test::SomeCommunicationPolicy, senf::test::SomeReadPolicy, senf::test::SomeWritePolicy>\n" "socket.server: false\n" ); + + BOOST_CHECK_NO_THROW( myh.facet<senf::test::SomeSocketProtocol>() ); } // Ensure, the destructor is called and calls the correct close() implementation diff --git a/Utils/Backtrace.cc b/Utils/Backtrace.cc new file mode 100644 index 000000000..09239c897 --- /dev/null +++ b/Utils/Backtrace.cc @@ -0,0 +1,89 @@ +// $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 Backtrace non-inline non-template implementation */ + +#include "Backtrace.hh" +//#include "Backtrace.ih" + +// Custom includes +#include <execinfo.h> +#include <cxxabi.h> +#include <boost/regex.hpp> + +//#include "Backtrace.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +prefix_ void senf::formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries) +{ + char ** symbols (::backtrace_symbols(backtrace, numEntries)); + + static boost::regex const backtraceRx + ("(.*)\\((.*)\\+(0x[0-9a-f]+)\\) \\[(0x[0-9a-f]+)\\]"); + enum { File = 1, + Symbol = 2, + Offset = 3, + Address = 4 }; + + for (unsigned i=0; i<numEntries; ++i) { + std::string sym (symbols[i]); + boost::smatch match; + if (regex_match(sym, match, backtraceRx)) { + std::string symbol (match[Symbol]); + int status (0); + char * demangled ( abi::__cxa_demangle(symbol.c_str(), 0, 0, &status) ); + if (demangled) { + symbol = std::string(demangled); + free(demangled); + } + os << " " << symbol << " + " << match[Offset] + << "\n in " << match[File] << " [" << match[Address] << "]\n"; + } + else if (sym == "[0xffffe410]") + os << " __kernel_vsyscall [0xffffe410]\n"; + else if (sym == "[0xffffe420]") + os << " __kernel_sigreturn [0xffffe410]\n"; + else if (sym == "[0xffffe440]") + os << " __kernel_rt_sigreturn [0xffffe440]\n"; + else + os << " " << sym << "\n"; + } + free(symbols); +} + + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "Backtrace.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/Utils/Backtrace.hh b/Utils/Backtrace.hh new file mode 100644 index 000000000..b2d39d75a --- /dev/null +++ b/Utils/Backtrace.hh @@ -0,0 +1,56 @@ +// $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 Backtrace public header */ + +#ifndef HH_Backtrace_ +#define HH_Backtrace_ 1 + +// Custom includes +#include <iostream> + +//#include "Backtrace.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { + + void formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries); + +} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "Backtrace.cci" +//#include "Backtrace.ct" +//#include "Backtrace.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/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index 1a684a525..fe55821ae 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -34,6 +34,7 @@ #include <fcntl.h> #include <errno.h> #include <signal.h> +#include <execinfo.h> #include <sstream> #include <algorithm> #include <boost/algorithm/string/predicate.hpp> @@ -41,6 +42,10 @@ #include <boost/format.hpp> #include "../Exception.hh" #include "../membind.hh" +#include "../Backtrace.hh" + +// #define __USE_GNU +#include <ucontext.h> //#include "Daemon.mpp" #define prefix_ @@ -196,6 +201,7 @@ prefix_ int senf::Daemon::start(int argc, char ** argv) openLog(); fork(); } + installSighandlers(); if (! pidfile_.empty()) { if (pidfileCreate()) pidfileCreated_ = true; @@ -417,6 +423,69 @@ prefix_ bool senf::Daemon::pidfileCreate() return true; } + +#ifdef SENF_DEBUG + +namespace { + void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg) + { + static char const * const signames[] = { + "", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", + "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", + "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", + "SIGPWR", "SIGSYS" }; + + // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg); + std::cerr << "\n" << "Signal " << sig; + if (unsigned(sig) < sizeof(signames) / sizeof(signames[0])) + std::cerr << " (" << signames[unsigned(sig)] << ")"; + std::cerr << " received\n"; + + if (sig == SIGSEGV) + std::cerr << "Invalid memory access at " << info->si_addr << "\n"; + + static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS]; + unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) ); + + // Hack the callers address into the backtrace + // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]); + + std::cerr << "Backtrace:\n"; + senf::formatBacktrace(std::cerr, entries, nEntries); + std::cerr << "-- \n"; + + if (sig != SIGUSR2) { + ::signal(sig, SIG_DFL); + ::kill(::getpid(), sig); + } + } + +} + +#endif + +prefix_ void senf::Daemon::installSighandlers() +{ +#ifdef SENF_DEBUG + struct ::sigaction sa; + sa.sa_sigaction = &fatalSignalsHandler; + ::sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + ::sigaction(SIGILL, &sa, NULL); + ::sigaction(SIGTRAP, &sa, NULL); + ::sigaction(SIGABRT, &sa, NULL); + ::sigaction(SIGFPE, &sa, NULL); + ::sigaction(SIGBUS, &sa, NULL); + ::sigaction(SIGSEGV, &sa, NULL); + ::sigaction(SIGSTKFLT, &sa, NULL); + ::sigaction(SIGSYS, &sa, NULL); + ::sigaction(SIGUSR2, &sa, NULL); +#endif +} + /////////////////////////////////////////////////////////////////////////// // senf::detail::DaemonWatcher diff --git a/Utils/Daemon/Daemon.hh b/Utils/Daemon/Daemon.hh index 25b8e603f..d0ba4a7ce 100644 --- a/Utils/Daemon/Daemon.hh +++ b/Utils/Daemon/Daemon.hh @@ -154,9 +154,9 @@ namespace senf { successful startup. */ int argc(); ///< Access command line parameter count - char ** argv(); ///< Access command line parameters + char ** argv(); ///< Access command line parameters - static void exit(unsigned code=0); ///< Terminate daemon with failure + static void exit(unsigned code=0); ///< Terminate daemon with failure ///\} @@ -195,10 +195,10 @@ namespace senf { This member is only called, if the default main() implementation is not overridden. */ private: - void openLog(); void fork(); bool pidfileCreate(); + void installSighandlers(); int argc_; char ** argv_; diff --git a/Utils/Exception.cc b/Utils/Exception.cc index a65123952..b2c750f38 100644 --- a/Utils/Exception.cc +++ b/Utils/Exception.cc @@ -30,12 +30,7 @@ #include <execinfo.h> #include <sstream> #include "../config.hh" - -// Copied from the binutils sources -#define HAVE_DECL_BASENAME 1 -#define HAVE_DECL_ASPRINTF 1 -#define HAVE_DECL_VASPRINTF 1 -#include "impl/demangle.h" +#include "Backtrace.hh" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// @@ -48,30 +43,12 @@ prefix_ void senf::ExceptionMixin::addBacktrace() { void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS]; unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) ); - char ** symbols = ::backtrace_symbols(entries, nEntries); - + std::stringstream ss; ss << "\nException at\n"; - for (unsigned i=0; i<nEntries; ++i) { - std::string sym (symbols[i]); - std::string::size_type fnStart (sym.find("(")); - if (fnStart != std::string::npos) { - std::string::size_type fnEnd (sym.find(")",fnStart+1)); - if (fnEnd != std::string::npos) { - std::string fn (sym,fnStart+1, fnEnd-fnStart-1); - char * demangled ( ::cplus_demangle(fn.c_str(), - DMGL_TYPES|DMGL_AUTO) ); - if (demangled) { - ss << " " << demangled << "( ... )" << std::string(sym,fnEnd+1) << "\n"; - continue; - } - } - } - ss << " " << sym << "\n"; - } + formatBacktrace(ss, entries, nEntries); ss << "-- \n" << message_; message_ = ss.str(); - free(symbols); } #endif diff --git a/senf.dict b/senf.dict index d04b5c3eb..00e57e0c3 100644 --- a/senf.dict +++ b/senf.dict @@ -380,7 +380,37 @@ setEnd setfill setFromPosition setw +SIGABRT +SIGALRM +SIGBUS +SIGCHLD +SIGCONT +SIGFPE +SIGHUP +SIGILL +SIGINT +SIGIO +SIGIOT +SIGKILL +SIGPIPE +SIGPROF +SIGPWR +SIGQUIT +SIGSEGV +SIGSTKFLT +SIGSTOP +SIGSYS +SIGTERM +SIGTRAP +SIGTSTP +SIGTTIN +SIGTTOU +SIGURG SIGUSR +SIGVTALRM +SIGWINCH +SIGXCPU +SIGXFSZ SimpleCommandNode SimpleCommandOverload SimplePacketType -- GitLab