Renameing. Reformatting crashhandler for c++11

This commit is contained in:
KjellKod 2013-09-25 21:59:28 -06:00
parent e0355e766a
commit ad998db248
6 changed files with 192 additions and 223 deletions

View File

@ -21,7 +21,9 @@ using namespace kjellkod;
Active::Active() : done_(false) {
}
Active::~Active() {
send( [this]{ done_ = true;} );
send([this] {
done_ = true;
});
thd_.join();
}

View File

@ -24,26 +24,25 @@
#include "shared_queue.h"
namespace kjellkod {
typedef std::function<void() > Callback;
typedef std::function<void() > Callback;
class Active {
private:
Active(); // Construction ONLY through factory createActive();
void run();
class Active {
private:
Active(); // Construction ONLY through factory createActive();
void run();
shared_queue<Callback> mq_;
std::thread thd_;
bool done_; // finished flag : set by ~Active
shared_queue<Callback> mq_;
std::thread thd_;
bool done_; // finished flag : set by ~Active
public:
virtual ~Active();
void send(Callback msg_);
static std::unique_ptr<Active> createActive();
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
};
public:
virtual ~Active();
void send(Callback msg_);
static std::unique_ptr<Active> createActive();
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
};
} // kjellkod

View File

@ -1,27 +1,22 @@
#ifndef CRASH_HANDLER_H_
#define CRASH_HANDLER_H_
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <string>
#include <csignal>
namespace g2
{
// PRIVATE-INTERNAL API
namespace internal
{
/** \return signal_name. Ref: signum.h and \ref installSignalHandler */
namespace g2 {
namespace internal {
/// @return signal_name. Ref: signum.h and @ref installSignalHandler */
std::string signalName(int signal_number);
/** Re-"throw" a fatal signal, previously caught. This will exit the application
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g2log, g2LogWorker after flushing messages to file */
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g2log, g2LogWorker after flushing messages to file */
void exitWithDefaultSignalHandler(int signal_number);
} // end g2::interal
// PUBLIC API:
@ -32,6 +27,8 @@ void exitWithDefaultSignalHandler(int signal_number);
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installSignalHandler();
}
} // g2::internal
} // g2
#endif // CRASH_HANDLER_H_

View File

