in src/router_core/router_core.c [135:338]
void qdr_core_free(qdr_core_t *core)
{
//
// Stop and join the thread
//
core->running = false;
sys_cond_signal(core->action_cond);
sys_thread_join(core->thread);
// have adaptors clean up all core resources
qdr_adaptors_finalize(core);
//
// The char* core->router_id and core->router_area are owned by qd->router_id and qd->router_area respectively
// We will set them to zero here just in case anybody tries to use these fields.
//
core->router_id = 0;
core->router_area = 0;
//
// Free the core resources
//
for (int i = 0; i <= QD_TREATMENT_LINK_BALANCED; ++i) {
if (core->forwarders[i]) {
free(core->forwarders[i]);
}
}
qdr_link_route_t *link_route = 0;
while ( (link_route = DEQ_HEAD(core->link_routes))) {
DEQ_REMOVE_HEAD(core->link_routes);
qdr_core_delete_link_route(core, link_route);
}
//
// The connection based link routes need to be removed before we call
// qdr_core_remove_address(addr) on all core->addrs
//
qdr_connection_t *conn = DEQ_HEAD(core->open_connections);
while (conn) {
while ((link_route = DEQ_HEAD(conn->conn_link_routes))) {
DEQ_REMOVE_HEAD(conn->conn_link_routes);
qdr_core_delete_link_route(core, link_route);
}
conn = DEQ_NEXT(conn);
}
qdr_auto_link_t *auto_link = 0;
while ( (auto_link = DEQ_HEAD(core->auto_links))) {
DEQ_REMOVE_HEAD(core->auto_links);
qdr_core_delete_auto_link(core, auto_link);
}
qdr_exchange_free_all(core);
qdr_address_t *addr = 0;
while ( (addr = DEQ_HEAD(core->addrs)) ) {
qdr_core_remove_address(core, addr);
}
qdr_address_config_t *addr_config = 0;
while ( (addr_config = DEQ_HEAD(core->addr_config))) {
qdr_core_remove_address_config(core, addr_config);
}
qd_hash_free(core->addr_hash);
qd_hash_free(core->addr_lr_al_hash);
qd_parse_tree_free(core->addr_parse_tree);
qd_parse_tree_free(core->link_route_tree[QD_INCOMING]);
qd_parse_tree_free(core->link_route_tree[QD_OUTGOING]);
qdr_node_t *rnode = 0;
while ( (rnode = DEQ_HEAD(core->routers)) ) {
qdr_router_node_free(core, rnode);
}
qdr_link_t *link = DEQ_HEAD(core->open_links);
while (link) {
DEQ_REMOVE_HEAD(core->open_links);
if (link->in_streaming_pool) {
DEQ_REMOVE_N(STREAMING_POOL, link->conn->streaming_link_pool, link);
link->in_streaming_pool = false;
}
qdr_link_cleanup_deliveries_CT(core, link->conn, link, true);
if (link->core_endpoint)
qdrc_endpoint_do_cleanup_CT(core, link->core_endpoint);
qdr_del_link_ref(&link->conn->links, link, QDR_LINK_LIST_CLASS_CONNECTION);
qdr_del_link_ref(&link->conn->links_with_work[link->priority], link, QDR_LINK_LIST_CLASS_WORK);
free(link->name);
free(link->disambiguated_name);
free(link->terminus_addr);
free(link->ingress_histogram);
free(link->insert_prefix);
free(link->strip_prefix);
link->name = 0;
//
// If there are still any work items remaining in the link->work_list
// remove them and free the associated link_work->error
//
sys_mutex_lock(link->conn->work_lock);
qdr_link_work_t *link_work = DEQ_HEAD(link->work_list);
while (link_work) {
DEQ_REMOVE_HEAD(link->work_list);
qdr_link_work_release(link_work);
link_work = DEQ_HEAD(link->work_list);
}
sys_mutex_unlock(link->conn->work_lock);
if (link->user_context) {
qdr_link_set_context(link, 0);
}
free_qdr_link_t(link);
link = DEQ_HEAD(core->open_links);
}
// finalize modules while we can still submit new actions
// this must happen after qdrc_endpoint_do_cleanup_CT calls
qdr_modules_finalize(core);
// discard any left over actions
qdr_action_list_t action_list;
DEQ_MOVE(core->action_list, action_list);
DEQ_APPEND(action_list, core->action_list_background);
qdr_action_t *action = DEQ_HEAD(action_list);
while (action) {
DEQ_REMOVE_HEAD(action_list);
action->action_handler(core, action, true);
free_qdr_action_t(action);
action = DEQ_HEAD(action_list);
}
// Drain the general work lists
qdr_general_handler(core);
sys_thread_free(core->thread);
sys_cond_free(core->action_cond);
sys_mutex_free(core->action_lock);
sys_mutex_free(core->work_lock);
sys_mutex_free(core->id_lock);
qd_timer_free(core->work_timer);
//
// Clean up any qdr_delivery_cleanup_t's that are still left in the core->delivery_cleanup_list
//
qdr_delivery_cleanup_t *cleanup = DEQ_HEAD(core->delivery_cleanup_list);
while (cleanup) {
DEQ_REMOVE_HEAD(core->delivery_cleanup_list);
if (cleanup->msg)
qd_message_free(cleanup->msg);
if (cleanup->iter)
qd_iterator_free(cleanup->iter);
free_qdr_delivery_cleanup_t(cleanup);
cleanup = DEQ_HEAD(core->delivery_cleanup_list);
}
conn = DEQ_HEAD(core->open_connections);
while (conn) {
DEQ_REMOVE_HEAD(core->open_connections);
if (conn->conn_id) {
qdr_del_connection_ref(&conn->conn_id->connection_refs, conn);
qdr_route_check_id_for_deletion_CT(core, conn->conn_id);
}
if (conn->alt_conn_id) {
qdr_del_connection_ref(&conn->alt_conn_id->connection_refs, conn);
qdr_route_check_id_for_deletion_CT(core, conn->alt_conn_id);
}
qdr_connection_work_t *work = DEQ_HEAD(conn->work_list);
while (work) {
DEQ_REMOVE_HEAD(conn->work_list);
qdr_connection_work_free_CT(work);
work = DEQ_HEAD(conn->work_list);
}
if (conn->has_streaming_links) {
assert(DEQ_IS_EMPTY(conn->streaming_link_pool)); // all links have been released
qdr_del_connection_ref(&core->streaming_connections, conn);
}
qdr_connection_free(conn);
conn = DEQ_HEAD(core->open_connections);
}
assert(DEQ_SIZE(core->streaming_connections) == 0);
// at this point all the conn identifiers have been freed
qd_hash_free(core->conn_id_hash);
qdr_agent_free(core->mgmt_agent);
if (core->routers_by_mask_bit) free(core->routers_by_mask_bit);
if (core->control_links_by_mask_bit) free(core->control_links_by_mask_bit);
if (core->data_links_by_mask_bit) free(core->data_links_by_mask_bit);
if (core->neighbor_free_mask) qd_bitmask_free(core->neighbor_free_mask);
if (core->rnode_conns_by_mask_bit) free(core->rnode_conns_by_mask_bit);
free(core);
}