Implement system init and deinit and event registration and deregistration

This commit is contained in:
Abdelrahman Said 2024-12-31 00:36:33 +00:00
parent 2de0c04b79
commit 0251507553
3 changed files with 117 additions and 102 deletions

View File

@ -5,7 +5,10 @@
#include <stdbool.h>
#include <sys/mman.h>
#define INVALID_EVENT ((Event) { .id = 0 })
#define INVALID_LISTENER ((EventListener){ .event = INVALID_EVENT, .id = 0 })
#define IS_INVALID_EVENT(EV) (EV.id == 0)
#define IS_INVALID_LISTENER(LS) (LS.id == 0)
struct event_system {
@ -22,19 +25,22 @@ struct event_system {
typedef struct event_slot EventSlot;
struct event_slot {
uptr offset;
bool free;
bool registered;
};
typedef struct event Event;
struct event {
typedef struct event_internal EventInternal;
struct event_internal {
u64 capacity;
u64 count;
EventCallback *callbacks[];
};
void *alloc(u64 size);
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 event_capacity, u64 initial_listeners_capacity) {
u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity) {
if (!es) {
return ES_INIT_NULL_POINTER;
}
@ -43,13 +49,19 @@ u32 es_init(EventSystem **es, u64 event_capacity, u64 initial_listeners_capacity
return ES_INIT_ALREADY_INITIALISED;
}
u64 callback_capacity = initial_listeners_capacity * 2;
u64 system = sizeof(EventSystem);
u64 event_slots = event_capacity * sizeof(EventSlot);
u64 free_slots = event_capacity * sizeof(u64);
u64 events = event_capacity * sizeof(Event);
u64 callbacks = event_capacity * callback_capacity * sizeof(EventCallback *);
u64 alloc_size = system + event_slots + free_slots + events + callbacks;
// 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);
// 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;
u8 *buffer = alloc(alloc_size);
if (!buffer) {
@ -65,70 +77,17 @@ u32 es_init(EventSystem **es, u64 event_capacity, u64 initial_listeners_capacity
event_system->alloc_size = alloc_size;
event_system->event_capacity = event_capacity;
event_system->event_count = 0;
event_system->free_count = event_capacity;
event_system->initial_callback_capacity = callback_capacity;
event_system->free_count = 0;
event_system->initial_callback_capacity = callback_capacity - 1;
event_system->events_offset = (uptr)system;
event_system->free_offset = (uptr)(system + event_slots);
event_system->callbacks_offset = (uptr)(system + event_slots + free_slots);
event_system->free_offset = (uptr)(system + event_offsets);
event_system->callbacks_offset = (uptr)(system + event_offsets + free_slots);
EventSlot *ev_slots_ptr = (EventSlot *)((uptr)event_system + event_system->events_offset);
u64 *free_slots_ptr = (u64 *)((uptr)event_system + event_system->free_offset);
EventSlot *ev_slots_array = get_event_slots_array(event_system);
u64 event_item_capacity = sizeof(Event) + callback_capacity * sizeof(EventCallback *);
u64 event_item_capacity = sizeof(EventInternal) + callback_capacity * sizeof(EventCallback *);
for (u64 i = 0; i < event_capacity; ++i) {
free_slots_ptr[i] = event_capacity - (i + 1);
ev_slots_ptr[i].offset = event_system->callbacks_offset + i * event_item_capacity;
}
return ES_INIT_SUCCESS;
}
void *alloc(u64 size) {
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
}
#if 0
struct event_system {
EventCallback *callbacks;
u64 *callback_count;
u64 *free;
u64 free_count;
u64 event_count;
u64 event_capacity;
u64 max_listeners_count;
};
void *alloc(u64 size);
void alloc_members(EventSystem *es, u64 event_capacity);
void default_init_event_system(EventSystem *es);
bool is_default_initialised(const EventSystem *es);
bool member_allocation_failed(const EventSystem *es);
u32 es_init(EventSystem **es, u64 event_capacity, u64 initial_listeners_capacity) {
if (!es) {
return ES_INIT_NULL_POINTER;
}
if (*es) {
return ES_INIT_ALREADY_INITIALISED;
}
*es = (EventSystem *)alloc(sizeof(EventSystem));
if (!*es) {
return ES_INIT_SYSTEM_ALLOC_FAILED;
}
EventSystem *system = *es;
system->free_count = 0;
system->event_count = 0;
system->event_capacity = event_capacity;
system->max_listeners_count = initial_listeners_capacity;
alloc_members(system, event_capacity);
if (member_allocation_failed(system)) {
default_init_event_system(system);
return ES_INIT_MEMBER_ALLOC_FAILED;
ev_slots_array[i].offset = event_system->callbacks_offset + i * event_item_capacity;
}
return ES_INIT_SUCCESS;
@ -141,20 +100,56 @@ void es_deinit(EventSystem **es) {
EventSystem *system = *es;
if (!is_default_initialised(system)) {
u64 event_capacity = system->event_capacity + 1;
munmap(system->callbacks, event_capacity * system->max_listeners_count * sizeof(EventCallback));
munmap(system->callback_count, event_capacity * sizeof(u64));
munmap(system->free, event_capacity * sizeof(u64));
}
munmap(system, sizeof(EventSystem));
munmap(system, system->alloc_size);
*es = NULL;
}
u32 es_register_event(EventSystem *es, u64 id) {}
Event es_register_event(EventSystem *es) {
Event event = INVALID_EVENT;
void es_deregister_event(EventSystem *es, u64 id) {}
if (!es) {
goto RETURN_EVENT;
}
EventSlot *event_slots_array = get_event_slots_array(es);
if (es->free_count > 0) {
u64 *free_array = get_free_array(es);
event.id = free_array[--(es->free_count)];
event_slots_array[event.id].registered = true;
free_array[es->free_count] = 0;
goto RETURN_EVENT;
}
if (es->event_count >= es->event_capacity) {
goto RETURN_EVENT;
}
event.id = ++(es->event_count);
event_slots_array[event.id].registered = true;
RETURN_EVENT:
return event;
}
void es_deregister_event(EventSystem *es, Event event) {
if (!es || IS_INVALID_EVENT(event)) {
return;
}
EventSlot *event_slots_array = get_event_slots_array(es);
u64 *free_array = get_free_array(es);
event_slots_array[event.id].registered = false;
free_array[(es->free_count)++] = event.id;
if (event.id == es->event_count) {
es->event_count -= 1;
}
}
EventListener es_add_event_listener(EventSystem *es, u64 id, EventCallback *listener) {}
@ -162,24 +157,21 @@ void es_remove_event_listener(EventSystem *es, EventListener listener) {}
void es_emit_event(EventSystem *es, u64 id, void *data) {}
void alloc_members(EventSystem *es, u64 event_capacity) {
es->callbacks = (EventCallback *)alloc(event_capacity * es->max_listeners_count * sizeof(EventCallback));
es->callback_count = (u64 *)alloc(event_capacity * sizeof(u64));
es->free = (u64 *)alloc(event_capacity * sizeof(u64));
// INTERNAL
void *alloc(u64 size) {
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
}
void default_init_event_system(EventSystem *es) {
*es = (EventSystem){0};
es->callbacks = (EventCallback *)es;
es->callback_count = (u64 *)es;
es->free = (u64 *)es;
EventSlot *get_event_slots_array(const EventSystem *es) {
return (EventSlot *)((uptr)es + es->events_offset);
}
bool is_default_initialised(const EventSystem *es) {
return es->callbacks == (EventCallback *)es || es->callback_count == (u64 *)es || es->free == (u64 *)es;
u64 *get_free_array(const EventSystem *es) {
return (u64 *)((uptr)es + es->free_offset);
}
bool member_allocation_failed(const EventSystem *es) {
return es->callbacks == NULL || es->callback_count == NULL || es->free == NULL;
EventInternal *get_event(const EventSystem *es, Event event) {
EventSlot *event_slots_array = get_event_slots_array(es);
return (EventInternal *)((uptr)es + event_slots_array[event.id].offset);
}
#endif

View File

@ -9,9 +9,14 @@ enum {
ES_INIT_ALLOCATION_FAILED,
};
typedef struct event Event;
struct event {
u64 id;
};
typedef struct event_listener EventListener;
struct event_listener {
u64 event;
Event event;
u64 id;
};
@ -19,10 +24,10 @@ typedef struct event_system EventSystem;
typedef void (EventCallback)(void *data);
u32 es_init(EventSystem **es, u64 event_capacity, u64 initial_event_listeners_count);
u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity);
void es_deinit(EventSystem **es);
u32 es_register_event(EventSystem *es, u64 id);
void es_deregister_event(EventSystem *es, u64 id);
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);

View File

@ -4,12 +4,30 @@
int main(void) {
EventSystem *es = NULL;
if (es_init(&es, 32, 64) != ES_INIT_SUCCESS) {
if (es_init(&es, 16, 64) != ES_INIT_SUCCESS) {
printf("INITIALISATION FAILED\n");
return 1;
}
// es_deinit(&es);
for (int i = 0; i < 40; ++i) {
Event ev = es_register_event(es);
printf("%lu\n", ev.id);
}
printf("\n");
unsigned int count = 6;
for (int i = 0; i < count; ++i) {
es_deregister_event(es, (Event){ .id = (i + 1) * 2 });
}
for (int i = 0; i < count; ++i) {
Event ev = es_register_event(es);
printf("%lu\n", ev.id);
}
es_deinit(&es);
return 0;
}