- events tested and implemented multithreading support through mpscq
This commit is contained in:
@@ -19,14 +19,41 @@
|
||||
#include <fennec/containers/dynarray.h>
|
||||
#include <fennec/containers/set.h>
|
||||
#include <fennec/core/event.h>
|
||||
#include <fennec/threading/lock_guard.h>
|
||||
#include <fennec/threading/mpscq.h>
|
||||
#include <fennec/threading/mutex.h>
|
||||
|
||||
#define FENNEC_EVENT_QUEUE_SIZE 8192
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
static mutex lock;
|
||||
static dynarray<set<event_listener*>> listeners;
|
||||
static mpscq<event> queue(FENNEC_EVENT_QUEUE_SIZE);
|
||||
|
||||
void event::handle_events() {
|
||||
lock_guard guard(lock);
|
||||
|
||||
// if we don't copy into a temporary buffer, we could deadlock ourselves
|
||||
// if someone unwittingly calls dispatch() in an event listener.
|
||||
dynarray<unique_ptr<event>> dispatch(FENNEC_EVENT_QUEUE_SIZE);
|
||||
|
||||
// we query the size instead of empty just in case someone decides to run their own thread
|
||||
// and send events from that thread.
|
||||
size_t n = queue.size();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
dispatch[i] = queue.pop();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
_handle_event(dispatch[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void event::_add_listener(event_listener* listener, uint64_t type) {
|
||||
lock_guard guard(lock);
|
||||
|
||||
void event::add_listener(event_listener* listener, uint64_t type) {
|
||||
if (listeners.size() <= type) {
|
||||
listeners.resize(type + 1);
|
||||
}
|
||||
@@ -34,9 +61,29 @@ void event::add_listener(event_listener* listener, uint64_t type) {
|
||||
}
|
||||
|
||||
void event::remove_listener(event_listener* listener) {
|
||||
lock_guard guard(lock);
|
||||
|
||||
for (auto& it : listeners) {
|
||||
it.erase(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void event::_handle_event(unique_ptr<event>& event) {
|
||||
auto type = event->get_type().id();
|
||||
for (auto& listener : listeners[type]) {
|
||||
listener->handle_event(event.get());
|
||||
}
|
||||
}
|
||||
|
||||
void event::_dispatch(unique_ptr<event>&& event) {
|
||||
// queue is taking ownership of the resource
|
||||
queue.emplace(event.release());
|
||||
}
|
||||
|
||||
void event::_dispatch_immediate(unique_ptr<event>&& event) {
|
||||
lock_guard guard(lock);
|
||||
|
||||
_handle_event(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,17 +16,24 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fennec/core/logger.h>
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
void _assert_callback(const char* expression, const char* file, int line, const char* function, const char* description)
|
||||
void _assert_callback(const fennec::cstring& expr, const fennec::cstring& file, int line, const fennec::cstring& func, const fennec::cstring& desc)
|
||||
{
|
||||
// Skip
|
||||
// __assert_callback
|
||||
// __assert_impl
|
||||
printf("Assert failed: \"%s\" \n"
|
||||
fennec::logger::log(fennec::format(""
|
||||
"Assert failed: \"{}\" \n"
|
||||
"At {}:{} in {} \n"
|
||||
"Description: {} \n"
|
||||
"Stacktrace: \n",
|
||||
expr, file, line, func, desc
|
||||
));
|
||||
/*printf("Assert failed: \"%s\" \n"
|
||||
"At %s:%d in %s \n"
|
||||
"Description: %s \n",
|
||||
expression, file, line, function, description);
|
||||
expression, file, line, function, description);*/
|
||||
cpptrace::generate_trace(2).print();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,21 @@
|
||||
// =====================================================================================================================
|
||||
|
||||
#include <fennec/lang/detail/_stdlib.h>
|
||||
#include <fennec/string/cstring.h>
|
||||
|
||||
void _assert_callback(const char* expression, const char* file, int line, const char* function, const char* description);
|
||||
void _assert_callback(const fennec::cstring& expr, const fennec::cstring& file, int line, const fennec::cstring& func, const fennec::cstring& desc);
|
||||
|
||||
void _assert_impl(const char* expression, const char* file, int line, const char* function, const char* description, bool halt)
|
||||
void _assert_impl(const char* expr, size_t expr_l,
|
||||
const char* file, size_t file_l, int line,
|
||||
const char* func, size_t func_l,
|
||||
const char* desc, bool halt)
|
||||
{
|
||||
_assert_callback(expression, file, line, function, description);
|
||||
_assert_callback(
|
||||
fennec::cstring(expr, expr_l),
|
||||
fennec::cstring(file, file_l), line,
|
||||
fennec::cstring(func, func_l),
|
||||
fennec::cstring(desc, ::strlen(desc) + 1)
|
||||
);
|
||||
|
||||
if (halt) {
|
||||
::abort();
|
||||
|
||||
@@ -70,6 +70,7 @@ void window_manager::shutdown() {
|
||||
}
|
||||
|
||||
assertf(_thread == thread::current(), "Attempted to shutdown Window Manager on a different thread!");
|
||||
lock_guard guard(_lock);
|
||||
|
||||
// Cleanup Windows
|
||||
for (auto& window : _windows) {
|
||||
@@ -84,31 +85,47 @@ void window_manager::shutdown() {
|
||||
}
|
||||
|
||||
void window_manager::dispatch() {
|
||||
assertf(_thread == thread::current(), "Attempted to dispatch Window Manager on a different thread!");
|
||||
if (not _display) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertf(_thread == thread::current(), "Attempted to dispatch Window Manager on a different thread!");
|
||||
lock_guard guard(_lock);
|
||||
|
||||
_display->dispatch();
|
||||
}
|
||||
|
||||
window_manager::window_id window_manager::create_window(const window::config& config, window_id parent) {
|
||||
assertf(_thread == thread::current(), "Attempted to create a window on a different thread!");
|
||||
if (not _display) {
|
||||
return nullid;
|
||||
}
|
||||
|
||||
assertf(_thread == thread::current(), "Attempted to create a window on a different thread!");
|
||||
lock_guard guard(_lock);
|
||||
|
||||
window* p = parent == nullid ? nullptr : _windows[parent].get();
|
||||
return _windows.emplace(_display->create_window(config, p));
|
||||
}
|
||||
|
||||
void window_manager::begin(window_id window) {
|
||||
assertf(_thread == thread::current(), "Attempted to set window context on a different thread!");
|
||||
if (not _display) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertf(_thread == thread::current(), "Attempted to set window context on a different thread!");
|
||||
lock_guard guard(_lock);
|
||||
|
||||
_windows[window]->begin_frame();
|
||||
}
|
||||
|
||||
void window_manager::end(window_id window) {
|
||||
assertf(_thread == thread::current(), "Attempted to set window context on a different thread!");
|
||||
if (not _display) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertf(_thread == thread::current(), "Attempted to set window context on a different thread!");
|
||||
lock_guard guard(_lock);
|
||||
|
||||
_windows[window]->end_frame();
|
||||
}
|
||||
} // fennec
|
||||
Reference in New Issue
Block a user