Implement system init and deinit and event registration and deregistration
This commit is contained in:
		| @@ -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); | ||||
| 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; | ||||
|   // 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 event_slots       = event_capacity * sizeof(EventSlot); | ||||
|   // 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(Event); | ||||
|   u64 events             = event_capacity * sizeof(EventInternal); | ||||
|   u64 callbacks          = event_capacity * callback_capacity * sizeof(EventCallback *); | ||||
|   u64 alloc_size        = system + event_slots + free_slots + events + callbacks; | ||||
|   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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										22
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -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; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user