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:
King_DuckZ 2020-09-05 17:09:01 +01:00
parent a32044a4b5
commit 3dc0f849b5
5 changed files with 70 additions and 15 deletions

View file

@ -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();
}
}
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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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