summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkev.h112
-rw-r--r--test/pkev.cpp76
2 files changed, 165 insertions, 23 deletions
diff --git a/pkev.h b/pkev.h
index 0ff010f..9ae9260 100644
--- a/pkev.h
+++ b/pkev.h
@@ -9,6 +9,10 @@ typedef uint64_t pk_ev_mgr_id_T;
typedef uint64_t pk_ev_id_T;
typedef uint64_t pk_ev_cb_id_T;
+const pk_ev_mgr_id_T pk_ev_mgr_id_T_MAX = 0xFFFFFFFFFFFFFFFF;
+const pk_ev_id_T pk_ev_id_T_MAX = 0xFFFFFFFFFFFFFFFF;
+const pk_ev_cb_id_T pk_ev_cb_id_T_MAX = 0xFFFFFFFFFFFFFFFF;
+
// TODO re-think threading
// note: pk_ev_init() is NOT thread-safe
@@ -25,6 +29,7 @@ pk_ev_id_T pk_ev_register_ev(pk_ev_mgr_id_T evmgr, void *user_ev_data);
pk_ev_cb_id_T pk_ev_register_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb_fn *cb, void *user_cb_data);
void pk_ev_emit(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, void *user_emit_data);
+void pk_ev_unregister_ev(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid);
void pk_ev_unregister_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb_id_T cbid);
#endif /* PK_EV_H */
@@ -37,9 +42,7 @@ void pk_ev_unregister_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb_id_T cb
#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
@@ -79,7 +82,9 @@ struct pk_ev {
struct pk_ev_mgr {
struct pk_ev *ev;
- atomic_uint_fast64_t n_ev;
+ atomic_uint_fast64_t left_evs;
+ atomic_uint_fast64_t right_evs;
+ atomic_uint_fast64_t unused_evs;
// reserved length of `pk_ev`s on this struct
atomic_uint_fast64_t rn_ev;
// on any given `pk_ev`, the number of callbacks reserved
@@ -119,6 +124,8 @@ pk_ev_inner_calc_sz(uint64_t ev_count, uint64_t cb_count, size_t *sz_ev_list, si
// base sizes
size_t l_sz_ev_list = sizeof(struct pk_ev) * ev_count;
size_t l_sz_ev_cb_list = sizeof(struct pk_ev_cb) * cb_count;
+ l_sz_ev_list += ((size_t)64 - alignof(struct pk_ev)) % (size_t)64;
+ l_sz_ev_cb_list += ((size_t)64 - alignof(struct pk_ev_cb)) % (size_t)64;
if (sz_ev_list != nullptr) *sz_ev_list = l_sz_ev_list;
if (sz_ev_cb_list != nullptr) *sz_ev_cb_list = l_sz_ev_cb_list;
@@ -157,29 +164,43 @@ pk_ev_inner_ev_mgr_create(uint64_t ev_count, uint64_t cb_count)
assert(ev_count < 0x100);
assert(cb_count < 0x100);
uint64_t i;
+ char *ptr;
struct pk_ev *ev;
size_t sz_ev_list;
size_t sz_ev_cb_list;
- size_t sz = pk_ev_inner_calc_sz(ev_count, cb_count, &sz_ev_list, &sz_ev_cb_list);
size_t sz_offset;
+ size_t sz = pk_ev_inner_calc_sz(ev_count, cb_count, &sz_ev_list, &sz_ev_cb_list);
struct pk_ev_mgr *mgr = (struct pk_ev_mgr*)PK_EV_MEM_ALLOC(sz, alignof(struct pk_ev_mgr), pk_ev_mstr.bkt);
if (mgr == NULL) goto early_exit;
- mgr->ev = (struct pk_ev*)(((char *)mgr) + sizeof(struct pk_ev_mgr));
+ ptr = ((char *)mgr) + sizeof(struct pk_ev_mgr);
+ sz_offset = (size_t)ptr % alignof(struct pk_ev);
+ ptr += ((size_t)64 - sz_offset) % (size_t)64;
+ mgr->ev = (struct pk_ev*)ptr;
atomic_init(&mgr->rn_ev, ev_count);
atomic_init(&mgr->rn_cb, cb_count);
- atomic_init(&mgr->n_ev, 0);
+ atomic_init(&mgr->left_evs, 0);
+ atomic_init(&mgr->right_evs, 0);
+ atomic_init(&mgr->unused_evs, 0xFFFFFFFFFFFFFFFF);
+ // find mem-aligned beginning of cb array
+ ptr += sz_ev_list;
+ sz_offset = (size_t)ptr % alignof(struct pk_ev_cb);
+ ptr += ((size_t)64 - sz_offset) % (size_t)64;
for (i = 0; i < ev_count; ++i) {
ev = &mgr->ev[i];
atomic_init(&ev->left_ev_cbs, 0);
atomic_init(&ev->right_ev_cbs, 0);
- sz_offset = sizeof(struct pk_ev_mgr);
- sz_offset += sz_ev_list;
- sz_offset += sz_ev_cb_list * i;
- ev->ev_cbs = (struct pk_ev_cb*)(((char *)mgr) + sz_offset);
+ sz_offset = sz_ev_cb_list * i;
+ ev->ev_cbs = (struct pk_ev_cb*)(ptr + sz_offset);
}
+ /* debug
+ fprintf(stdout, "[%s] mgr: sz: %lu, ev_count: %lu, cb_count: %lu \n", __FILE__, sz, ev_count, cb_count);
+ fprintf(stdout, "\t%p - ptr\n", (void*)mgr);
+ fprintf(stdout, "\t%p - evs (+%lu)\n", (void*)mgr->ev, (char*)mgr->ev - (char*)mgr);
+ fprintf(stdout, "\t%p - cbs (+%lu)\n", (void*)mgr->ev[0].ev_cbs, (char*)mgr->ev[0].ev_cbs - (char*)mgr);
+ */
early_exit:
return mgr;
}
@@ -187,17 +208,23 @@ early_exit:
static void
pk_ev_inner_ev_mgr_clone(struct pk_ev_mgr *old, struct pk_ev_mgr *mgr)
{
- uint64_t i;
+ uint64_t i, ii;
+ uint64_t u, uu;
struct pk_ev *ev_old;
struct pk_ev *ev;
- atomic_store(&mgr->n_ev, atomic_load(&old->n_ev));
- size_t old_sz_ev_cb_list;
- for (i = 0; i < old->n_ev; ++i) {
+ ii = atomic_load(&old->right_evs);
+ atomic_store(&mgr->left_evs, atomic_load(&old->left_evs));
+ atomic_store(&mgr->right_evs, ii);
+ atomic_store(&mgr->unused_evs, atomic_load(&old->unused_evs));
+ for (i = 0; i < ii; ++i) {
ev_old = &old->ev[i];
ev = &mgr->ev[i];
- pk_ev_inner_calc_sz(0, atomic_load(&ev_old->right_ev_cbs), nullptr, &old_sz_ev_cb_list);
ev->user_ev_data = ev_old->user_ev_data;
- memcpy(ev->ev_cbs, ev_old->ev_cbs, old_sz_ev_cb_list);
+ uu = atomic_load(&ev_old->right_ev_cbs);
+ for (u = 0; u <= uu; ++u) {
+ ev->ev_cbs[u].cb = ev_old->ev_cbs[u].cb;
+ ev->ev_cbs[u].user_cb_data = ev_old->ev_cbs[u].user_cb_data;
+ }
atomic_store(&ev->left_ev_cbs, atomic_load(&ev_old->left_ev_cbs));
atomic_store(&ev->right_ev_cbs, atomic_load(&ev_old->right_ev_cbs));
}
@@ -264,12 +291,15 @@ pk_ev_register_ev(pk_ev_mgr_id_T evmgr, void *user_ev_data)
{
assert(evmgr < 64);
uint64_t new_size;
+ uint64_t i, ii, flg;
pk_ev_id_T id;
+ bool found = false;
struct pk_ev_mgr *mgr = nullptr;
mtx_lock(&pk_ev_mstr.mtxs[evmgr]);
- if (pk_ev_mstr.mgrs[evmgr]->n_ev == pk_ev_mstr.mgrs[evmgr]->rn_ev) {
- new_size = PK_MAX(2, PK_MIN(255, pk_ev_mstr.mgrs[evmgr]->rn_ev * PK_EV_GROW_RATIO));
- if (new_size == pk_ev_mstr.mgrs[evmgr]->rn_ev) {
+ mgr = pk_ev_mstr.mgrs[evmgr];
+ if (mgr->left_evs == mgr->right_evs && mgr->right_evs == mgr->rn_ev) {
+ new_size = PK_MAX(2, PK_MIN(255, mgr->rn_ev * PK_EV_GROW_RATIO));
+ if (new_size == mgr->rn_ev) {
PK_LOG_ERR("[pkev.h] need more room, but failed to grow ev count.\n");
mtx_unlock(&pk_ev_mstr.mtxs[evmgr]);
exit(1);
@@ -280,9 +310,29 @@ pk_ev_register_ev(pk_ev_mgr_id_T evmgr, void *user_ev_data)
PK_EV_MEM_FREE(pk_ev_mstr.mgrs[evmgr], old_sz, pk_ev_mstr.bkt);
pk_ev_mstr.mgrs[evmgr] = mgr;
}
- id = pk_ev_mstr.mgrs[evmgr]->n_ev++;
+ id = atomic_load(&mgr->left_evs);
+ if (mgr->left_evs != mgr->right_evs) {
+ i = atomic_load(&mgr->left_evs);
+ ii = atomic_load(&mgr->rn_ev);
+ flg = atomic_load(&mgr->unused_evs);
+ for (; i < ii; ++i) {
+ if (flg & (1lu << i)) {
+ if (!found) {
+ found = true;
+ flg &= ~(1lu << i);
+ continue;
+ }
+ break;
+ }
+ }
+ atomic_store(&mgr->left_evs, i);
+ atomic_store(&mgr->unused_evs, flg);
+ } else {
+ atomic_store(&mgr->left_evs, atomic_load(&mgr->left_evs) + 1);
+ atomic_store(&mgr->right_evs, atomic_load(&mgr->right_evs) + 1);
+ }
mtx_unlock(&pk_ev_mstr.mtxs[evmgr]);
- pk_ev_mstr.mgrs[evmgr]->ev[id].user_ev_data = user_ev_data;
+ mgr->ev[id].user_ev_data = user_ev_data;
return id;
}
@@ -353,6 +403,26 @@ pk_ev_emit(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, void *user_emit_data)
}
void
+pk_ev_unregister_ev(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid)
+{
+ assert(evmgr <= pk_ev_mstr.rn_mgrs);
+ struct pk_ev_mgr *mgr = pk_ev_mstr.mgrs[evmgr];
+ assert(evid <= mgr->right_evs);
+ if (mgr == nullptr) return;
+ mgr->ev[evid].user_ev_data = NULL;
+ atomic_store(&mgr->ev[evid].left_ev_cbs, 0);
+ atomic_store(&mgr->ev[evid].right_ev_cbs, 0);
+ for (uint64_t u = 0; u < mgr->rn_cb; ++u) {
+ mgr->ev[evid].ev_cbs[u].cb = NULL;
+ mgr->ev[evid].ev_cbs[u].user_cb_data = NULL;
+ }
+ atomic_store(&mgr->unused_evs, atomic_load(&mgr->unused_evs) | (1lu << evid));
+ if (evid < atomic_load(&mgr->left_evs)) {
+ atomic_store(&mgr->left_evs, evid);
+ }
+}
+
+void
pk_ev_unregister_cb(pk_ev_mgr_id_T evmgr, pk_ev_id_T evid, pk_ev_cb_id_T cbid)
{
struct pk_ev_mgr *mgr = pk_ev_mstr.mgrs[evmgr];
diff --git a/test/pkev.cpp b/test/pkev.cpp
index 0d39336..61835df 100644
--- a/test/pkev.cpp
+++ b/test/pkev.cpp
@@ -90,9 +90,30 @@ int main(int argc, char *argv[])
(void)stdout;
size_t i, ii;
+ // register, emit
+ {
+ std::packaged_task<void()> handle_ev_one([](){ ev_one.handled = true; });
+ std::packaged_task<void()> handle_ev_two([](){ ev_two.handled = true; });
+ pk_ev_mgr_id_T evmgr = test_setup();
+ ev_one.evid = pk_ev_register_ev(evmgr, NULL);
+ ev_two.evid = pk_ev_register_ev(evmgr, NULL);
+ pk_ev_register_cb(evmgr, ev_one.evid, &invoke_packged_task, NULL);
+ pk_ev_register_cb(evmgr, ev_two.evid, &invoke_packged_task, NULL);
+ pk_ev_emit(evmgr, ev_one.evid, &handle_ev_one);
+ pk_ev_emit(evmgr, ev_two.evid, &handle_ev_two);
+ PK_LOGV_INF("%s: ev_one: %lu, ev_two: %lu\n", __FILE__, ev_one.evid, ev_two.evid);
+ PK_LOGV_INF("%s: ev_one: %s, ev_two: %s\n", __FILE__, ev_one.handled ? "true" : "false", ev_two.handled ? "true" : "false");
+ pk_ev_teardown();
+ fflush(stdout);
+ fflush(stderr);
+ if (ev_one.evid != 0 || ev_two.evid != 1) exit(1);
+ if (ev_one.handled == false || ev_two.handled == false) exit(1);
+ }
- // register, emit, catch
+ // register, emit, clear
{
+ ev_one.handled = false;
+ ev_two.handled = false;
std::packaged_task<void()> handle_ev_one([](){ ev_one.handled = true; });
std::packaged_task<void()> handle_ev_two([](){ ev_two.handled = true; });
pk_ev_mgr_id_T evmgr = test_setup();
@@ -100,16 +121,65 @@ int main(int argc, char *argv[])
ev_two.evid = pk_ev_register_ev(evmgr, NULL);
pk_ev_register_cb(evmgr, ev_one.evid, &invoke_packged_task, NULL);
pk_ev_register_cb(evmgr, ev_two.evid, &invoke_packged_task, NULL);
+ pk_ev_unregister_ev(ev_one.evmgr, ev_one.evid);
pk_ev_emit(evmgr, ev_one.evid, &handle_ev_one);
pk_ev_emit(evmgr, ev_two.evid, &handle_ev_two);
PK_LOGV_INF("%s: ev_one: %s, ev_two: %s\n", __FILE__, ev_one.handled ? "true" : "false", ev_two.handled ? "true" : "false");
pk_ev_teardown();
fflush(stdout);
fflush(stderr);
+ if (ev_one.handled == true || ev_two.handled == false) exit(1);
+ }
+
+ // register, emit, clear, register
+ {
+ ev_one.handled = false;
+ ev_two.handled = false;
+ std::packaged_task<void()> handle_ev_one([](){ ev_one.handled = true; });
+ std::packaged_task<void()> handle_ev_two([](){ ev_two.handled = true; });
+ pk_ev_mgr_id_T evmgr = test_setup();
+ ev_one.evid = pk_ev_register_ev(evmgr, NULL);
+ ev_two.evid = pk_ev_register_ev(evmgr, NULL);
+ pk_ev_register_cb(evmgr, ev_one.evid, &invoke_packged_task, NULL);
+ pk_ev_register_cb(evmgr, ev_two.evid, &invoke_packged_task, NULL);
+ PK_LOGV_INF("%s: ev_one: %lu, ev_two: %lu\n", __FILE__, ev_one.evid, ev_two.evid);
+ fflush(stdout);
+ fflush(stderr);
+ if (ev_one.evid != 0 || ev_two.evid != 1) exit(1);
+ pk_ev_unregister_ev(ev_one.evmgr, ev_one.evid);
+
+ pk_ev_emit(evmgr, ev_one.evid, &handle_ev_one);
+ pk_ev_emit(evmgr, ev_two.evid, &handle_ev_two);
+ PK_LOGV_INF("%s: ev_one: %s, ev_two: %s\n", __FILE__, ev_one.handled ? "true" : "false", ev_two.handled ? "true" : "false");
+ fflush(stdout);
+ fflush(stderr);
+ if (ev_one.handled == true || ev_two.handled == false) exit(1);
+ pk_ev_unregister_ev(ev_two.evmgr, ev_two.evid);
+
+ std::packaged_task<void()> handle_ev_thr([](){ ev_one.handled = true; });
+ std::packaged_task<void()> handle_ev_for([](){ ev_two.handled = true; });
+ ev_one.handled = false;
+ ev_two.handled = false;
+ ev_one.evid = pk_ev_register_ev(evmgr, NULL);
+ ev_two.evid = pk_ev_register_ev(evmgr, NULL);
+ pk_ev_register_cb(evmgr, ev_one.evid, &invoke_packged_task, NULL);
+ pk_ev_register_cb(evmgr, ev_two.evid, &invoke_packged_task, NULL);
+ PK_LOGV_INF("%s: ev_one: %lu, ev_two: %lu\n", __FILE__, ev_one.evid, ev_two.evid);
+ fflush(stdout);
+ fflush(stderr);
+ if (ev_one.evid != 0 || ev_two.evid != 1) exit(1);
+
+ pk_ev_emit(evmgr, ev_one.evid, &handle_ev_thr);
+ pk_ev_emit(evmgr, ev_two.evid, &handle_ev_for);
+ PK_LOGV_INF("%s: ev_one: %s, ev_two: %s\n", __FILE__, ev_one.handled ? "true" : "false", ev_two.handled ? "true" : "false");
+ fflush(stdout);
+ fflush(stderr);
if (ev_one.handled == false || ev_two.handled == false) exit(1);
+
+ pk_ev_teardown();
}
- // threaded register, emit, catch
+ // threaded register, emit
{
std::packaged_task<void()> handle_ev_one([](){ ev_one.handled = true; });
std::packaged_task<void()> handle_ev_two([](){ ev_two.handled = true; });
@@ -126,10 +196,12 @@ int main(int argc, char *argv[])
});
t1.join();
t2.join();
+ PK_LOGV_INF("%s: ev_one: %lu, ev_two: %lu\n", __FILE__, ev_one.evid, ev_two.evid);
PK_LOGV_INF("%s: ev_one: %s, ev_two: %s\n", __FILE__, ev_one.handled ? "true" : "false", ev_two.handled ? "true" : "false");
pk_ev_teardown();
fflush(stdout);
fflush(stderr);
+ if (ev_one.evid != 0 || ev_two.evid != 1) exit(1);
if (ev_one.handled == false || ev_two.handled == false) exit(1);
}