@ -1,8 +1,8 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include "crashhandler.hpp"
#include "g2log.h"
@ -21,91 +21,77 @@
#include <cxxabi.h>
#include <cstdlib>
namespace
{
namespace {
// Dump of stack,. then exit through g2log background worker
// ALL thanks to this thread at StackOverflow. Pretty much borrowed from:
// Ref: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
void crashHandler(int signal_number, siginfo_t *info, void *unused_context)
{
const size_t max_dump_size = 50;
void* dump[max_dump_size];
size_t size = backtrace(dump, max_dump_size);
char** messages = backtrace_symbols(dump, size); // overwrite sigaction with caller's address
void crashHandler(int signal_number, siginfo_t *info, void *unused_context) {
const size_t max_dump_size = 50;
void* dump[max_dump_size];
size_t size = backtrace(dump, max_dump_size);
char** messages = backtrace_symbols(dump, size); // overwrite sigaction with caller's address
std::ostringstream oss;
oss << "Received fatal signal: " << g2::internal::signalName(signal_number);
oss << "(" << signal_number << ")" << std::endl;
oss << "\tPID: " << getpid() << std::endl;
std::ostringstream oss;
oss << "Received fatal signal: " << g2::internal::signalName(signal_number);
oss << "(" << signal_number << ")" << std::endl;
oss << "\tPID: " << getpid() << std::endl;
// dump stack: skip first frame, since that is here
for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
{
char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
// find parantheses and +address offset surrounding mangled name
for (char *p = messages[idx]; *p; ++p)
{
if (*p == '(')
{
mangled_name = p;
// dump stack: skip first frame, since that is here
for (size_t idx = 1; idx < size && messages != nullptr; ++idx) {
char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
// find parantheses and +address offset surrounding mangled name
for (char *p = messages[idx]; *p; ++p) {
if (*p == '(') {
mangled_name = p;
} else if (*p == '+') {
offset_begin = p;
} else if (*p == ')') {
offset_end = p;
break;
}
}
else if (*p == '+')
{
offset_begin = p;
// if the line could be processed, attempt to demangle the symbol
if (mangled_name && offset_begin && offset_end &&
mangled_name < offset_begin) {
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
int status;
char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
// if demangling is successful, output the demangled function name
if (status == 0) {
oss << "\tstack dump [" << idx << "] " << messages[idx] << " : " << real_name << "+";
oss << offset_begin << offset_end << std::endl;
} // otherwise, output the mangled function name
else {
oss << "\tstack dump [" << idx << "] " << messages[idx] << mangled_name << "+";
oss << offset_begin << offset_end << std::endl;
}
free(real_name); // mallocated by abi::__cxa_demangle(...)
} else {
// no demangling done -- just dump the whole line
oss << "\tstack dump [" << idx << "] " << messages[idx] << std::endl;
}
else if (*p == ')')
{
offset_end = p;
break;
}
}
// if the line could be processed, attempt to demangle the symbol
if (mangled_name && offset_begin && offset_end &&
mangled_name < offset_begin)
{
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
int status;
char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
// if demangling is successful, output the demangled function name
if (status == 0)
{
oss << "\tstack dump [" << idx << "] " << messages[idx] << " : " << real_name << "+";
oss << offset_begin << offset_end << std::endl;
}
// otherwise, output the mangled function name
else
{
oss << "\tstack dump [" << idx << "] " << messages[idx] << mangled_name << "+";
oss << offset_begin << offset_end << std::endl;
}
free(real_name); // mallocated by abi::__cxa_demangle(...)
}
else
{
// no demangling done -- just dump the whole line
oss << "\tstack dump [" << idx << "] " << messages[idx] << std::endl;
}
} // END: for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
} // END: for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
free(messages);
{ // Local scope, trigger send
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << oss.str() << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
free(messages);
{ // Local scope, trigger send
using namespace g2::internal;
std::string fatal_content = {"\n\n***** FATAL TRIGGER RECEIVED ******* \n"};
fatal_content.append(oss.str()).append("\n");
fatal_content.append({"\n***** RETHROWING SIGNAL "});
fatal_content.append(signalName(signal_number)).append("(");
fatal_content.append(std::to_string(signal_number)).append({")\n"});
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message); std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // message sent to g2LogWorker
// wait to die -- will be inside the FatalTrigger
FatalMessage fatal_message(fatal_content, FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message);
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // message sent to g2LogWorker
// wait to die -- will be inside the FatalTrigger
}
} // end anonymous namespace
@ -116,8 +102,7 @@ void crashHandler(int signal_number, siginfo_t *info, void *unused_context)
// Redirecting and using signals. In case of fatal signals g2log should log the fatal signal
// and flush the log queue and then "rethrow" the signal to exit
namespace g2
{
namespace g2 {
// References:
// sigaction : change the default action if a specific signal is received
// http://linux.die.net/man/2/sigaction
@ -129,60 +114,55 @@ namespace g2
// memset + sigemptyset: Maybe unnecessary to do both but there seems to be some confusion here
// ,plenty of examples when both or either are used
// http://stackoverflow.com/questions/6878546/why-doesnt-parent-process-return-to-the-exact-location-after-handling-signal_number
namespace internal
{
std::string signalName(int signal_number)
{
switch(signal_number)
{
case SIGABRT: return "SIGABRT";break;
case SIGFPE: return "SIGFPE"; break;
case SIGSEGV: return "SIGSEGV"; break;
case SIGILL: return "SIGILL"; break;
case SIGTERM: return "SIGTERM"; break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ")";
return oss.str();
}
namespace internal {
std::string signalName(int signal_number) {
switch (signal_number) {
case SIGABRT: return {"SIGABRT"}; break;
case SIGFPE: return {"SIGFPE"}; break;
case SIGSEGV: return {"SIGSEGV"}; break;
case SIGILL: return {"SIGILL"}; break;
case SIGTERM: return {"SIGTERM"}; break;
default:
std::string error = {"UNKNOWN SIGNAL("};
error.append(std::to_string(signal_number)).append(")");
return error;
}
}
// Triggered by g2log->g2LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(int signal_number)
{
std::cerr << "\nExiting - FATAL SIGNAL: " << signal_number << " " << std::flush;
struct sigaction action;
memset(&action, 0, sizeof(action)); //
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL; // take default action for the signal
sigaction(signal_number, &action, NULL);
kill(getpid(), signal_number);
abort(); // should never reach this
void exitWithDefaultSignalHandler(int signal_number) {
std::cerr << "\nExiting - FATAL SIGNAL: " << signal_number << " " << std::flush;
struct sigaction action;
memset(&action, 0, sizeof (action)); //
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL; // take default action for the signal
sigaction(signal_number, &action, NULL);
kill(getpid(), signal_number);
abort(); // should never reach this
}
} // end g2::internal
void installSignalHandler()
{
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = &crashHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
void installSignalHandler() {
struct sigaction action;
memset(&action, 0, sizeof (action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = &crashHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
// do it verbose style - install all signal actions
if(sigaction(SIGABRT, &action, NULL) < 0)
perror("sigaction - SIGABRT");
if(sigaction(SIGFPE, &action, NULL) < 0)
perror("sigaction - SIGFPE");
if(sigaction(SIGILL, &action, NULL) < 0)
perror("sigaction - SIGILL");
if(sigaction(SIGSEGV, &action, NULL) < 0)
perror("sigaction - SIGSEGV");
if(sigaction(SIGTERM, &action, NULL) < 0)
perror("sigaction - SIGTERM");
// do it verbose style - install all signal actions
if (sigaction(SIGABRT, &action, NULL) < 0)
perror("sigaction - SIGABRT");
if (sigaction(SIGFPE, &action, NULL) < 0)
perror("sigaction - SIGFPE");
if (sigaction(SIGILL, &action, NULL) < 0)
perror("sigaction - SIGILL");
if (sigaction(SIGSEGV, &action, NULL) < 0)
perror("sigaction - SIGSEGV");
if (sigaction(SIGTERM, &action, NULL) < 0)
perror("sigaction - SIGTERM");
}
} // end namespace g2
} // g2::internal
} // g2

View File

@ -1,8 +1,8 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include "crashhandler.hpp"
#include "g2log.h"
@ -17,76 +17,67 @@
#include <process.h> // getpid
#define getpid _getpid
namespace
{
void crashHandler(int signal_number)
{
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
namespace {
void crashHandler(int signal_number) {
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message); std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
FatalMessage fatal_message(fatal_stream.str(), FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message);
std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // scope exit - message sent to LogWorker, wait to die...
} // end anonymous namespace
namespace g2
{
namespace internal
{
std::string signalName(int signal_number)
{
switch(signal_number)
{
case SIGABRT: return "SIGABRT";break;
case SIGFPE: return "SIGFPE"; break;
case SIGSEGV: return "SIGSEGV"; break;
case SIGILL: return "SIGILL"; break;
case SIGTERM: return "SIGTERM"; break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ")";
return oss.str();
}
namespace g2 {
namespace internal {
std::string signalName(int signal_number) {
switch (signal_number) {
case SIGABRT: return {"SIGABRT"}; break;
case SIGFPE: return {"SIGFPE"}; break;
case SIGSEGV: return {"SIGSEGV"}; break;
case SIGILL: return {"SIGILL"}; break;
case SIGTERM: return {"SIGTERM"}; break;
default:
std::string out = {"UNKNOWN SIGNAL("}
out.append(std::to_string(signal_number).append(")");
return oss.str();
}
}
// Triggered by g2log::LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(int signal_number)
{
// Restore our signalhandling to default
if(SIG_ERR == signal (SIGABRT, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGFPE, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGSEGV, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGILL, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGTERM, SIG_DFL))
perror("signal - SIGABRT");
void exitWithDefaultSignalHandler(int signal_number) {
// Restore our signalhandling to default
if (SIG_ERR == signal(SIGABRT, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGSEGV, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGILL, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGTERM, SIG_DFL))
perror("signal - SIGABRT");
raise(signal_number);
}
} // end g2::internal
void installSignalHandler()
{
if(SIG_ERR == signal (SIGABRT, crashHandler))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGFPE, crashHandler))
perror("signal - SIGFPE");
if(SIG_ERR == signal (SIGSEGV, crashHandler))
perror("signal - SIGSEGV");
if(SIG_ERR == signal (SIGILL, crashHandler))
perror("signal - SIGILL");
if(SIG_ERR == signal (SIGTERM, crashHandler))
perror("signal - SIGTERM");
void installSignalHandler() {
if (SIG_ERR == signal(SIGABRT, crashHandler))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, crashHandler))
perror("signal - SIGFPE");
if (SIG_ERR == signal(SIGSEGV, crashHandler))
perror("signal - SIGSEGV");
if (SIG_ERR == signal(SIGILL, crashHandler))
perror("signal - SIGILL");
if (SIG_ERR == signal(SIGTERM, crashHandler))
perror("signal - SIGTERM");
}
} // end namespace g2
} // g2::internal
} // g2

View File

@ -69,7 +69,7 @@ void initializeLogging(g2LogWorker *bgworker)
if(false == once_only_signalhandler)
{
installSignalHandler();
internal::installSignalHandler();
once_only_signalhandler = true;
}
}