From 9154f9b7192551a0ad263b3a69a08cf0627529e6 Mon Sep 17 00:00:00 2001 From: sale Date: Fri, 16 Dec 2016 12:56:36 +0000 Subject: [PATCH] Added signal handler and refactored exception handler Summary: Added signal handler and refactored exception handler Test Plan: manual Reviewers: buda Subscribers: buda Differential Revision: https://memgraph.phacility.com/D17 --- .arclint | 8 -- include/utils/signals/handler.hpp | 41 +++++++++ include/utils/terminate_handler.hpp | 53 +++++------- src/memgraph_bolt.cpp | 130 +++++++++++++++------------- tests/unit/signal_handler.cpp | 27 ++++++ 5 files changed, 158 insertions(+), 101 deletions(-) delete mode 100644 .arclint create mode 100644 include/utils/signals/handler.hpp create mode 100644 tests/unit/signal_handler.cpp diff --git a/.arclint b/.arclint deleted file mode 100644 index 6c5a03cd2..000000000 --- a/.arclint +++ /dev/null @@ -1,8 +0,0 @@ -{ - "linters": { - "cppcheck": { - "type": "cppcheck", - "include": ["(\\.cpp$)", "(\\.hpp$)"] - } - } -} diff --git a/include/utils/signals/handler.hpp b/include/utils/signals/handler.hpp new file mode 100644 index 000000000..18d833870 --- /dev/null +++ b/include/utils/signals/handler.hpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include + +using Function = std::function; + +enum class Signal : int { + Terminate = SIGTERM, + SegmentationFault = SIGSEGV, + Interupt = SIGINT, + Quit = SIGQUIT, + Abort = SIGABRT +}; + +class SignalHandler { + private: + static std::map> handlers_; + + static void handle(int signal) { handlers_[signal](); } + + public: + static void register_handler(Signal signal, Function func) { + int signal_number = static_cast(signal); + handlers_[signal_number] = func; + std::signal(signal_number, SignalHandler::handle); + } + + // TODO possible changes if signelton needed later + /* + static SignalHandler& instance() { + static SignalHandler instance; + return instance; + } + */ +}; + +std::map> SignalHandler::handlers_ = {}; diff --git a/include/utils/terminate_handler.hpp b/include/utils/terminate_handler.hpp index 7c19396ac..7ae21d5a1 100644 --- a/include/utils/terminate_handler.hpp +++ b/include/utils/terminate_handler.hpp @@ -1,48 +1,35 @@ #pragma once #include "utils/auto_scope.hpp" +#include "utils/stacktrace.hpp" -#include #include +#include // TODO: log to local file or remote database -void stacktrace(std::ostream& stream) noexcept -{ - void* array[50]; - int size = backtrace(array, 50); +void stacktrace(std::ostream& stream) noexcept { + Stacktrace stacktrace; - stream << __FUNCTION__ << " backtrace returned " - << size << " frames." << std::endl; + std::string message; - char** messages = backtrace_symbols(array, size); - Auto(free(messages)); - - for (int i = 0; i < size && messages != NULL; ++i) - stream << "[bt]: (" << i << ") " << messages[i] << std::endl; - - stream << std::endl; + for (int i = 0; i < stacktrace.size(); i++) { + message.append(fmt::format("\n at {} ({})", stacktrace[i].function, + stacktrace[i].location)); + } + stream << message << std::endl; } // TODO: log to local file or remote database -void terminate_handler(std::ostream& stream) noexcept -{ - if (auto exc = std::current_exception()) - { - try - { - std::rethrow_exception(exc); - } - catch(std::exception& ex) - { - stream << ex.what() << std::endl << std::endl; - stacktrace(stream); - } +void terminate_handler(std::ostream& stream) noexcept { + if (auto exc = std::current_exception()) { + try { + std::rethrow_exception(exc); + } catch (std::exception& ex) { + stream << ex.what() << std::endl << std::endl; + stacktrace(stream); } - - std::abort(); + } + std::abort(); } -void terminate_handler() noexcept -{ - terminate_handler(std::cout); -} +void terminate_handler() noexcept { terminate_handler(std::cout); } diff --git a/src/memgraph_bolt.cpp b/src/memgraph_bolt.cpp index b5d67ea3b..03fcb2e51 100644 --- a/src/memgraph_bolt.cpp +++ b/src/memgraph_bolt.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include "communication/bolt/v1/server/server.hpp" #include "communication/bolt/v1/server/worker.hpp" @@ -9,74 +9,84 @@ #include "logging/default.hpp" #include "logging/streams/stdout.hpp" +#include "utils/signals/handler.hpp" +#include "utils/stacktrace.hpp" #include "utils/terminate_handler.hpp" static bolt::Server* serverptr; Logger logger; -void sigint_handler(int s) -{ - auto signal = s == SIGINT ? "SIGINT" : "SIGABRT"; - - logger.info("Recieved signal {}", signal); - logger.info("Shutting down..."); - - std::exit(EXIT_SUCCESS); -} - static constexpr const char* interface = "0.0.0.0"; static constexpr const char* port = "7687"; -int main(void) -{ - // TODO figure out what is the relationship between this and signals - // that are configured below - std::set_terminate(&terminate_handler); +void throw_and_stacktace(std::string message) { + Stacktrace stacktrace; - // logger init -#ifdef SYNC_LOGGER - logging::init_sync(); -#else - logging::init_async(); -#endif - logging::log->pipe(std::make_unique()); + for (int i = 0; i < stacktrace.size(); i++) + message.append(fmt::format("\n at {} ({})", stacktrace[i].function, + stacktrace[i].location)); - // get Main logger - logger = logging::log->logger("Main"); - logger.info("{}", logging::log->type()); - - signal(SIGINT, sigint_handler); - signal(SIGABRT, sigint_handler); - - io::Socket socket; - - try - { - socket = io::Socket::bind(interface, port); - } - catch(io::NetworkError e) - { - logger.error("Cannot bind to socket on {} at {}", interface, port); - logger.error("{}", e.what()); - - std::exit(EXIT_FAILURE); - } - - socket.set_non_blocking(); - socket.listen(1024); - - logger.info("Listening on {} at {}", interface, port); - - bolt::Server server(std::move(socket)); - serverptr = &server; - - // TODO: N should be configurable - auto N = std::thread::hardware_concurrency(); - logger.info("Starting {} workers", N); - server.start(N); - - logger.info("Shutting down..."); - - return EXIT_SUCCESS; + logger.info(message); +} + +int main(void) { + // TODO figure out what is the relationship between this and signals + // that are configured below + std::set_terminate(&terminate_handler); + +// logger init +#ifdef SYNC_LOGGER + logging::init_sync(); +#else + logging::init_async(); +#endif + logging::log->pipe(std::make_unique()); + + // get Main logger + logger = logging::log->logger("Main"); + logger.info("{}", logging::log->type()); + + SignalHandler::register_handler(Signal::SegmentationFault, []() { + throw_and_stacktace("SegmentationFault signal raised"); + exit(1); + }); + + SignalHandler::register_handler(Signal::Terminate, []() { + throw_and_stacktace("Terminate signal raised"); + exit(1); + }); + + SignalHandler::register_handler(Signal::Abort, []() { + throw_and_stacktace("Abort signal raised"); + exit(1); + }); + + io::Socket socket; + + try { + socket = io::Socket::bind(interface, port); + } catch (io::NetworkError e) { + logger.error("Cannot bind to socket on {} at {}", interface, port); + logger.error("{}", e.what()); + + std::exit(EXIT_FAILURE); + } + + socket.set_non_blocking(); + socket.listen(1024); + + logger.info("Listening on {} at {}", interface, port); + + bolt::Server server(std::move(socket)); + serverptr = &server; + + // TODO: N should be configurable + auto N = std::thread::hardware_concurrency(); + logger.info("Starting {} workers", N); + server.start(N); + + logger.info("Shutting down..."); + + return EXIT_SUCCESS; } diff --git a/tests/unit/signal_handler.cpp b/tests/unit/signal_handler.cpp new file mode 100644 index 000000000..d5e83a8d8 --- /dev/null +++ b/tests/unit/signal_handler.cpp @@ -0,0 +1,27 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include +#include +#include + +#include "utils/signals/handler.hpp" +#include "utils/stacktrace.hpp" + +TEST_CASE("SignalHandler Segmentation Fault Test") { + SignalHandler::register_handler(Signal::SegmentationFault, []() { + std::cout << "Segmentation Fault" << std::endl; + Stacktrace stacktrace; + + int size = 10; + std::string message; + for (int i = 0; i < size; i++) { + message.append(fmt::format("\n at {} ({})", stacktrace[i].function, + stacktrace[i].location)); + } + std::cout << message << std::endl; + + }); + + std::raise(SIGSEGV); +}