diff options
author | Paul Wicks <pwicks86@gmail.com> | 2018-07-10 13:38:27 -0700 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2020-12-19 12:59:25 +0100 |
commit | 6d6c9a254102374d3fdbc4c39eac0b67e07168b7 (patch) | |
tree | 62028d8c95483062382c334bb4cdb8ef98fa5967 /gnuradio-runtime/lib/terminate_handler.cc | |
parent | a5e49d9120e8d0d7adf4de792cc3c4bc1a6defbc (diff) |
runtime: Add terminate handling
This consists of the following changes:
1. Add a top_block parameter to control exception handling
This restores past behavior where the scheduler catches exceptions
raised in block threads, allowing flowgraphs to continue running after
the failure of an individual block. It also adds optional new behavior,
selected by setting catch_exceptions=False to the top block, which causes
exceptions to not be caught. In this mode of operation, a std::terminate
handler can be installed to print a stack trace before the flowgraph exits.
2. Add terminate_handler to top_block_impl
This adds a terminate_handler function that prints information
about any uncaught exceptions and also attempts to print a backtrace
for said exception after which it calls std::abort. The backtrace is
printed via libunwind, which is a new optional dependency. If libunwind
is not found/installed, then the terminate handler will still print
information about the exception and then exit.
Co-Authored-By: Scott Torborg <storborg@gmail.com>
Diffstat (limited to 'gnuradio-runtime/lib/terminate_handler.cc')
-rw-r--r-- | gnuradio-runtime/lib/terminate_handler.cc | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/gnuradio-runtime/lib/terminate_handler.cc b/gnuradio-runtime/lib/terminate_handler.cc new file mode 100644 index 0000000000..ed3b1d93b4 --- /dev/null +++ b/gnuradio-runtime/lib/terminate_handler.cc @@ -0,0 +1,147 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <pmt/pmt.h> +#include <boost/thread.hpp> +#include <exception> +#include <iostream> +#include <regex> +#include <stdexcept> + +#include <cxxabi.h> + +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <cstdio> +#include <cstdlib> +#endif + +namespace gr { + +#ifdef HAVE_LIBUNWIND +void print_backtrace() +{ + unw_cursor_t cursor; + unw_context_t context; + + // Initialize cursor to current frame for local unwinding. + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + // Unwind frames one by one, going up the frame stack. + while (unw_step(&cursor) > 0) { + unw_word_t offset, pc; + unw_get_reg(&cursor, UNW_REG_IP, &pc); + if (pc == 0) { + break; + } + std::fprintf(stderr, "0x%lx:", pc); + + char sym[256]; + if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { + char* nameptr = sym; + int status; + char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &status); + if (status == 0) { + nameptr = demangled; + } + std::fprintf(stderr, " (%s+0x%lx)\n", nameptr, offset); + std::free(demangled); + } else { + std::fprintf(stderr, + " -- error: unable to obtain symbol name for this frame\n"); + } + } +} +#endif + +void terminate_handler_impl() +{ + std::cerr << "terminate reached from thread id: " << boost::this_thread::get_id(); + try { + std::exception_ptr eptr = std::current_exception(); + if (eptr) { + std::rethrow_exception(eptr); + } + } catch (const std::out_of_range& e) { + std::cerr << "Got std::out_of_range" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::length_error& e) { + std::cerr << "Got std::length_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::domain_error& e) { + std::cerr << "Got std::domain_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::invalid_argument& e) { + std::cerr << "Got std::invalid_argument" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const pmt::exception& e) { + std::cerr << "Got pmt::exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::logic_error& e) { + std::cerr << "Got std::logic_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::ios_base::failure& e) { + std::cerr << "Got std::ios_base::falure" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::system_error& e) { + std::cerr << "Got std::system_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::regex_error& e) { + std::cerr << "Got std::regex_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::underflow_error& e) { + std::cerr << "Got std::underflow_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::overflow_error& e) { + std::cerr << "Got std::overflow_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::range_error& e) { + std::cerr << "Got std::range_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::runtime_error& e) { + std::cerr << "Got std::runtime_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_typeid& e) { + std::cerr << "Got std::bad_typeid" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_cast& e) { + std::cerr << "Got std::bad_cast" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_weak_ptr& e) { + std::cerr << "Got std::bad_weak_ptr" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_function_call& e) { + std::cerr << "Got std::bad_function_call" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_array_new_length& e) { + std::cerr << "Got std::bad_array_new_length" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_alloc& e) { + std::cerr << "Got std::bad_alloc" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_exception& e) { + std::cerr << "Got std::bad_exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::exception& e) { + std::cerr << "Got std::exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (...) { + std::cerr << "Got unknown exception" << std::endl; + } +#ifdef HAVE_LIBUNWIND + // Use libunwind to print a backtrace + print_backtrace(); +#endif + std::abort(); +} + +void install_terminate_handler() { std::set_terminate(&terminate_handler_impl); } +} // namespace gr |