diff --git a/src/event_system.c b/src/event_system.c index ba38d72..2d4f894 100644 --- a/src/event_system.c +++ b/src/event_system.c @@ -5,13 +5,16 @@ #include #include +#define INVALID_SYSTEM ((EventSystem){ .id = 0 }) #define INVALID_EVENT ((Event) { .id = 0 }) #define INVALID_LISTENER ((EventListener){ .event = INVALID_EVENT, .id = 0 }) +#define IS_INVALID_SYSTEM(ES) (ES.id == 0) #define IS_INVALID_EVENT(EV) (EV.id == 0) #define IS_INVALID_LISTENER(LS) (LS.id == 0) -struct event_system { +typedef struct es_internal ESInternal; +struct es_internal { u64 alloc_size; u64 event_capacity; u64 event_count; @@ -32,86 +35,100 @@ typedef struct event_internal EventInternal; struct event_internal { u64 capacity; u64 count; - EventCallback *callbacks[]; + u64 free_count; + u64 *free; + EventCallback *callbacks; }; -void *alloc(u64 size); -EventSlot *get_event_slots_array(const EventSystem *es); -u64 *get_free_array(const EventSystem *es); -EventInternal *get_event(const EventSystem *es, Event event); - -u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity) { - if (!es) { - return ES_INIT_NULL_POINTER; - } - - if (*es) { - return ES_INIT_ALREADY_INITIALISED; - } +internal void *alloc(u64 size); +internal ESInternal *get_event_system_internal(EventSystem event_system); +internal EventSlot *get_event_slots_array(const ESInternal *es); +internal u64 *get_free_array(const ESInternal *es); +internal EventInternal *get_event(const ESInternal *es, Event event); +internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset); +EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity) { // Double event capacity to reduce chances of reallocation u64 event_capacity = initial_event_capacity * 2; - // Increase listener capacity by one to account for 0th EventListener being invalid - u64 listeners_capacity = initial_listeners_capacity + 1; // Double listener capacity to reduce chances of reallocation - u64 callback_capacity = listeners_capacity * 2; - u64 system = sizeof(EventSystem); + u64 callback_capacity = initial_listeners_capacity * 2; + u64 system = sizeof(ESInternal); // Increase event capacity by one to account for 0th Event being invalid u64 event_offsets = (event_capacity + 1) * sizeof(EventSlot); u64 free_slots = event_capacity * sizeof(u64); u64 events = event_capacity * sizeof(EventInternal); - u64 callbacks = event_capacity * callback_capacity * sizeof(EventCallback *); - u64 alloc_size = system + event_offsets + free_slots + events + callbacks; + // Increase listener capacity by one to account for 0th EventListener being invalid + u64 event_callbacks = (callback_capacity + 1) * sizeof(EventCallback *); + u64 event_free = callback_capacity * sizeof(u64 *); + u64 callbacks = event_capacity * event_callbacks; + u64 free_callbacks = event_capacity * event_free; + u64 alloc_size = system + event_offsets + free_slots + events + callbacks + free_callbacks; + EventSystem es = INVALID_SYSTEM; + + // NOTE (Abdelrahman): The idea here is to have a single buffer that holds all the data. + // For the purposes of this test, offsets are manually calculated to different parts of the buffer. + // An actual implementation of this should probably use an internal memory arena making allocations + // easier, while still maintaining all data in a single buffer. u8 *buffer = alloc(alloc_size); if (!buffer) { - return ES_INIT_ALLOCATION_FAILED; + goto RETURN_SYSTEM; } memset(buffer, 0, alloc_size); - *es = (EventSystem *)buffer; + es.id = (u64)buffer; - EventSystem *event_system = *es; + ESInternal *event_system = (ESInternal *)buffer; event_system->alloc_size = alloc_size; event_system->event_capacity = event_capacity; event_system->event_count = 0; event_system->free_count = 0; - event_system->initial_callback_capacity = callback_capacity - 1; + event_system->initial_callback_capacity = callback_capacity; event_system->events_offset = (uptr)system; event_system->free_offset = (uptr)(system + event_offsets); event_system->callbacks_offset = (uptr)(system + event_offsets + free_slots); - EventSlot *ev_slots_array = get_event_slots_array(event_system); + EventSlot *ev_slots = get_event_slots_array(event_system); - u64 event_item_capacity = sizeof(EventInternal) + callback_capacity * sizeof(EventCallback *); + u64 event_item_capacity = sizeof(EventInternal) + event_callbacks + event_free; + EventInternal *event; + uptr offset; for (u64 i = 0; i < event_capacity; ++i) { - ev_slots_array[i].offset = event_system->callbacks_offset + i * event_item_capacity; + offset = event_system->callbacks_offset + i * event_item_capacity; + ev_slots[i + 1].offset = offset; + event = get_event_from_offset(event_system, offset); + event->capacity = callback_capacity; + // WARN (Abdelrahman): As mentioned above, an actual arena would be very useful here. The below + // would break if the order of the EventInternal struct changes + event->free = (u64 *)((uptr)event_system + offset + sizeof(EventInternal)); + event->callbacks = (EventCallback *)((uptr)event_system + offset + sizeof(EventInternal) + event_free); } - return ES_INIT_SUCCESS; +RETURN_SYSTEM: + return es; } -void es_deinit(EventSystem **es) { - if (!es || !*es) { +void es_deinit(EventSystem event_system) { + if (IS_INVALID_SYSTEM(event_system)) { return; } - EventSystem *system = *es; + ESInternal *es = get_event_system_internal(event_system); - munmap(system, system->alloc_size); - *es = NULL; + munmap(system, es->alloc_size); } -Event es_register_event(EventSystem *es) { +Event es_register_event(EventSystem event_system) { Event event = INVALID_EVENT; - if (!es) { + if (IS_INVALID_SYSTEM(event_system)) { goto RETURN_EVENT; } - EventSlot *event_slots_array = get_event_slots_array(es); + ESInternal *es = get_event_system_internal(event_system); + EventSlot *event_slots_array = get_event_slots_array(es); if (es->free_count > 0) { u64 *free_array = get_free_array(es); @@ -125,6 +142,7 @@ Event es_register_event(EventSystem *es) { } if (es->event_count >= es->event_capacity) { + // TODO (Abdelrahman): Handle reallocating when out of events goto RETURN_EVENT; } @@ -135,8 +153,13 @@ RETURN_EVENT: return event; } -void es_deregister_event(EventSystem *es, Event event) { - if (!es || IS_INVALID_EVENT(event)) { +void es_deregister_event(EventSystem event_system, Event event) { + if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT(event)) { + return; + } + + ESInternal *es = get_event_system_internal(event_system); + if (event.id > es->event_count) { return; } @@ -151,27 +174,35 @@ void es_deregister_event(EventSystem *es, Event event) { } } -EventListener es_add_event_listener(EventSystem *es, u64 id, EventCallback *listener) {} +EventListener es_add_event_listener(EventSystem event_system, Event event, EventCallback *listener) {} -void es_remove_event_listener(EventSystem *es, EventListener listener) {} +void es_remove_event_listener(EventSystem event_system, EventListener listener) {} -void es_emit_event(EventSystem *es, u64 id, void *data) {} +void es_emit_event(EventSystem event_system, Event event, void *data) {} // INTERNAL -void *alloc(u64 size) { +internal void *alloc(u64 size) { return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0); } -EventSlot *get_event_slots_array(const EventSystem *es) { +internal ESInternal *get_event_system_internal(EventSystem event_system) { + return (ESInternal *)event_system.id; +} + +internal EventSlot *get_event_slots_array(const ESInternal *es) { return (EventSlot *)((uptr)es + es->events_offset); } -u64 *get_free_array(const EventSystem *es) { +internal u64 *get_free_array(const ESInternal *es) { return (u64 *)((uptr)es + es->free_offset); } -EventInternal *get_event(const EventSystem *es, Event event) { +internal EventInternal *get_event(const ESInternal *es, Event event) { EventSlot *event_slots_array = get_event_slots_array(es); - return (EventInternal *)((uptr)es + event_slots_array[event.id].offset); + return get_event_from_offset(es, event_slots_array[event.id].offset); +} + +internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset) { + return (EventInternal *)((uptr)es + offset); } diff --git a/src/event_system.h b/src/event_system.h index 19a14a7..69a153c 100644 --- a/src/event_system.h +++ b/src/event_system.h @@ -9,6 +9,11 @@ enum { ES_INIT_ALLOCATION_FAILED, }; +typedef struct event_system EventSystem; +struct event_system { + u64 id; +}; + typedef struct event Event; struct event { u64 id; @@ -20,14 +25,12 @@ struct event_listener { u64 id; }; -typedef struct event_system EventSystem; - typedef void (EventCallback)(void *data); -u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity); -void es_deinit(EventSystem **es); -Event es_register_event(EventSystem *es); -void es_deregister_event(EventSystem *es, Event event); -EventListener es_add_event_listener(EventSystem *es, u64 id, EventCallback *listener); -void es_remove_event_listener(EventSystem *es, EventListener listener); -void es_emit_event(EventSystem *es, u64 id, void *data); +EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity); +void es_deinit(EventSystem event_system); +Event es_register_event(EventSystem event_system); +void es_deregister_event(EventSystem event_system, Event event); +EventListener es_add_event_listener(EventSystem event_system, Event event, EventCallback *listener); +void es_remove_event_listener(EventSystem event_system, EventListener listener); +void es_emit_event(EventSystem event_system, Event event, void *data); diff --git a/src/main.c b/src/main.c index a674604..2e23d5f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,13 +1,8 @@ #include "event_system.h" #include -#include int main(void) { - EventSystem *es = NULL; - if (es_init(&es, 16, 64) != ES_INIT_SUCCESS) { - printf("INITIALISATION FAILED\n"); - return 1; - } + EventSystem es = es_init(16, 64); for (int i = 0; i < 40; ++i) { Event ev = es_register_event(es); @@ -27,7 +22,7 @@ int main(void) { printf("%lu\n", ev.id); } - es_deinit(&es); + es_deinit(es); return 0; }