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.
This commit is contained in:
parent
a32044a4b5
commit
3dc0f849b5
5 changed files with 70 additions and 15 deletions
|
@ -19,6 +19,13 @@
|
|||
#include "eventia.hpp"
|
||||
#include "private/context.hpp"
|
||||
#include <cassert>
|
||||
#if !defined(NDEBUG)
|
||||
# ifdef __GNUG__
|
||||
# include <cstdlib>
|
||||
# include <memory>
|
||||
# include <cxxabi.h>
|
||||
# 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<char, void(*)(void*)> 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
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#if !defined(NDEBUG)
|
||||
# include <iostream>
|
||||
# include <typeinfo>
|
||||
#endif
|
||||
|
||||
namespace eve {
|
||||
|
||||
|
@ -32,12 +36,34 @@ protected:
|
|||
virtual void on_loop_stopping() noexcept = 0;
|
||||
void set_exception (std::exception_ptr ptr);
|
||||
|
||||
template <typename EV> 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 <typename EV>
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue