diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2024-11-04 17:19:45 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2024-11-04 17:19:45 -0500 |
| commit | 20a26c98b9a6708adb651474aa8bda08733342ac (patch) | |
| tree | 93e9d0a4739c60f66dee632984208ac9b89a8e1d /pkev.h | |
| parent | f249c81418bc08d5cef7ea33ac5ff2546ba53774 (diff) | |
pkev: 1st pass: growing event managers
note: creating more than
PK_EV_INIT_MGR_COUNT mgrs is unsupported.
A mgr is allocated into contiguous memory.
When the reserved number of evs or cbs is passed,
the offender grows by PK_EV_GROW_RATIO.
PK_EV_INIT_MGR_COUNT = 1
PK_EV_INIT_EV_COUNT = 16
PK_EV_INIT_CB_COUNT = 8
PK_EV_GROW_RATIO = 1.5
Diffstat (limited to 'pkev.h')
| -rw-r--r-- | pkev.h | 234 |
1 files changed, 176 insertions, 58 deletions
@@ -3,110 +3,228 @@ #include <stdint.h> -struct pk_ev_mgr; +typedef uint64_t pk_ev_mgr_id_T; typedef uint64_t pk_ev_id_T; -struct pk_ev_mgr *pk_ev_create(); -void pk_ev_destroy(struct pk_ev_mgr *evmgr); +// note: pk_ev_init() is NOT thread-safe +void pk_ev_init(); +// note: pk_ev_teardown() is NOT thread-safe +void pk_ev_teardown(); + +const pk_ev_mgr_id_T pk_ev_create_mgr(); +void pk_ev_destroy_mgr(pk_ev_mgr_id_T evmgr); typedef void (pk_ev_cb)(); -bool pk_ev_register_ev(struct pk_ev_mgr *evmgr, pk_ev_id_T evid); -bool pk_ev_register_cb(struct pk_ev_mgr *evmgr, pk_ev_id_T evid, pk_ev_cb *cb); -void pk_ev_emit(struct pk_ev_mgr *evmgr, pk_ev_id_T evid); +const pk_ev_id_T pk_ev_register_ev(pk_ev_mgr_id_T evmgr); +bool pk_ev_register_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb *cb); +void pk_ev_emit(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid); #endif /* PK_EV_H */ #ifdef PK_IMPL_EV -#include <stdio.h> #include <assert.h> +#include <stdatomic.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <threads.h> +#include <string.h> + +#ifndef PK_EV_INIT_MGR_COUNT +# define PK_EV_INIT_MGR_COUNT 1 +#endif -#ifndef PK_EV_MAX_COUNT -# define PK_EV_MAX_COUNT 16 +#ifndef PK_EV_INIT_EV_COUNT +# define PK_EV_INIT_EV_COUNT 16 #endif -#ifndef PK_EV_MAX_CB_COUNT -# define PK_EV_MAX_CB_COUNT 8 +#ifndef PK_EV_INIT_CB_COUNT +# define PK_EV_INIT_CB_COUNT 8 #endif struct pk_ev { - pk_ev_id_T evid; - pk_ev_cb *cb[PK_EV_MAX_CB_COUNT]; - uint8_t n_cb; + pk_ev_cb **cb; + atomic_uint_fast8_t n_cb; }; struct pk_ev_mgr { - struct pk_ev ev[PK_EV_MAX_COUNT]; - uint8_t n_ev; + struct pk_ev *ev; + atomic_uint_fast8_t n_ev; + atomic_uint_fast8_t rn_ev; + atomic_uint_fast8_t rn_cb; }; -inline struct pk_ev_mgr* -pk_ev_create() +struct pk_ev_mstr { + atomic_uint_fast64_t flg_mgrs; + atomic_uint_fast64_t rn_mgrs; + struct pk_ev_mgr **mgrs; + mtx_t *mtxs; +}; + +struct pk_ev_mstr pk_ev_mstr; + +inline void +pk_ev_init() { - struct pk_ev_mgr *mgr = (struct pk_ev_mgr*)malloc(sizeof(struct pk_ev_mgr)); - if (mgr == NULL) return NULL; - memset(mgr, 0, sizeof(struct pk_ev_mgr)); - return mgr; + int i; + pk_ev_mstr.mgrs = (struct pk_ev_mgr **)malloc(sizeof(void *) * PK_EV_INIT_MGR_COUNT); + pk_ev_mstr.mtxs = (mtx_t*)malloc(sizeof(mtx_t) * PK_EV_INIT_MGR_COUNT); + memset(pk_ev_mstr.mgrs, 0, sizeof(void *) * PK_EV_INIT_MGR_COUNT); + memset(pk_ev_mstr.mtxs, 0, sizeof(mtx_t) * PK_EV_INIT_MGR_COUNT); + for (i = 0; i < PK_EV_INIT_MGR_COUNT; ++i) { + mtx_init(&pk_ev_mstr.mtxs[i], mtx_plain); + } + atomic_store(&pk_ev_mstr.flg_mgrs, 0); + atomic_store(&pk_ev_mstr.rn_mgrs, PK_EV_INIT_MGR_COUNT); } inline void -pk_ev_destroy(struct pk_ev_mgr *evmgr) +pk_ev_teardown() { - assert(evmgr != NULL); - memset(evmgr, 0, sizeof(struct pk_ev_mgr)); - free(evmgr); + int i; + for (i = 0; i < pk_ev_mstr.rn_mgrs; ++i) { + if ((atomic_load(&pk_ev_mstr.rn_mgrs) & (1lu << i)) == 0) continue; + mtx_lock(&pk_ev_mstr.mtxs[i]); + free(pk_ev_mstr.mgrs[i]); + pk_ev_mstr.mgrs[i] = NULL; + mtx_unlock(&pk_ev_mstr.mtxs[i]); + mtx_destroy(&pk_ev_mstr.mtxs[i]); + } + free(pk_ev_mstr.mgrs); + free(pk_ev_mstr.mtxs); + pk_ev_mstr.mgrs = NULL; + pk_ev_mstr.mtxs = NULL; } -inline bool -pk_ev_register_ev(struct pk_ev_mgr *evmgr, pk_ev_id_T evid) +static inline struct pk_ev_mgr* +pk_ev_inner_ev_mgr_create(uint64_t ev_count, uint64_t cb_count) { - assert(evmgr != NULL); int i; - for (i = 0; i < evmgr->n_ev; ++i) { - if (evmgr->ev[i].evid == evid) { - return false; - } + struct pk_ev *ev; + size_t sz = sizeof(struct pk_ev_mgr) + ((sizeof(struct pk_ev) * ev_count)) + (sizeof (void *) * ev_count * cb_count); + size_t sz_ev = (sizeof(pk_ev_cb*) * cb_count); + size_t sz_evs = sizeof(struct pk_ev) * ev_count; + + struct pk_ev_mgr *mgr = (struct pk_ev_mgr*)malloc(sz); + if (mgr == NULL) goto early_exit; + + memset(mgr, 0, sz); + mgr->ev = (struct pk_ev*)(((char *)mgr) + sizeof(struct pk_ev_mgr)); + atomic_init(&mgr->rn_ev, ev_count); + atomic_init(&mgr->rn_cb, cb_count); + atomic_init(&mgr->n_ev, 0); + for (i = 0; i < mgr->rn_ev; ++i) { + ev = &mgr->ev[i]; + atomic_init(&ev->n_cb, 0); + ev->cb = (pk_ev_cb**)(((char *)mgr) + sizeof(struct pk_ev_mgr) + sz_evs + (sz_ev * i)); } - evmgr->ev[evmgr->n_ev].evid = evid; - evmgr->n_ev++; - return true; + +early_exit: + return mgr; } -inline bool -pk_ev_register_cb(struct pk_ev_mgr *evmgr, pk_ev_id_T evid, pk_ev_cb *cb) +static inline void +pk_ev_inner_ev_mgr_clone(struct pk_ev_mgr *old, struct pk_ev_mgr *mgr) { - assert(evmgr != NULL); - struct pk_ev *ev = {0}; int i; - for (i = 0; i < evmgr->n_ev; ++i) { - if (evmgr->ev[i].evid == evid) { - ev = &evmgr->ev[i]; + struct pk_ev *ev_old; + struct pk_ev *ev; + atomic_store(&mgr->n_ev, atomic_load(&old->n_ev)); + for (i = 0; i < old->n_ev; ++i) { + ev_old = &old->ev[i]; + ev = &mgr->ev[i]; + memcpy(ev->cb, ev_old->cb, sizeof(pk_ev_cb*) * atomic_load(&ev_old->n_cb)); + atomic_store(&ev->n_cb, atomic_load(&ev_old->n_cb)); + } +} + +inline const pk_ev_mgr_id_T +pk_ev_create_mgr() +{ + uint64_t i; + pk_ev_mgr_id_T flg; + pk_ev_mgr_id_T flg_new; + pk_ev_mgr_id_T id; + struct pk_ev_mgr *mgr = pk_ev_inner_ev_mgr_create(PK_EV_INIT_EV_COUNT, PK_EV_INIT_CB_COUNT); + if (mgr == NULL) return -1; +start: + flg = atomic_load(&pk_ev_mstr.flg_mgrs); + while (1) { + flg_new = flg; + for (i = 0; i < atomic_load(&pk_ev_mstr.rn_mgrs); ++i) { + if ((flg & (1u << i)) == 0) break; + } + if (i == atomic_load(&pk_ev_mstr.rn_mgrs)) { + goto recreate; } + id = i; + flg_new |= (1u << i); + if (atomic_compare_exchange_strong(&pk_ev_mstr.flg_mgrs, &flg, flg_new)) break; + thrd_yield(); + } + pk_ev_mstr.mgrs[id]= mgr; + return id; +recreate: + // TODO recreate mgr, out of space + assert(1 == 0 && "[pkev.h] Out of mgr space."); + exit(1); + goto start; +} + +inline void +pk_ev_destroy_mgr(pk_ev_mgr_id_T evmgr) +{ + assert(evmgr >= 0); + mtx_lock(&pk_ev_mstr.mtxs[evmgr]); + free(pk_ev_mstr.mgrs[evmgr]); + pk_ev_mstr.mgrs[evmgr] = NULL; + mtx_unlock(&pk_ev_mstr.mtxs[evmgr]); +} + +inline const pk_ev_id_T +pk_ev_register_ev(pk_ev_mgr_id_T evmgr) +{ + assert(evmgr < 64); + pk_ev_id_T id; + struct pk_ev_mgr *mgr; + mtx_lock(&pk_ev_mstr.mtxs[evmgr]); + if (pk_ev_mstr.mgrs[evmgr]->n_ev == pk_ev_mstr.mgrs[evmgr]->rn_ev) { + mgr = pk_ev_inner_ev_mgr_create(pk_ev_mstr.mgrs[evmgr]->rn_ev * 1.5, pk_ev_mstr.mgrs[evmgr]->rn_cb); + pk_ev_inner_ev_mgr_clone(pk_ev_mstr.mgrs[evmgr], mgr); + free(pk_ev_mstr.mgrs[evmgr]); + pk_ev_mstr.mgrs[evmgr] = mgr; + } + id = pk_ev_mstr.mgrs[evmgr]->n_ev++; + mtx_unlock(&pk_ev_mstr.mtxs[evmgr]); + return id; +} + +inline bool +pk_ev_register_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb *cb) +{ + assert(evmgr < 64); + struct pk_ev_mgr *mgr; + mtx_lock(&pk_ev_mstr.mtxs[evmgr]); + if (pk_ev_mstr.mgrs[evmgr]->ev[evid].n_cb == pk_ev_mstr.mgrs[evmgr]->rn_cb) { + mgr = pk_ev_inner_ev_mgr_create(pk_ev_mstr.mgrs[evmgr]->rn_ev, pk_ev_mstr.mgrs[evmgr]->rn_cb * 1.5); + pk_ev_inner_ev_mgr_clone(pk_ev_mstr.mgrs[evmgr], mgr); + free(pk_ev_mstr.mgrs[evmgr]); + pk_ev_mstr.mgrs[evmgr] = mgr; } - if (ev == NULL) return false; - ev->cb[ev->n_cb] = cb; - ev->n_cb++; + pk_ev_mstr.mgrs[evmgr]->ev[evid].cb[pk_ev_mstr.mgrs[evmgr]->ev[evid].n_cb++] = cb; + mtx_unlock(&pk_ev_mstr.mtxs[evmgr]); return true; } inline void -pk_ev_emit(struct pk_ev_mgr *evmgr, pk_ev_id_T evid) +pk_ev_emit(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid) { - assert(evmgr != NULL); + assert(evmgr < 64); uint8_t i; - struct pk_ev *ev = {0}; - for (i = 0; i < evmgr->n_ev; ++i) { - if (evmgr->ev[i].evid == evid) { - ev = &evmgr->ev[i]; - break; - } - } - if (ev == NULL) return; - for (i = 0; i < ev->n_cb; ++i) { - (*ev->cb[i])(); + for (i = 0; i < pk_ev_mstr.mgrs[evmgr]->ev[evid].n_cb; ++i) { + (*pk_ev_mstr.mgrs[evmgr]->ev[evid].cb[i])(); } } |
