- events tested and implemented multithreading support through mpscq

This commit is contained in:
2025-12-23 12:24:23 -05:00
parent 1f6637408d
commit 184bc7fcdf
12 changed files with 281 additions and 31 deletions

View File

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

View File

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

View File

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

View File

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