// // Copyright 2020 Staysail Systems, Inc. // Copyright 2017 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // #include "core/nng_impl.h" #include "reap.h" #include // New stuff. static nni_reap_list *reap_list = NULL; static nni_thr reap_thr; static bool reap_exit; static nni_mtx reap_mtx; static bool reap_empty; static nni_cv reap_work_cv; static nni_cv reap_empty_cv; static void reap_worker(void *unused) { NNI_ARG_UNUSED(unused); nni_thr_set_name(NULL, "nng:reap2"); nni_mtx_lock(&reap_mtx); for (;;) { nni_reap_list *list; bool reaped = false; for (list = reap_list; list != NULL; list = list->rl_next) { nni_reap_node *node; size_t offset; nni_cb func; if ((node = list->rl_nodes) == NULL) { continue; } reaped = true; offset = list->rl_offset; func = list->rl_func; list->rl_nodes = NULL; // We process our list of nodes while not holding // the lock. nni_mtx_unlock(&reap_mtx); while (node != NULL) { void *ptr; ptr = ((char *) node) - offset; node = node->rn_next; func(ptr); } nni_mtx_lock(&reap_mtx); } if (!reaped) { reap_empty = true; nni_cv_wake(&reap_empty_cv); if (reap_exit) { nni_mtx_unlock(&reap_mtx); return; } nni_cv_wait(&reap_work_cv); } } } void nni_reap(nni_reap_list *rl, void *item) { nni_reap_node *node; nni_mtx_lock(&reap_mtx); if (!rl->rl_inited) { rl->rl_inited = true; rl->rl_next = reap_list; reap_list = rl; } reap_empty = false; node = (void *) ((char *) item + rl->rl_offset); node->rn_next = rl->rl_nodes; rl->rl_nodes = node; nni_cv_wake1(&reap_work_cv); nni_mtx_unlock(&reap_mtx); } void nni_reap_drain(void) { nni_mtx_lock(&reap_mtx); while (!reap_empty) { nni_cv_wait(&reap_empty_cv); } nni_mtx_unlock(&reap_mtx); } int nni_reap_sys_init(void) { int rv; reap_exit = false; nni_mtx_init(&reap_mtx); nni_cv_init(&reap_work_cv, &reap_mtx); nni_cv_init(&reap_empty_cv, &reap_mtx); // If this fails, we don't fail init, instead we will try to // start up at reap time. if ((rv = nni_thr_init(&reap_thr, reap_worker, NULL)) != 0) { nni_cv_fini(&reap_work_cv); nni_cv_fini(&reap_empty_cv); nni_mtx_fini(&reap_mtx); return (rv); } nni_thr_run(&reap_thr); return (0); } void nni_reap_sys_fini(void) { nni_mtx_lock(&reap_mtx); reap_exit = true; nni_cv_wake1(&reap_work_cv); nni_mtx_unlock(&reap_mtx); nni_thr_fini(&reap_thr); // NB: The subsystem linkages remain in place. We don't need // to reinitialize them across future initializations. }