From 3dc0f849b55a89a64e76558a2dc2348a213bc468 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 5 Sep 2020 17:09:01 +0100 Subject: [PATCH] Fix bug with ~Event() calling a virtual method This solves a crash when an exception is thrown on the main thread (in test() for example, when setting json storage to xz but without liblzma support enabled). Thi also makes the program quit gracefully when SIGINT is received. It seems to also fix the problem with exceptions thrown in worker threads. --- src/eventia/event.cpp | 35 ++++++++++++++++++++++++++++++----- src/eventia/event.hpp | 26 ++++++++++++++++++++++++++ src/eventia/eventia.cpp | 6 ++++++ src/eventia/signal.cpp | 9 ++++----- src/eventia/timer.cpp | 9 ++++----- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/eventia/event.cpp b/src/eventia/event.cpp index b4ff82c..d9328bc 100644 --- a/src/eventia/event.cpp +++ b/src/eventia/event.cpp @@ -19,6 +19,13 @@ #include "eventia.hpp" #include "private/context.hpp" #include +#if !defined(NDEBUG) +# ifdef __GNUG__ +# include +# include +# include +# endif +#endif namespace eve { @@ -32,18 +39,36 @@ Event::Event (const Context& ctx) : Event::~Event() noexcept { m_eventia->unregister_stop_callback(m_cb_id); - on_loop_stopping_local(); } void Event::on_loop_stopping_local() noexcept { - if (not m_was_stopped) { - m_was_stopped = true; - this->on_loop_stopping(); - } + this->on_loop_stopping(); } void Event::set_exception (std::exception_ptr ptr) { m_eventia->set_exception(ptr); } +#if !defined(NDEBUG) +std::string Event::demangle (const char* name) { + //see: + //https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname + +#ifdef __GNUG__ + int status = -4; // some arbitrary value to eliminate the compiler warning + + // enable c++11 by passing the flag -std=c++11 to g++ + std::unique_ptr res { + abi::__cxa_demangle(name, NULL, NULL, &status), + std::free + }; + + return (status==0) ? res.get() : name ; +#else + // does nothing if not g++ + return name; +#endif +} +#endif + } //namespace eve diff --git a/src/eventia/event.hpp b/src/eventia/event.hpp index 231218f..9e4af69 100644 --- a/src/eventia/event.hpp +++ b/src/eventia/event.hpp @@ -18,6 +18,10 @@ #pragma once #include +#if !defined(NDEBUG) +# include +# include +#endif namespace eve { @@ -32,12 +36,34 @@ protected: virtual void on_loop_stopping() noexcept = 0; void set_exception (std::exception_ptr ptr); + template void stop_ifn(EV& eve); + private: void on_loop_stopping_local() noexcept; +#if !defined(NDEBUG) + static std::string demangle(const char* name); +#endif unsigned int m_cb_id; Eventia* m_eventia; bool m_was_stopped; }; +template +inline void Event::stop_ifn (EV& eve) { +#if !defined(NDEBUG) + const bool was_stopped = m_was_stopped; +#endif + + if (not m_was_stopped) { + m_was_stopped = true; + eve.stop(); + } + +#if !defined(NDEBUG) + std::cout << "Event stopped: " << demangle(typeid(EV).name()) << + " (was already stopped: " << std::boolalpha << was_stopped << ")\n"; +#endif +} + } //namespace eve diff --git a/src/eventia/eventia.cpp b/src/eventia/eventia.cpp index b71e06a..eeaaebd 100644 --- a/src/eventia/eventia.cpp +++ b/src/eventia/eventia.cpp @@ -76,6 +76,7 @@ Eventia::Eventia() : Eventia::~Eventia() noexcept { try { + this->stop(); this->wait(); } catch (std::runtime_error& err) { @@ -104,9 +105,14 @@ void Eventia::do_nothing() { } void Eventia::stop() { +#if !defined(NDEBUG) + std::cout << "Stopping Eventia (" << m_local->stop_cbs.size() << " observers)...\n"; +#endif for (auto& stop_cb : m_local->stop_cbs) { stop_cb.second(); } + m_local->async.send(); + m_local->async.stop(); m_local->loop.break_loop(ev::ALL); } diff --git a/src/eventia/signal.cpp b/src/eventia/signal.cpp index 02f94cc..6a6430c 100644 --- a/src/eventia/signal.cpp +++ b/src/eventia/signal.cpp @@ -59,17 +59,16 @@ Signal::Signal (int sig, const Context& ctx) : } } -Signal::~Signal() noexcept = default; +Signal::~Signal() noexcept { + Signal::on_loop_stopping(); +} void Signal::on_signal_ev() { this->on_signal(); } void Signal::on_loop_stopping() noexcept { -#if !defined(NDEBUG) - std::cout << "Signal::on_loop_stopping()\n"; -#endif - m_local->signal.stop(); + stop_ifn(m_local->signal); } } //namespace eve diff --git a/src/eventia/timer.cpp b/src/eventia/timer.cpp index 80bdfba..1906c45 100644 --- a/src/eventia/timer.cpp +++ b/src/eventia/timer.cpp @@ -60,7 +60,9 @@ Timer::Timer (double delay, const Context& ctx) : this->set_timer(delay); } -Timer::~Timer() noexcept = default; +Timer::~Timer() noexcept { + Timer::on_loop_stopping(); +} void Timer::on_timer_ev() { double& elapsed = m_local->elapsed; @@ -92,10 +94,7 @@ void Timer::set_timer (double delay) { } void Timer::on_loop_stopping() noexcept { -#if !defined(NDEBUG) - std::cout << "Timer::on_loop_stopping()\n"; -#endif - m_local->timer.stop(); + this->stop_ifn(m_local->timer); } } //namespace eve