diff --git a/CHANGES b/CHANGES index fee79f4487..962de85927 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ +5638. [bug] Improvements related to network manager/task manager + integration: + - added isc_managers_create() and _destroy() functions + to handle setup and teardown of netmgr, taskmgr, + timermgr and socketmgr since these require a + precise order of operations now. + - event queue processing is now quantized to prevent + infinite looping. + - the netmgr can now be paused from within a netmgr + thread. + - fixed deadlocks due to conflict between netmgr + pause/resume and listen/stoplistening operations. + [GL #2654] + 5637. [placeholder] 5636. [bug] Check that zone files for 'dnssec-policy' zones are diff --git a/bin/delv/delv.c b/bin/delv/delv.c index fc974853c4..c7eb8d6839 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -1761,10 +1762,8 @@ main(int argc, char *argv[]) { isc_mem_create(&mctx); CHECK(isc_appctx_create(mctx, &actx)); - netmgr = isc_nm_start(mctx, 1); - CHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - CHECK(isc_socketmgr_create(mctx, &socketmgr)); - CHECK(isc_timermgr_create(mctx, &timermgr)); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); parse_args(argc, argv); @@ -1867,18 +1866,7 @@ cleanup: if (client != NULL) { dns_client_destroy(&client); } - if (taskmgr != NULL) { - isc_taskmgr_destroy(&taskmgr); - } - if (netmgr != NULL) { - isc_nm_destroy(&netmgr); - } - if (timermgr != NULL) { - isc_timermgr_destroy(&timermgr); - } - if (socketmgr != NULL) { - isc_socketmgr_destroy(&socketmgr); - } + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); if (actx != NULL) { isc_appctx_destroy(&actx); } diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index a4a2ebdaf1..7ae651e517 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -106,9 +107,9 @@ unsigned int timeout = 0; unsigned int extrabytes; isc_mem_t *mctx = NULL; isc_log_t *lctx = NULL; +isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *global_task = NULL; -isc_nm_t *netmgr = NULL; isc_sockaddr_t localaddr; isc_refcount_t sendcount = ATOMIC_VAR_INIT(0); isc_refcount_t recvcount = ATOMIC_VAR_INIT(0); @@ -226,8 +227,9 @@ void (*dighost_shutdown)(void); /* forward declarations */ +#define cancel_lookup(l) _cancel_lookup(l, __FILE__, __LINE__) static void -cancel_lookup(dig_lookup_t *lookup); +_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line); static void recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, @@ -1360,10 +1362,7 @@ setup_libs(void) { isc_log_setdebuglevel(lctx, 0); - netmgr = isc_nm_start(mctx, 1); - - result = isc_taskmgr_create(mctx, 0, netmgr, &taskmgr); - check_result(result, "isc_taskmgr_create"); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); result = isc_task_create(taskmgr, 0, &global_task); check_result(result, "isc_task_create"); @@ -1696,6 +1695,9 @@ _query_detach(dig_query_t **queryp, const char *file, unsigned int line) { isc_refcount_current(&query->references) - 1); if (isc_refcount_decrement(&query->references) == 1) { + INSIST(query->readhandle == NULL); + INSIST(query->sendhandle == NULL); + if (ISC_LINK_LINKED(query, link)) { ISC_LIST_UNLINK(lookup->q, query, link); } @@ -1752,13 +1754,18 @@ start_lookup(void) { * decremented, current_lookup will not be set to NULL.) */ static void -clear_current_lookup() { +clear_current_lookup(void) { dig_lookup_t *lookup = current_lookup; INSIST(!free_now); debug("clear_current_lookup()"); + if (lookup == NULL) { + debug("current_lookup is already detached"); + return; + } + if (ISC_LIST_HEAD(lookup->q) != NULL) { debug("still have a worker"); return; @@ -2671,11 +2678,12 @@ send_done(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { /*% * Cancel a lookup, sending canceling reads on all existing sockets. */ + static void -cancel_lookup(dig_lookup_t *lookup) { +_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line) { dig_query_t *query, *next; - debug("cancel_lookup()"); + debug("%s:%u:%s()", file, line, __func__); query = ISC_LIST_HEAD(lookup->q); while (query != NULL) { REQUIRE(DIG_VALID_QUERY(query)); @@ -2904,6 +2912,7 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { isc_result_totext(eresult)); } + cancel_lookup(l); lookup_detach(&l); query_detach(&query); return; @@ -2941,6 +2950,7 @@ static void start_udp(dig_query_t *query) { isc_result_t result; dig_query_t *next = NULL; + dig_query_t *connectquery = NULL; REQUIRE(DIG_VALID_QUERY(query)); @@ -2992,8 +3002,10 @@ start_udp(dig_query_t *query) { } } + query_attach(query, &connectquery); isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr, - (isc_nmiface_t *)&query->sockaddr, udp_ready, query, + (isc_nmiface_t *)&query->sockaddr, udp_ready, + connectquery, (timeout ? timeout : UDP_TIMEOUT) * 1000, 0); } @@ -3568,16 +3580,19 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, region, arg); LOCK_LOOKUP; - lookup_attach(query->lookup, &l); isc_refcount_decrement0(&recvcount); debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount)); if (eresult == ISC_R_CANCELED) { debug("recv_done: cancel"); - goto detach_query; + isc_nmhandle_detach(&query->readhandle); + query_detach(&query); + return; } + lookup_attach(query->lookup, &l); + if (query->lookup->use_usec) { TIME_NOW_HIRES(&query->time_recv); } else { @@ -4188,19 +4203,23 @@ cancel_all(void) { return; } atomic_store(&cancel_now, true); - if (current_lookup != NULL) { + while (current_lookup != NULL) { for (q = ISC_LIST_HEAD(current_lookup->q); q != NULL; q = nq) { nq = ISC_LIST_NEXT(q, link); debug("canceling pending query %p, belonging to %p", q, current_lookup); if (q->readhandle != NULL) { - isc_refcount_decrement0(&recvcount); - debug("recvcount=%" PRIuFAST32, - isc_refcount_current(&recvcount)); + isc_nm_cancelread(q->readhandle); } query_detach(&q); } - lookup_detach(¤t_lookup); + + /* + * current_lookup could have been detached via query_detach(). + */ + if (current_lookup != NULL) { + lookup_detach(¤t_lookup); + } } l = ISC_LIST_HEAD(lookup_list); while (l != NULL) { @@ -4226,20 +4245,8 @@ destroy_libs(void) { debug("freeing task"); isc_task_detach(&global_task); } - /* - * The taskmgr_destroy() and isc_nm_destroy() calls block until - * all events are cleared. - */ - if (taskmgr != NULL) { - debug("freeing taskmgr"); - isc_taskmgr_destroy(&taskmgr); - } - debug("closing down netmgr"); - isc_nm_closedown(netmgr); - - debug("destroy netmgr"); - isc_nm_destroy(&netmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); LOCK_LOOKUP; isc_refcount_destroy(&recvcount); diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index 902dfce8b4..f19b692612 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -3963,13 +3964,7 @@ main(int argc, char *argv[]) { print_time(outfp); print_version(outfp); - netmgr = isc_nm_start(mctx, ntasks); - - result = isc_taskmgr_create(mctx, 0, netmgr, &taskmgr); - if (result != ISC_R_SUCCESS) { - fatal("failed to create task manager: %s", - isc_result_totext(result)); - } + isc_managers_create(mctx, ntasks, 0, 0, &netmgr, &taskmgr, NULL, NULL); master = NULL; result = isc_task_create(taskmgr, 0, &master); @@ -4020,8 +4015,7 @@ main(int argc, char *argv[]) { for (i = 0; i < (int)ntasks; i++) { isc_task_detach(&tasks[i]); } - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *)); postsign(); TIME_NOW(&sign_finish); diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c index 01918009a3..d3084b3ea1 100644 --- a/bin/named/controlconf.c +++ b/bin/named/controlconf.c @@ -1164,10 +1164,10 @@ add_listener(named_controls_t *cp, controllistener_t **listenerp, } #endif - CHECK(isc_nm_listentcp(named_g_nm, (isc_nmiface_t *)&listener->address, - control_newconn, listener, - sizeof(controlconnection_t), 5, NULL, - &listener->sock)); + CHECK(isc_nm_listentcp( + named_g_netmgr, (isc_nmiface_t *)&listener->address, + control_newconn, listener, sizeof(controlconnection_t), 5, NULL, + &listener->sock)); #if 0 /* XXX: no unix socket support yet */ if (type == isc_socktype_unix) { diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index b8ea5946a4..8663eaf012 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -62,7 +62,7 @@ EXTERN bool named_g_run_done INIT(false); */ EXTERN isc_timermgr_t *named_g_timermgr INIT(NULL); EXTERN isc_socketmgr_t *named_g_socketmgr INIT(NULL); -EXTERN isc_nm_t *named_g_nm INIT(NULL); +EXTERN isc_nm_t *named_g_netmgr INIT(NULL); EXTERN cfg_parser_t *named_g_parser INIT(NULL); EXTERN cfg_parser_t *named_g_addparser INIT(NULL); EXTERN const char *named_g_version INIT(PACKAGE_VERSION); diff --git a/bin/named/main.c b/bin/named/main.c index f033607609..28bfdd57f6 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -937,45 +938,17 @@ create_managers(void) { "using %u UDP listener%s per interface", named_g_udpdisp, named_g_udpdisp == 1 ? "" : "s"); - /* - * We have ncpus network threads, ncpus worker threads, ncpus - * old network threads - make it 4x just to be safe. The memory - * impact is negligible. - */ - isc_hp_init(4 * named_g_cpus); - named_g_nm = isc_nm_start(named_g_mctx, named_g_cpus); - if (named_g_nm == NULL) { - UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_nm_start() failed"); - return (ISC_R_UNEXPECTED); + result = isc_managers_create(named_g_mctx, named_g_cpus, + 0 /* quantum */, maxsocks, &named_g_netmgr, + &named_g_taskmgr, &named_g_timermgr, + &named_g_socketmgr); + if (result != ISC_R_SUCCESS) { + return (result); } - result = isc_taskmgr_create(named_g_mctx, 0, named_g_nm, - &named_g_taskmgr); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_taskmgr_create() failed: %s", - isc_result_totext(result)); - return (ISC_R_UNEXPECTED); - } - - result = isc_timermgr_create(named_g_mctx, &named_g_timermgr); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_timermgr_create() failed: %s", - isc_result_totext(result)); - return (ISC_R_UNEXPECTED); - } - - result = isc_socketmgr_create2(named_g_mctx, &named_g_socketmgr, - maxsocks, named_g_cpus); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_socketmgr_create() failed: %s", - isc_result_totext(result)); - return (ISC_R_UNEXPECTED); - } isc_socketmgr_maxudp(named_g_socketmgr, maxudp); - isc_nm_maxudp(named_g_nm, maxudp); + isc_nm_maxudp(named_g_netmgr, maxudp); + result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &socks); if (result == ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, @@ -988,21 +961,8 @@ create_managers(void) { static void destroy_managers(void) { - /* - * isc_nm_closedown() closes all active connections, freeing - * attached clients and other resources and preventing new - * connections from being established, but it not does not - * stop all processing or destroy the netmgr yet. - */ - isc_nm_closedown(named_g_nm); - - /* - * isc_taskmgr_destroy() will block until all tasks have exited. - */ - isc_taskmgr_destroy(&named_g_taskmgr); - isc_nm_destroy(&named_g_nm); - isc_timermgr_destroy(&named_g_timermgr); - isc_socketmgr_destroy(&named_g_socketmgr); + isc_managers_destroy(&named_g_netmgr, &named_g_taskmgr, + &named_g_timermgr, &named_g_socketmgr); } static void diff --git a/bin/named/server.c b/bin/named/server.c index e306fd63b5..d411647c44 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -8840,7 +8840,8 @@ load_configuration(const char *filename, named_server_t *server, advertised = MAX_ADVERTISED_TIMEOUT; } - isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, advertised); + isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive, + advertised); /* * Configure sets of UDP query source ports. @@ -9844,6 +9845,12 @@ view_loaded(void *arg) { "all zones loaded"); } + /* + * Clear taskmgr privileged mode now that zones are loaded. + */ + isc_taskmgr_setmode(dns_zonemgr_gettaskmgr(server->zonemgr), + isc_taskmgrmode_normal); + CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr), "forcing zone maintenance"); @@ -9866,7 +9873,7 @@ view_loaded(void *arg) { } static isc_result_t -load_zones(named_server_t *server, bool reconfig) { +load_zones(named_server_t *server, bool init, bool reconfig) { isc_result_t result; dns_view_t *view; ns_zoneload_t *zl; @@ -9923,6 +9930,19 @@ cleanup: isc_mem_put(server->mctx, zl, sizeof(*zl)); } + /* + * If we're setting up the server for the first time, + * set the task manager into privileged mode; this ensures + * that no other tasks will begin to run until after + * zone loading is complete. + * + * We do *not* want to do this in the case of reload or + * reconfig, as loading a large zone could cause the server + * to be inactive for too long a time. + */ + isc_taskmgr_setmode(named_g_taskmgr, init ? isc_taskmgrmode_privileged + : isc_taskmgrmode_normal); + isc_task_endexclusive(server->task); return (result); } @@ -9950,7 +9970,7 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(ns_interfacemgr_create( named_g_mctx, server->sctx, named_g_taskmgr, - named_g_timermgr, named_g_socketmgr, named_g_nm, + named_g_timermgr, named_g_socketmgr, named_g_netmgr, named_g_dispatchmgr, server->task, named_g_udpdisp, geoip, named_g_cpus, &server->interfacemgr), "creating interface manager"); @@ -9988,7 +10008,7 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(load_configuration(named_g_conffile, server, true), "loading configuration"); - CHECKFATAL(load_zones(server, false), "loading zones"); + CHECKFATAL(load_zones(server, true, false), "loading zones"); #ifdef ENABLE_AFL named_g_run_done = true; #endif /* ifdef ENABLE_AFL */ @@ -10181,7 +10201,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) { * startup and shutdown of the server, as well as all exclusive * tasks. */ - CHECKFATAL(isc_task_create(named_g_taskmgr, 0, &server->task), + CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0), "creating server task"); isc_task_setname(server->task, "server", server); isc_taskmgr_setexcltask(named_g_taskmgr, server->task); @@ -10220,7 +10240,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) { CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr, named_g_timermgr, named_g_socketmgr, - named_g_nm, &server->zonemgr), + named_g_netmgr, &server->zonemgr), "dns_zonemgr_create"); CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_" "setsize"); @@ -10260,7 +10280,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) { isc_sockstatscounter_max), "isc_stats_create"); isc_socketmgr_setstats(named_g_socketmgr, server->sockstats); - isc_nm_setstats(named_g_nm, server->sockstats); + isc_nm_setstats(named_g_netmgr, server->sockstats); CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats, dns_zonestatscounter_max), @@ -10501,7 +10521,7 @@ reload(named_server_t *server) { CHECK(loadconfig(server)); - result = load_zones(server, false); + result = load_zones(server, false, false); if (result == ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, @@ -10870,7 +10890,7 @@ named_server_reconfigcommand(named_server_t *server) { CHECK(loadconfig(server)); - result = load_zones(server, true); + result = load_zones(server, false, true); if (result == ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, @@ -16342,7 +16362,7 @@ named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) { return (ISC_R_UNEXPECTEDEND); } - isc_nm_gettimeouts(named_g_nm, &initial, &idle, &keepalive, + isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive, &advertised); /* Look for optional arguments. */ @@ -16396,7 +16416,7 @@ named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) { result = isc_task_beginexclusive(named_g_server->task); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, + isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive, advertised); isc_task_endexclusive(named_g_server->task); diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index d2cfc12bf5..7e1e982646 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -3612,7 +3612,7 @@ add_listener(named_server_t *server, named_statschannel_t **listenerp, CHECK(ISC_R_FAMILYNOSUPPORT); } - CHECK(isc_httpdmgr_create(named_g_nm, server->mctx, addr, client_ok, + CHECK(isc_httpdmgr_create(named_g_netmgr, server->mctx, addr, client_ok, destroy_listener, listener, &listener->httpdmgr)); diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 4965a274f5..b5ab597899 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -923,16 +924,8 @@ setup_system(void) { result = dns_dispatchmgr_create(gmctx, &dispatchmgr); check_result(result, "dns_dispatchmgr_create"); - result = isc_socketmgr_create(gmctx, &socketmgr); - check_result(result, "dns_socketmgr_create"); - - result = isc_timermgr_create(gmctx, &timermgr); - check_result(result, "dns_timermgr_create"); - - netmgr = isc_nm_start(gmctx, 1); - - result = isc_taskmgr_create(gmctx, 0, netmgr, &taskmgr); - check_result(result, "isc_taskmgr_create"); + isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); result = isc_task_create(taskmgr, 0, &global_task); check_result(result, "isc_task_create"); @@ -3325,21 +3318,12 @@ cleanup(void) { dst_key_free(&sig0key); } - ddebug("Shutting down task manager"); - isc_taskmgr_destroy(&taskmgr); - - ddebug("Shutting down network manager"); - isc_nm_destroy(&netmgr); + ddebug("Shutting down managers"); + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); ddebug("Destroying event"); isc_event_free(&global_event); - ddebug("Shutting down socket manager"); - isc_socketmgr_destroy(&socketmgr); - - ddebug("Shutting down timer manager"); - isc_timermgr_destroy(&timermgr); - #ifdef HAVE_GSSAPI /* * Cleanup GSSAPI resources after taskmgr has been destroyed. diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c index 624910a02d..fe30895f99 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ const char *progname = NULL; bool verbose; +static isc_nm_t *netmgr = NULL; static isc_taskmgr_t *taskmgr = NULL; static isc_task_t *rndc_task = NULL; @@ -72,7 +74,6 @@ static bool local4set = false, local6set = false; static int nserveraddrs; static int currentaddr = 0; static unsigned int remoteport = 0; -static isc_nm_t *netmgr = NULL; static isc_buffer_t *databuf = NULL; static isccc_ccmsg_t rndc_ccmsg; static uint32_t algorithm; @@ -1030,9 +1031,7 @@ main(int argc, char **argv) { serial = isc_random32(); isc_mem_create(&rndc_mctx); - netmgr = isc_nm_start(rndc_mctx, 1); - DO("create task manager", - isc_taskmgr_create(rndc_mctx, 0, netmgr, &taskmgr)); + isc_managers_create(rndc_mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); DO("create task", isc_task_create(taskmgr, 0, &rndc_task)); isc_log_create(rndc_mctx, &log, &logconfig); isc_log_setcontext(log); @@ -1089,9 +1088,7 @@ main(int argc, char **argv) { } isc_task_detach(&rndc_task); - isc_taskmgr_destroy(&taskmgr); - - isc_nm_closedown(netmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); /* * Note: when TCP connections are shut down, there will be a final @@ -1101,8 +1098,6 @@ main(int argc, char **argv) { */ isccc_ccmsg_invalidate(&rndc_ccmsg); - isc_nm_destroy(&netmgr); - isc_log_destroy(&log); isc_log_setcontext(NULL); diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 02f312ee2f..aa2007d7d2 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -208,10 +209,10 @@ main(int argc, char *argv[]) { isc_logconfig_t *lcfg; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_task_t *task; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; - dns_dispatchmgr_t *dispatchmgr; + isc_task_t *task = NULL; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; unsigned int attrs, attrmask; dns_dispatch_t *dispatchv4; dns_view_t *view; @@ -277,17 +278,10 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - netmgr = isc_nm_start(mctx, 1); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); - RUNCHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - task = NULL; RUNCHECK(isc_task_create(taskmgr, 0, &task)); - timermgr = NULL; - - RUNCHECK(isc_timermgr_create(mctx, &timermgr)); - socketmgr = NULL; - RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); - dispatchmgr = NULL; RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | @@ -318,13 +312,10 @@ main(int argc, char *argv[]) { dns_dispatch_detach(&dispatchv4); dns_dispatchmgr_destroy(&dispatchmgr); - isc_socketmgr_destroy(&socketmgr); - isc_timermgr_destroy(&timermgr); - isc_task_shutdown(task); isc_task_detach(&task); - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); + + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); dst_lib_destroy(); diff --git a/bin/tests/system/resolve.c b/bin/tests/system/resolve.c index b2fc5225a8..c8f7a18621 100644 --- a/bin/tests/system/resolve.c +++ b/bin/tests/system/resolve.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -66,25 +67,8 @@ isc_timermgr_t *ctxs_timermgr = NULL; static void ctxs_destroy(void) { - if (ctxs_netmgr != NULL) { - isc_nm_closedown(ctxs_netmgr); - } - - if (ctxs_taskmgr != NULL) { - isc_taskmgr_destroy(&ctxs_taskmgr); - } - - if (ctxs_netmgr != NULL) { - isc_nm_destroy(&ctxs_netmgr); - } - - if (ctxs_timermgr != NULL) { - isc_timermgr_destroy(&ctxs_timermgr); - } - - if (ctxs_socketmgr != NULL) { - isc_socketmgr_destroy(&ctxs_socketmgr); - } + isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, + &ctxs_socketmgr); if (ctxs_actx != NULL) { isc_appctx_destroy(&ctxs_actx); @@ -106,22 +90,8 @@ ctxs_init(void) { goto fail; } - ctxs_netmgr = isc_nm_start(ctxs_mctx, 1); - - result = isc_taskmgr_create(ctxs_mctx, 0, ctxs_netmgr, &ctxs_taskmgr); - if (result != ISC_R_SUCCESS) { - goto fail; - } - - result = isc_socketmgr_create(ctxs_mctx, &ctxs_socketmgr); - if (result != ISC_R_SUCCESS) { - goto fail; - } - - result = isc_timermgr_create(ctxs_mctx, &ctxs_timermgr); - if (result != ISC_R_SUCCESS) { - goto fail; - } + isc_managers_create(ctxs_mctx, 1, 0, 0, &ctxs_netmgr, &ctxs_taskmgr, + &ctxs_timermgr, &ctxs_socketmgr); return (ISC_R_SUCCESS); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 51ed1212dd..b72b38056a 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -191,21 +192,21 @@ sendquery(isc_task_t *task, isc_event_t *event) { int main(int argc, char *argv[]) { - char *ourkeyname; + char *ourkeyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; - isc_socket_t *sock; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *sock = NULL; unsigned int attrs, attrmask; isc_sockaddr_t bind_any; - dns_dispatchmgr_t *dispatchmgr; - dns_dispatch_t *dispatchv4; - dns_view_t *view; - dns_tkeyctx_t *tctx; - isc_log_t *log; - isc_logconfig_t *logconfig; - isc_task_t *task; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; + dns_tkeyctx_t *tctx = NULL; + isc_log_t *log = NULL; + isc_logconfig_t *logconfig = NULL; + isc_task_t *task = NULL; isc_result_t result; int type; @@ -235,17 +236,12 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - netmgr = isc_nm_start(mctx, 1); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); - RUNCHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - task = NULL; RUNCHECK(isc_task_create(taskmgr, 0, &task)); - timermgr = NULL; - RUNCHECK(isc_timermgr_create(mctx, &timermgr)); - socketmgr = NULL; - RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); - dispatchmgr = NULL; RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + isc_sockaddr_any(&bind_any); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | DNS_DISPATCHATTR_IPV4; @@ -293,11 +289,8 @@ main(int argc, char *argv[]) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); isc_socket_detach(&sock); - isc_socketmgr_destroy(&socketmgr); - isc_timermgr_destroy(&timermgr); + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); dst_key_free(&ourkey); dns_tsigkey_detach(&initialkey); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index cc92df049c..891b9cd04f 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -135,22 +136,22 @@ sendquery(isc_task_t *task, isc_event_t *event) { int main(int argc, char **argv) { - char *keyname; - isc_nm_t *netmgr; + char *keyname = NULL; + isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; - isc_socket_t *sock; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_socket_t *sock = NULL; unsigned int attrs, attrmask; isc_sockaddr_t bind_any; - dns_dispatchmgr_t *dispatchmgr; - dns_dispatch_t *dispatchv4; - dns_view_t *view; - dns_tkeyctx_t *tctx; - dst_key_t *dstkey; - isc_log_t *log; - isc_logconfig_t *logconfig; - isc_task_t *task; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; + dns_tkeyctx_t *tctx = NULL; + dst_key_t *dstkey = NULL; + isc_log_t *log = NULL; + isc_logconfig_t *logconfig = NULL; + isc_task_t *task = NULL; isc_result_t result; int type; @@ -179,16 +180,10 @@ main(int argc, char **argv) { RUNCHECK(dst_lib_init(mctx, NULL)); - netmgr = isc_nm_start(mctx, 1); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); - RUNCHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - task = NULL; RUNCHECK(isc_task_create(taskmgr, 0, &task)); - timermgr = NULL; - RUNCHECK(isc_timermgr_create(mctx, &timermgr)); - socketmgr = NULL; - RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); - dispatchmgr = NULL; RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); isc_sockaddr_any(&bind_any); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | @@ -237,11 +232,8 @@ main(int argc, char **argv) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); isc_socket_detach(&sock); - isc_socketmgr_destroy(&socketmgr); - isc_timermgr_destroy(&timermgr); + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); dns_tsigkeyring_detach(&ring); diff --git a/bin/tests/test_client.c b/bin/tests/test_client.c index c145115af8..6337406298 100644 --- a/bin/tests/test_client.c +++ b/bin/tests/test_client.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -307,7 +308,7 @@ setup(void) { isc_mem_create(&mctx); - netmgr = isc_nm_start(mctx, workers); + isc_managers_create(mctx, workers, 0, 0, &netmgr, NULL, NULL, NULL); } static void @@ -316,7 +317,7 @@ teardown(void) { close(out); } - isc_nm_destroy(&netmgr); + isc_managers_destroy(&netmgr, NULL, NULL, NULL); isc_mem_destroy(&mctx); if (tls_ctx) { isc_tlsctx_free(&tls_ctx); @@ -464,8 +465,6 @@ run(void) { } waitforsignal(); - - isc_nm_closedown(netmgr); } int diff --git a/bin/tests/test_server.c b/bin/tests/test_server.c index 9276b62022..a53577e201 100644 --- a/bin/tests/test_server.c +++ b/bin/tests/test_server.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -188,12 +189,12 @@ setup(void) { isc_mem_create(&mctx); - netmgr = isc_nm_start(mctx, workers); + isc_managers_create(mctx, workers, 0, 0, &netmgr, NULL, NULL, NULL); } static void teardown(void) { - isc_nm_destroy(&netmgr); + isc_managers_destroy(&netmgr, NULL, NULL, NULL); isc_mem_destroy(&mctx); if (tls_ctx) { isc_tlsctx_free(&tls_ctx); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index a8c47b6197..1b0f04c4ce 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2070,10 +2071,10 @@ main(int argc, char *argv[]) { isc_logconfig_t *lcfg; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_task_t *task; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; - dns_dispatchmgr_t *dispatchmgr; + isc_task_t *task = NULL; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; unsigned int attrs, attrmask; dns_dispatch_t *dispatchvx; dns_view_t *view; @@ -2130,17 +2131,11 @@ main(int argc, char *argv[]) { fatal("can't choose between IPv4 and IPv6"); } - netmgr = isc_nm_start(mctx, 1); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); - RUNCHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - task = NULL; RUNCHECK(isc_task_create(taskmgr, 0, &task)); - timermgr = NULL; - RUNCHECK(isc_timermgr_create(mctx, &timermgr)); - socketmgr = NULL; - RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); - dispatchmgr = NULL; RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY; @@ -2206,13 +2201,10 @@ main(int argc, char *argv[]) { dns_dispatch_detach(&dispatchvx); dns_dispatchmgr_destroy(&dispatchmgr); - isc_socketmgr_destroy(&socketmgr); - isc_timermgr_destroy(&timermgr); - isc_task_shutdown(task); isc_task_detach(&task); - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); + + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); dst_lib_destroy(); diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 48e3ae34b5..3acb5a1983 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -1735,6 +1735,12 @@ dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); *\li 'zone->zmgr' == NULL; */ +isc_taskmgr_t * +dns_zonemgr_gettaskmgr(dns_zonemgr_t *zmgr); +/*% + * Get the tasmkgr object attached to 'zmgr'. + */ + void dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value); /*%< @@ -1746,7 +1752,7 @@ dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value); */ uint32_t -dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr); +dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr); /*%< * Return the maximum number of simultaneous transfers in allowed. * @@ -1764,7 +1770,7 @@ dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value); */ uint32_t -dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr); +dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr); /*%< * Return the number of transfers allowed per nameserver. * diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 71f0e0c743..c14eed36e8 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -95,18 +96,10 @@ cleanup_managers(void) { isc_task_shutdown(maintask); isc_task_destroy(&maintask); } - if (socketmgr != NULL) { - isc_socketmgr_destroy(&socketmgr); - } - if (taskmgr != NULL) { - isc_taskmgr_destroy(&taskmgr); - } - if (netmgr != NULL) { - isc_nm_destroy(&netmgr); - } - if (timermgr != NULL) { - isc_timermgr_destroy(&timermgr); - } + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, + taskmgr == NULL ? NULL : &taskmgr, + timermgr == NULL ? NULL : &timermgr, + socketmgr == NULL ? NULL : &socketmgr); if (app_running) { isc_app_finish(); } @@ -117,10 +110,8 @@ create_managers(void) { isc_result_t result; ncpus = isc_os_ncpus(); - netmgr = isc_nm_start(dt_mctx, ncpus); - CHECK(isc_taskmgr_create(dt_mctx, 0, netmgr, &taskmgr)); - CHECK(isc_timermgr_create(dt_mctx, &timermgr)); - CHECK(isc_socketmgr_create(dt_mctx, &socketmgr)); + isc_managers_create(dt_mctx, ncpus, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); CHECK(isc_task_create(taskmgr, 0, &maintask)); return (ISC_R_SUCCESS); diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index bcf586d02b..145d47883e 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -1389,8 +1389,9 @@ dns_zonemgr_getiolimit dns_zonemgr_getnotifyrate dns_zonemgr_getserialqueryrate dns_zonemgr_getstartupnotifyrate -dns_zonemgr_getttransfersin -dns_zonemgr_getttransfersperns +dns_zonemgr_gettaskmgr +dns_zonemgr_gettransfersin +dns_zonemgr_gettransfersperns dns_zonemgr_managezone dns_zonemgr_releasezone dns_zonemgr_resumexfrs diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9553ade3e8..c0d69c76aa 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -18478,7 +18478,7 @@ dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value) { } uint32_t -dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr) { +dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); return (zmgr->transfersin); @@ -18492,12 +18492,19 @@ dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value) { } uint32_t -dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) { +dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); return (zmgr->transfersperns); } +isc_taskmgr_t * +dns_zonemgr_gettaskmgr(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + return (zmgr->taskmgr); +} + /* * Try to start a new incoming zone transfer to fill a quota * slot that was just vacated. diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 22212d9e38..c5368309f4 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -11,6 +11,7 @@ libisc_la_HEADERS = \ include/isc/atomic.h \ include/isc/attributes.h \ include/isc/backtrace.h \ + include/isc/barrier.h \ include/isc/base32.h \ include/isc/base64.h \ include/isc/bind9.h \ @@ -46,6 +47,7 @@ libisc_la_HEADERS = \ include/isc/list.h \ include/isc/log.h \ include/isc/magic.h \ + include/isc/managers.h \ include/isc/md.h \ include/isc/mem.h \ include/isc/meminfo.h \ @@ -182,6 +184,7 @@ libisc_la_SOURCES = \ lex.c \ lib.c \ log.c \ + managers.c \ md.c \ mem.c \ mutexblock.c \ @@ -222,6 +225,10 @@ libisc_la_SOURCES = \ pthreads/thread.c \ entropy_private.h \ fsaccess_common_p.h \ + task_p.h \ + timer_p.h \ + socket_p.h \ + netmgr_p.h \ lib_p.h \ mem_p.h \ tls_p.h diff --git a/lib/isc/hp.c b/lib/isc/hp.c index 92d160b3eb..20646a8a74 100644 --- a/lib/isc/hp.c +++ b/lib/isc/hp.c @@ -82,6 +82,9 @@ tid(void) { void isc_hp_init(int max_threads) { + if (isc__hp_max_threads > max_threads) { + return; + } isc__hp_max_threads = max_threads; isc__hp_max_retired = max_threads * HP_MAX_HPS; } diff --git a/lib/isc/include/isc/barrier.h b/lib/isc/include/isc/barrier.h new file mode 100644 index 0000000000..48353c69a8 --- /dev/null +++ b/lib/isc/include/isc/barrier.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include + +#if __SANITIZE_THREAD__ && !defined(WIN32) + +#include + +#define isc_barrier_t pthread_barrier_t + +#define isc_barrier_init(barrier, count) \ + pthread_barrier_init(barrier, NULL, count) +#define isc_barrier_destroy(barrier) pthread_barrier_destroy(barrier) +#define isc_barrier_wait(barrier) pthread_barrier_wait(barrier) + +#else + +#include + +#define isc_barrier_t uv_barrier_t + +#define isc_barrier_init(barrier, count) uv_barrier_init(barrier, count) +#define isc_barrier_destroy(barrier) uv_barrier_destroy(barrier) +#define isc_barrier_wait(barrier) uv_barrier_wait(barrier) + +#endif /* __SANITIZE_THREAD__ */ diff --git a/lib/isc/include/isc/hp.h b/lib/isc/include/isc/hp.h index 44155e625a..948eaa894a 100644 --- a/lib/isc/include/isc/hp.h +++ b/lib/isc/include/isc/hp.h @@ -66,8 +66,10 @@ typedef void(isc_hp_deletefunc_t)(void *); void isc_hp_init(int max_threads); /*%< - * Initialize hazard pointer constants - isc__hp_max_threads. If more threads - * will try to access hp it will assert. + * Initialize hazard pointer constants, isc__hp_max_threads and + * isc__hp_max_retired. If more threads try to access hp, it + * will assert. Calling this function repeatedly can be used + * to increase the limits, but cannot reduce them. */ isc_hp_t * diff --git a/lib/isc/include/isc/managers.h b/lib/isc/include/isc/managers.h new file mode 100644 index 0000000000..3b3227b09e --- /dev/null +++ b/lib/isc/include/isc/managers.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include +#include +#include +#include + +typedef struct isc_managers isc_managers_t; + +isc_result_t +isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum, + size_t sockets, isc_nm_t **netmgrp, + isc_taskmgr_t **taskmgrp, isc_timermgr_t **timermgrp, + isc_socketmgr_t **socketmgrp); + +void +isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp, + isc_timermgr_t **timermgrp, isc_socketmgr_t **socketmgrp); diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 5ecb92d022..7ce897786b 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -68,19 +68,10 @@ typedef void (*isc_nm_opaquecb_t)(void *arg); * callbacks. */ -isc_nm_t * -isc_nm_start(isc_mem_t *mctx, uint32_t workers); -/*%< - * Creates a new network manager with 'workers' worker threads, - * and starts it running. - */ - void isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst); void isc_nm_detach(isc_nm_t **mgr0); -void -isc_nm_destroy(isc_nm_t **mgr0); /*%< * Attach/detach a network manager. When all references have been * released, the network manager is shut down, freeing all resources. @@ -88,15 +79,6 @@ isc_nm_destroy(isc_nm_t **mgr0); * for all other references to be gone. */ -void -isc_nm_closedown(isc_nm_t *mgr); -/*%< - * Close down all active connections, freeing associated resources; - * prevent new connections from being established. This can optionally - * be called prior to shutting down the netmgr, to stop all processing - * before shutting down the task manager. - */ - /* Return thread ID of current thread, or ISC_NETMGR_TID_UNKNOWN */ int isc_nm_tid(void); diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index 61b853c990..ad6cf29603 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -9,8 +9,7 @@ * information regarding copyright ownership. */ -#ifndef ISC_SOCKET_H -#define ISC_SOCKET_H 1 +#pragma once /***** ***** Module Info @@ -676,42 +675,6 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, isc_task_t *task, */ /*@}*/ -isc_result_t -isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); - -isc_result_t -isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, - unsigned int maxsocks, int nthreads); -/*%< - * Create a socket manager. If "maxsocks" is non-zero, it specifies the - * maximum number of sockets that the created manager should handle. - * isc_socketmgr_create() is equivalent of isc_socketmgr_create2() with - * "maxsocks" being zero. - * - * Notes: - * - *\li All memory will be allocated in memory context 'mctx'. - * - * Requires: - * - *\li 'mctx' is a valid memory context. - * - *\li 'managerp' points to a NULL isc_socketmgr_t. - * - *\li 'actx' is a valid application context (for createinctx()). - * - * Ensures: - * - *\li '*managerp' is a valid isc_socketmgr_t. - * - * Returns: - * - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li #ISC_R_UNEXPECTED - *\li #ISC_R_NOTIMPLEMENTED - */ - isc_result_t isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp); /*%< @@ -741,31 +704,6 @@ isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats); * (see above). */ -void -isc_socketmgr_destroy(isc_socketmgr_t **managerp); -/*%< - * Destroy a socket manager. - * - * Notes: - * - *\li This routine blocks until there are no sockets left in the manager, - * so if the caller holds any socket references using the manager, it - * must detach them before calling isc_socketmgr_destroy() or it will - * block forever. - * - * Requires: - * - *\li '*managerp' is a valid isc_socketmgr_t. - * - *\li All sockets managed by this manager are fully detached. - * - * Ensures: - * - *\li *managerp == NULL - * - *\li All resources used by the manager have been freed. - */ - isc_sockettype_t isc_socket_gettype(isc_socket_t *sock); /*%< @@ -908,5 +846,3 @@ typedef isc_result_t (*isc_socketmgrcreatefunc_t)(isc_mem_t * mctx, isc_socketmgr_t **managerp); ISC_LANG_ENDDECLS - -#endif /* ISC_SOCKET_H */ diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h index 29e7c99544..4883785a22 100644 --- a/lib/isc/include/isc/task.h +++ b/lib/isc/include/isc/task.h @@ -9,12 +9,11 @@ * information regarding copyright ownership. */ -#ifndef ISC_TASK_H -#define ISC_TASK_H 1 +#pragma once /***** -***** Module Info -*****/ + ***** Module Info + *****/ /*! \file isc/task.h * \brief The task system provides a lightweight execution context, which is @@ -85,8 +84,8 @@ #define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535) /***** -***** Tasks. -*****/ + ***** Tasks. + *****/ ISC_LANG_BEGINDECLS @@ -137,6 +136,12 @@ isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum, *\li #ISC_R_SHUTTINGDOWN */ +void +isc_task_ready(isc_task_t *task); +/*%< + * Enqueue the task onto netmgr queue. + */ + isc_result_t isc_task_run(isc_task_t *task); /*%< @@ -606,15 +611,15 @@ isc_task_setprivilege(isc_task_t *task, bool priv); * but when the task manager has been set to privileged execution mode via * isc_taskmgr_setmode(), only tasks with the flag set will be executed, * and all other tasks will wait until they're done. Once all privileged - * tasks have finished executing, the task manager will automatically - * return to normal execution mode and nonprivileged task can resume. + * tasks have finished executing, the task manager resumes running + * non-privileged tasks. * * Requires: *\li 'task' is a valid task. */ bool -isc_task_privilege(isc_task_t *task); +isc_task_getprivilege(isc_task_t *task); /*%< * Returns the current value of the task's privilege flag. * @@ -622,83 +627,47 @@ isc_task_privilege(isc_task_t *task); *\li 'task' is a valid task. */ -/***** -***** Task Manager. -*****/ - -isc_result_t -isc_taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, - isc_taskmgr_t **managerp); +bool +isc_task_privileged(isc_task_t *task); /*%< - * Create a new task manager. - * - * Notes: - * - *\li If 'default_quantum' is non-zero, then it will be used as the default - * quantum value when tasks are created. If zero, then an implementation - * defined default quantum will be used. - * - *\li If 'nm' is set then netmgr is paused when an exclusive task mode - * is requested. + * Returns true if the task's privilege flag is set *and* the task + * manager is currently in privileged mode. * * Requires: - * - *\li 'mctx' is a valid memory context. - * - *\li managerp != NULL && *managerp == NULL - * - * Ensures: - * - *\li On success, '*managerp' will be attached to the newly created task - * manager. - * - * Returns: - * - *\li #ISC_R_SUCCESS - *\li #ISC_R_NOMEMORY - *\li #ISC_R_NOTHREADS No threads could be created. - *\li #ISC_R_UNEXPECTED An unexpected error occurred. - *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task - * manager shutting down. + *\li 'task' is a valid task. */ +/***** + ***** Task Manager. + *****/ + void isc_taskmgr_attach(isc_taskmgr_t *, isc_taskmgr_t **); void isc_taskmgr_detach(isc_taskmgr_t *); +/*%< + * Attach/detach the task manager. + */ void -isc_taskmgr_destroy(isc_taskmgr_t **managerp); +isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode); +isc_taskmgrmode_t +isc_taskmgr_mode(isc_taskmgr_t *manager); /*%< - * Destroy '*managerp'. + * Set/get the operating mode of the task manager. Valid modes are: * - * Notes: + *\li isc_taskmgrmode_normal + *\li isc_taskmgrmode_privileged * - *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by - * *managerp that haven't already been shutdown. The call will block - * until all tasks have entered the done state. - * - *\li isc_taskmgr_destroy() must not be called by a task event action, - * because it would block forever waiting for the event action to - * complete. An event action that wants to cause task manager shutdown - * should request some non-event action thread of execution to do the - * shutdown, e.g. by signaling a condition variable or using - * isc_app_shutdown(). - * - *\li Task manager references are not reference counted, so the caller - * must ensure that no attempt will be made to use the manager after - * isc_taskmgr_destroy() returns. + * In privileged execution mode, only tasks that have had the "privilege" + * flag set via isc_task_setprivilege() can be executed. When all such + * tasks are complete, non-privileged tasks resume running. The task calling + * this function should be in task-exclusive mode; the privileged tasks + * will be run after isc_task_endexclusive() is called. * * Requires: * - *\li '*managerp' is a valid task manager. - * - *\li isc_taskmgr_destroy() has not be called previously on '*managerp'. - * - * Ensures: - * - *\li All resources used by the task manager, and any tasks it managed, - * have been freed. + *\li 'manager' is a valid task manager. */ void @@ -736,5 +705,3 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr, void *tasksobj0); #endif /* HAVE_JSON_C */ ISC_LANG_ENDDECLS - -#endif /* ISC_TASK_H */ diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h index 88601b8f85..96376e5cc8 100644 --- a/lib/isc/include/isc/timer.h +++ b/lib/isc/include/isc/timer.h @@ -9,8 +9,7 @@ * information regarding copyright ownership. */ -#ifndef ISC_TIMER_H -#define ISC_TIMER_H 1 +#pragma once /***** ***** Module Info @@ -276,58 +275,7 @@ isc_timer_gettype(isc_timer_t *timer); *\li 'timer' to be a valid timer. */ -isc_result_t -isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); -/*%< - * Create a timer manager. - * - * Notes: - * - *\li All memory will be allocated in memory context 'mctx'. - * - * Requires: - * - *\li 'mctx' is a valid memory context. - * - *\li 'managerp' points to a NULL isc_timermgr_t. - * - * Ensures: - * - *\li '*managerp' is a valid isc_timermgr_t. - * - * Returns: - * - *\li Success - *\li No memory - *\li Unexpected error - */ - -void -isc_timermgr_destroy(isc_timermgr_t **managerp); -/*%< - * Destroy a timer manager. - * - * Notes: - * - *\li This routine blocks until there are no timers left in the manager, - * so if the caller holds any timer references using the manager, it - * must detach them before calling isc_timermgr_destroy() or it will - * block forever. - * - * Requires: - * - *\li '*managerp' is a valid isc_timermgr_t. - * - * Ensures: - * - *\li *managerp == NULL - * - *\li All resources used by the manager have been freed. - */ - void isc_timermgr_poke(isc_timermgr_t *m); ISC_LANG_ENDDECLS - -#endif /* ISC_TIMER_H */ diff --git a/lib/isc/managers.c b/lib/isc/managers.c new file mode 100644 index 0000000000..f86d4c8485 --- /dev/null +++ b/lib/isc/managers.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include "netmgr_p.h" +#include "socket_p.h" +#include "task_p.h" +#include "timer_p.h" + +isc_result_t +isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum, + size_t sockets, isc_nm_t **netmgrp, + isc_taskmgr_t **taskmgrp, isc_timermgr_t **timermgrp, + isc_socketmgr_t **socketmgrp) { + isc_result_t result; + isc_nm_t *netmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_timermgr_t *timermgr = NULL; + + /* + * We have ncpus network threads, ncpus old network threads - make + * it 4x just to be on the safe side. + */ + isc_hp_init(4 * workers); + + REQUIRE(netmgrp != NULL && *netmgrp == NULL); + isc__netmgr_create(mctx, workers, &netmgr); + *netmgrp = netmgr; + INSIST(netmgr != NULL); + + REQUIRE(taskmgrp == NULL || *taskmgrp == NULL); + if (taskmgrp != NULL) { + INSIST(netmgr != NULL); + result = isc__taskmgr_create(mctx, quantum, netmgr, &taskmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_taskmgr_create() failed: %s", + isc_result_totext(result)); + goto fail; + } + *taskmgrp = taskmgr; + } + + REQUIRE(timermgrp == NULL || *timermgrp == NULL); + if (timermgrp != NULL) { + result = isc__timermgr_create(mctx, &timermgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_timermgr_create() failed: %s", + isc_result_totext(result)); + goto fail; + } + *timermgrp = timermgr; + } + + REQUIRE(socketmgrp == NULL || *socketmgrp == NULL); + if (socketmgrp != NULL) { + result = isc__socketmgr_create(mctx, &socketmgr, sockets, + workers); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socketmgr_create() failed: %s", + isc_result_totext(result)); + goto fail; + } + *socketmgrp = socketmgr; + } + + return (ISC_R_SUCCESS); +fail: + isc_managers_destroy(netmgrp, taskmgrp, timermgrp, socketmgrp); + + return (result); +} + +void +isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp, + isc_timermgr_t **timermgrp, isc_socketmgr_t **socketmgrp) { + /* + * If we have a taskmgr to clean up, then we must also have a netmgr. + */ + REQUIRE(taskmgrp != NULL || netmgrp == NULL); + + /* + * The sequence of operations here is important: + * + * 1. Initiate shutdown of the taskmgr, sending shutdown events to + * all tasks that are not already shutting down. + */ + if (taskmgrp != NULL) { + INSIST(*taskmgrp != NULL); + isc__taskmgr_shutdown(*taskmgrp); + } + + /* + * 2. Initiate shutdown of the network manager, freeing clients + * and other resources and preventing new connections, but do + * not stop processing of existing events. + */ + if (netmgrp != NULL) { + INSIST(*netmgrp != NULL); + isc__netmgr_shutdown(*netmgrp); + } + + /* + * 3. Finish destruction of the task manager when all tasks + * have completed. + */ + if (taskmgrp != NULL) { + isc__taskmgr_destroy(taskmgrp); + } + + /* + * 4. Finish destruction of the netmgr, and wait until all + * references have been released. + */ + if (netmgrp != NULL) { + isc__netmgr_destroy(netmgrp); + } + + /* + * 5. Clean up the remaining managers. + */ + if (timermgrp != NULL) { + INSIST(*timermgrp != NULL); + isc__timermgr_destroy(timermgrp); + } + if (socketmgrp != NULL) { + INSIST(*socketmgrp != NULL); + isc__socketmgr_destroy(socketmgrp); + } +} diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 4482e2023d..b76c0b263b 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -1199,7 +1199,7 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; - sock->result = ISC_R_DEFAULT; + sock->result = ISC_R_UNSET; sock->connect_cb = cb; sock->connect_cbarg = cbarg; atomic_init(&sock->client, true); @@ -2170,8 +2170,8 @@ isc_nm_listenhttp(isc_nm_t *mgr, isc_nmiface_t *iface, int backlog, isc__nmsocket_attach(sock, &sock->outer->h2.httpserver); sock->nchildren = sock->outer->nchildren; - sock->result = ISC_R_DEFAULT; - sock->tid = isc_random_uniform(sock->nchildren); + sock->result = ISC_R_UNSET; + sock->tid = 0; sock->fd = (uv_os_sock_t)-1; atomic_store(&sock->listening, true); @@ -2239,8 +2239,6 @@ isc_nm_http_endpoint(isc_nmsocket_t *sock, const char *uri, isc_nm_recv_cb_t cb, void isc__nm_http_stoplistening(isc_nmsocket_t *sock) { - isc__netievent_httpstop_t *ievent = NULL; - REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_httplistener); @@ -2250,9 +2248,16 @@ isc__nm_http_stoplistening(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } - ievent = isc__nm_get_netievent_httpstop(sock->mgr, sock); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); + if (!isc__nm_in_netthread()) { + isc__netievent_httpstop_t *ievent = + isc__nm_get_netievent_httpstop(sock->mgr, sock); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); + } else { + REQUIRE(isc_nm_tid() == sock->tid); + isc__netievent_httpstop_t ievent = { .sock = sock }; + isc__nm_async_httpstop(NULL, (isc__netievent_t *)&ievent); + } } static void @@ -2294,7 +2299,6 @@ isc__nm_async_httpstop(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(worker); REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); atomic_store(&sock->listening, false); atomic_store(&sock->closing, false); diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 4384932dca..e532b014cc 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #include "uv-compat.h" +#define ISC_NETMGR_QUANTUM_DEFAULT 128 + #define ISC_NETMGR_TID_UNKNOWN -1 /* Must be different from ISC_NETMGR_TID_UNKNOWN */ @@ -172,7 +175,6 @@ typedef struct isc__networker { uv_async_t async; /* async channel to send * data to this networker */ isc_mutex_t lock; - isc_condition_t cond; bool paused; bool finished; isc_thread_t thread; @@ -183,11 +185,14 @@ typedef struct isc__networker { * used for listening etc. * can be processed while * worker is paused */ + isc_condition_t cond_prio; + isc_refcount_t references; atomic_int_fast64_t pktcount; char *recvbuf; char *sendbuf; bool recvbuf_inuse; + unsigned int quantum; } isc__networker_t; /* @@ -244,7 +249,6 @@ typedef enum isc__netievent_type { netievent_udpclose, netievent_udpsend, netievent_udpread, - netievent_udpstop, netievent_udpcancel, netievent_tcpconnect, @@ -253,7 +257,6 @@ typedef enum isc__netievent_type { netievent_tcpstartread, netievent_tcppauseread, netievent_tcpaccept, - netievent_tcpstop, netievent_tcpcancel, netievent_tcpdnsaccept, @@ -262,7 +265,6 @@ typedef enum isc__netievent_type { netievent_tcpdnssend, netievent_tcpdnsread, netievent_tcpdnscancel, - netievent_tcpdnsstop, netievent_tlsclose, netievent_tlssend, @@ -277,12 +279,10 @@ typedef enum isc__netievent_type { netievent_tlsdnssend, netievent_tlsdnsread, netievent_tlsdnscancel, - netievent_tlsdnsstop, netievent_tlsdnscycle, netievent_tlsdnsshutdown, netievent_httpclose, - netievent_httpstop, netievent_httpsend, netievent_shutdown, @@ -296,19 +296,26 @@ typedef enum isc__netievent_type { netievent_task, netievent_privilegedtask, - netievent_prio = 0xff, /* event type values higher than this - * will be treated as high-priority - * events, which can be processed - * while the netmgr is paused. - */ + /* + * event type values higher than this will be treated + * as high-priority events, which can be processed + * while the netmgr is pausing or paused. + */ + netievent_prio = 0xff, + netievent_udplisten, + netievent_udpstop, netievent_tcplisten, + netievent_tcpstop, netievent_tcpdnslisten, + netievent_tcpdnsstop, netievent_tlsdnslisten, + netievent_tlsdnsstop, + netievent_httpstop, + netievent_resume, netievent_detach, netievent_close, - } isc__netievent_type; typedef union { @@ -653,7 +660,7 @@ struct isc_nm { int magic; isc_refcount_t references; isc_mem_t *mctx; - uint32_t nworkers; + int nworkers; isc_mutex_t lock; isc_condition_t wkstatecond; isc_condition_t wkpausecond; @@ -668,7 +675,7 @@ struct isc_nm { isc_mutex_t evlock; uint_fast32_t workers_running; - uint_fast32_t workers_paused; + atomic_uint_fast32_t workers_paused; atomic_uint_fast32_t maxudp; atomic_bool paused; @@ -699,6 +706,9 @@ struct isc_nm { atomic_uint_fast32_t keepalive; atomic_uint_fast32_t advertised; + isc_barrier_t pausing; + isc_barrier_t resuming; + #ifdef NETMGR_TRACE ISC_LIST(isc_nmsocket_t) active_sockets; #endif @@ -833,6 +843,9 @@ struct isc_nmsocket { /*% Self socket */ isc_nmsocket_t *self; + isc_barrier_t startlistening; + isc_barrier_t stoplistening; + /*% TLS stuff */ struct tls { isc_tls_t *tls; @@ -927,7 +940,7 @@ struct isc_nmsocket { /* Atomic */ /*% Number of running (e.g. listening) child sockets */ - uint_fast32_t rchildren; + atomic_uint_fast32_t rchildren; /*% * Socket is active if it's listening, working, etc. If it's diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 0699fe807e..2baa4419f9 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include "netmgr-int.h" +#include "netmgr_p.h" #include "openssl_shim.h" #include "uv-compat.h" @@ -134,15 +136,29 @@ nm_thread(isc_threadarg_t worker0); static void async_cb(uv_async_t *handle); static bool -process_queue(isc__networker_t *worker, isc_queue_t *queue); +process_netievent(isc__networker_t *worker, isc__netievent_t *ievent); static bool -process_priority_queue(isc__networker_t *worker); +process_queue(isc__networker_t *worker, isc_queue_t *queue, + unsigned int *quantump); static void -process_privilege_queue(isc__networker_t *worker); -static void -process_tasks_queue(isc__networker_t *worker); -static void -process_normal_queue(isc__networker_t *worker); +wait_for_priority_queue(isc__networker_t *worker); +static bool +process_priority_queue(isc__networker_t *worker, unsigned int *quantump); +static bool +process_privilege_queue(isc__networker_t *worker, unsigned int *quantump); +static bool +process_task_queue(isc__networker_t *worker, unsigned int *quantump); +static bool +process_normal_queue(isc__networker_t *worker, unsigned int *quantump); + +#define drain_priority_queue(worker) \ + (void)process_priority_queue(worker, &(unsigned int){ UINT_MAX }) +#define drain_privilege_queue(worker) \ + (void)process_privilege_queue(worker, &(unsigned int){ UINT_MAX }) +#define drain_task_queue(worker) \ + (void)process_task_queue(worker, &(unsigned int){ UINT_MAX }) +#define drain_normal_queue(worker) \ + (void)process_normal_queue(worker, &(unsigned int){ UINT_MAX }) static void isc__nm_async_stop(isc__networker_t *worker, isc__netievent_t *ev0); @@ -206,8 +222,8 @@ isc__nm_winsock_destroy(void) { } #endif /* WIN32 */ -isc_nm_t * -isc_nm_start(isc_mem_t *mctx, uint32_t workers) { +void +isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { isc_nm_t *mgr = NULL; char name[32]; @@ -227,6 +243,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { isc_refcount_init(&mgr->references, 1); atomic_init(&mgr->maxudp, 0); atomic_init(&mgr->interlocked, ISC_NETMGR_NON_INTERLOCKED); + atomic_init(&mgr->workers_paused, 0); #ifdef NETMGR_TRACE ISC_LIST_INIT(mgr->active_sockets); @@ -256,6 +273,9 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { isc_mempool_associatelock(mgr->evpool, &mgr->evlock); isc_mempool_setfillcount(mgr->evpool, 32); + isc_barrier_init(&mgr->pausing, workers); + isc_barrier_init(&mgr->resuming, workers); + mgr->workers = isc_mem_get(mctx, workers * sizeof(isc__networker_t)); for (size_t i = 0; i < workers; i++) { int r; @@ -263,6 +283,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { *worker = (isc__networker_t){ .mgr = mgr, .id = i, + .quantum = ISC_NETMGR_QUANTUM_DEFAULT, }; r = uv_loop_init(&worker->loop); @@ -274,12 +295,13 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { RUNTIME_CHECK(r == 0); isc_mutex_init(&worker->lock); - isc_condition_init(&worker->cond); worker->ievents = isc_queue_new(mgr->mctx, 128); - worker->ievents_priv = isc_queue_new(mgr->mctx, 128); worker->ievents_task = isc_queue_new(mgr->mctx, 128); + worker->ievents_priv = isc_queue_new(mgr->mctx, 128); worker->ievents_prio = isc_queue_new(mgr->mctx, 128); + isc_condition_init(&worker->cond_prio); + worker->recvbuf = isc_mem_get(mctx, ISC_NETMGR_RECVBUF_SIZE); worker->sendbuf = isc_mem_get(mctx, ISC_NETMGR_SENDBUF_SIZE); @@ -296,7 +318,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { } mgr->magic = NM_MAGIC; - return (mgr); + *netmgrp = mgr; } /* @@ -314,7 +336,7 @@ nm_destroy(isc_nm_t **mgr0) { mgr->magic = 0; - for (size_t i = 0; i < mgr->nworkers; i++) { + for (int i = 0; i < mgr->nworkers; i++) { isc__networker_t *worker = &mgr->workers[i]; isc__netievent_t *event = isc__nm_get_netievent_stop(mgr); isc__nm_enqueue_ievent(worker, event); @@ -326,7 +348,7 @@ nm_destroy(isc_nm_t **mgr0) { } UNLOCK(&mgr->lock); - for (size_t i = 0; i < mgr->nworkers; i++) { + for (int i = 0; i < mgr->nworkers; i++) { isc__networker_t *worker = &mgr->workers[i]; isc__netievent_t *ievent = NULL; int r; @@ -348,6 +370,7 @@ nm_destroy(isc_nm_t **mgr0) { { isc_mempool_put(mgr->evpool, ievent); } + isc_condition_destroy(&worker->cond_prio); r = uv_loop_close(&worker->loop); INSIST(r == 0); @@ -357,7 +380,6 @@ nm_destroy(isc_nm_t **mgr0) { isc_queue_destroy(worker->ievents_task); isc_queue_destroy(worker->ievents_prio); isc_mutex_destroy(&worker->lock); - isc_condition_destroy(&worker->cond); isc_mem_put(mgr->mctx, worker->sendbuf, ISC_NETMGR_SENDBUF_SIZE); @@ -370,6 +392,9 @@ nm_destroy(isc_nm_t **mgr0) { isc_stats_detach(&mgr->stats); } + isc_barrier_destroy(&mgr->resuming); + isc_barrier_destroy(&mgr->pausing); + isc_condition_destroy(&mgr->wkstatecond); isc_condition_destroy(&mgr->wkpausecond); isc_mutex_destroy(&mgr->lock); @@ -389,34 +414,70 @@ nm_destroy(isc_nm_t **mgr0) { #endif /* WIN32 */ } +static void +enqueue_pause(isc__networker_t *worker) { + isc__netievent_pause_t *event = + isc__nm_get_netievent_pause(worker->mgr); + isc__nm_enqueue_ievent(worker, (isc__netievent_t *)event); +} + +static void +isc__nm_async_pause(isc__networker_t *worker, isc__netievent_t *ev0) { + UNUSED(ev0); + REQUIRE(worker->paused == false); + + worker->paused = true; + uv_stop(&worker->loop); +} + void isc_nm_pause(isc_nm_t *mgr) { REQUIRE(VALID_NM(mgr)); - uint_fast32_t pausing = 0; REQUIRE(!atomic_load(&mgr->paused)); isc__nm_acquire_interlocked_force(mgr); - for (size_t i = 0; i < mgr->nworkers; i++) { + if (isc__nm_in_netthread()) { + REQUIRE(isc_nm_tid() == 0); + } + + for (int i = 0; i < mgr->nworkers; i++) { isc__networker_t *worker = &mgr->workers[i]; - if (i != (size_t)isc_nm_tid()) { - isc__netievent_resume_t *event = - isc__nm_get_netievent_pause(mgr); - pausing++; - isc__nm_enqueue_ievent(worker, - (isc__netievent_t *)event); - } else { + if (i == isc_nm_tid()) { isc__nm_async_pause(worker, NULL); + } else { + enqueue_pause(worker); } } + if (isc__nm_in_netthread()) { + atomic_fetch_add(&mgr->workers_paused, 1); + isc_barrier_wait(&mgr->pausing); + } + LOCK(&mgr->lock); - while (mgr->workers_paused != pausing) { + while (atomic_load(&mgr->workers_paused) != mgr->workers_running) { WAIT(&mgr->wkstatecond, &mgr->lock); } + UNLOCK(&mgr->lock); + REQUIRE(atomic_compare_exchange_strong(&mgr->paused, &(bool){ false }, true)); - UNLOCK(&mgr->lock); +} + +static void +enqueue_resume(isc__networker_t *worker) { + isc__netievent_resume_t *event = + isc__nm_get_netievent_resume(worker->mgr); + isc__nm_enqueue_ievent(worker, (isc__netievent_t *)event); +} + +static void +isc__nm_async_resume(isc__networker_t *worker, isc__netievent_t *ev0) { + UNUSED(ev0); + REQUIRE(worker->paused == true); + + worker->paused = false; } void @@ -424,26 +485,36 @@ isc_nm_resume(isc_nm_t *mgr) { REQUIRE(VALID_NM(mgr)); REQUIRE(atomic_load(&mgr->paused)); - for (size_t i = 0; i < mgr->nworkers; i++) { + if (isc__nm_in_netthread()) { + REQUIRE(isc_nm_tid() == 0); + drain_priority_queue(&mgr->workers[isc_nm_tid()]); + } + + for (int i = 0; i < mgr->nworkers; i++) { isc__networker_t *worker = &mgr->workers[i]; - if (i != (size_t)isc_nm_tid()) { - isc__netievent_resume_t *event = - isc__nm_get_netievent_resume(mgr); - isc__nm_enqueue_ievent(worker, - (isc__netievent_t *)event); - } else { + if (i == isc_nm_tid()) { isc__nm_async_resume(worker, NULL); + } else { + enqueue_resume(worker); } } + if (isc__nm_in_netthread()) { + drain_privilege_queue(&mgr->workers[isc_nm_tid()]); + + atomic_fetch_sub(&mgr->workers_paused, 1); + isc_barrier_wait(&mgr->resuming); + } + LOCK(&mgr->lock); - while (mgr->workers_paused != 0) { + while (atomic_load(&mgr->workers_paused) != 0) { WAIT(&mgr->wkstatecond, &mgr->lock); } + UNLOCK(&mgr->lock); + REQUIRE(atomic_compare_exchange_strong(&mgr->paused, &(bool){ true }, false)); - BROADCAST(&mgr->wkpausecond); - UNLOCK(&mgr->lock); + isc__nm_drop_interlocked(mgr); } @@ -473,11 +544,11 @@ isc_nm_detach(isc_nm_t **mgr0) { } void -isc_nm_closedown(isc_nm_t *mgr) { +isc__netmgr_shutdown(isc_nm_t *mgr) { REQUIRE(VALID_NM(mgr)); atomic_store(&mgr->closing, true); - for (size_t i = 0; i < mgr->nworkers; i++) { + for (int i = 0; i < mgr->nworkers; i++) { isc__netievent_t *event = NULL; event = isc__nm_get_netievent_shutdown(mgr); isc__nm_enqueue_ievent(&mgr->workers[i], event); @@ -485,19 +556,18 @@ isc_nm_closedown(isc_nm_t *mgr) { } void -isc_nm_destroy(isc_nm_t **mgr0) { +isc__netmgr_destroy(isc_nm_t **netmgrp) { isc_nm_t *mgr = NULL; int counter = 0; - REQUIRE(mgr0 != NULL); - REQUIRE(VALID_NM(*mgr0)); + REQUIRE(VALID_NM(*netmgrp)); - mgr = *mgr0; + mgr = *netmgrp; /* * Close active connections. */ - isc_nm_closedown(mgr); + isc__netmgr_shutdown(mgr); /* * Wait for the manager to be dereferenced elsewhere. @@ -524,7 +594,7 @@ isc_nm_destroy(isc_nm_t **mgr0) { /* * Detach final reference. */ - isc_nm_detach(mgr0); + isc_nm_detach(netmgrp); } void @@ -615,43 +685,29 @@ nm_thread(isc_threadarg_t worker0) { if (worker->paused) { INSIST(atomic_load(&mgr->interlocked) != isc_nm_tid()); - /* - * We need to lock the worker first; otherwise - * isc_nm_resume() might slip in before WAIT() in - * the while loop starts, then the signal never - * gets delivered and we are stuck forever in the - * paused loop. - */ - LOCK(&worker->lock); - LOCK(&mgr->lock); - mgr->workers_paused++; - SIGNAL(&mgr->wkstatecond); - UNLOCK(&mgr->lock); + atomic_fetch_add(&mgr->workers_paused, 1); + if (isc_barrier_wait(&mgr->pausing) != 0) { + LOCK(&mgr->lock); + SIGNAL(&mgr->wkstatecond); + UNLOCK(&mgr->lock); + } while (worker->paused) { - WAIT(&worker->cond, &worker->lock); - UNLOCK(&worker->lock); - (void)process_priority_queue(worker); - LOCK(&worker->lock); + wait_for_priority_queue(worker); } - LOCK(&mgr->lock); - mgr->workers_paused--; - SIGNAL(&mgr->wkstatecond); - UNLOCK(&mgr->lock); - UNLOCK(&worker->lock); - /* - * All workers must run the privileged event + * All workers must drain the privileged event * queue before we resume from pause. */ - process_privilege_queue(worker); + drain_privilege_queue(worker); - LOCK(&mgr->lock); - while (atomic_load(&mgr->paused)) { - WAIT(&mgr->wkpausecond, &mgr->lock); + atomic_fetch_sub(&mgr->workers_paused, 1); + if (isc_barrier_wait(&mgr->resuming) != 0) { + LOCK(&mgr->lock); + SIGNAL(&mgr->wkstatecond); + UNLOCK(&mgr->lock); } - UNLOCK(&mgr->lock); } if (r == 0) { @@ -660,16 +716,6 @@ nm_thread(isc_threadarg_t worker0) { } INSIST(!worker->finished); - - /* - * We've fully resumed from pause. Drain the normal - * asynchronous event queues before resuming the uv_run() - * loop. (This is not strictly necessary, it just ensures - * that all pending events are processed before another - * pause can slip in.) - */ - process_tasks_queue(worker); - process_normal_queue(worker); } /* @@ -677,8 +723,8 @@ nm_thread(isc_threadarg_t worker0) { * (they may include shutdown events) but do not process * the netmgr event queue. */ - process_privilege_queue(worker); - process_tasks_queue(worker); + drain_privilege_queue(worker); + drain_task_queue(worker); LOCK(&mgr->lock); mgr->workers_running--; @@ -688,6 +734,23 @@ nm_thread(isc_threadarg_t worker0) { return ((isc_threadresult_t)0); } +static bool +process_all_queues(isc__networker_t *worker, unsigned int quantum) { + /* + * The queue processing functions will return false when the + * system is pausing or stopping, or if we have completed + * 'quantum' events. + * + * We don't want to proceed to a new queue until the previous one + * has been fully drained, so whenever one queue is interrupted, + * we skip all the later ones. + */ + return (process_priority_queue(worker, &quantum) && + process_privilege_queue(worker, &quantum) && + process_task_queue(worker, &quantum) && + process_normal_queue(worker, &quantum)); +} + /* * async_cb() is a universal callback for 'async' events sent to event loop. * It's the only way to safely pass data to the libuv event loop. We use a @@ -697,18 +760,14 @@ nm_thread(isc_threadarg_t worker0) { static void async_cb(uv_async_t *handle) { isc__networker_t *worker = (isc__networker_t *)handle->loop->data; + unsigned int quantum = worker->quantum; - /* - * process_priority_queue() returns false when pausing or stopping, - * so we don't want to process the other queues in that case. - */ - if (!process_priority_queue(worker)) { - return; + if (!process_all_queues(worker, quantum)) { + /* If we didn't process all the events, we need to enqueue + * async_cb to be run in the next iteration of the uv_loop + */ + uv_async_send(handle); } - - process_privilege_queue(worker); - process_tasks_queue(worker); - process_normal_queue(worker); } static void @@ -719,23 +778,6 @@ isc__nm_async_stop(isc__networker_t *worker, isc__netievent_t *ev0) { uv_close((uv_handle_t *)&worker->async, NULL); } -static void -isc__nm_async_pause(isc__networker_t *worker, isc__netievent_t *ev0) { - UNUSED(ev0); - REQUIRE(worker->paused == false); - - worker->paused = true; - uv_stop(&worker->loop); -} - -static void -isc__nm_async_resume(isc__networker_t *worker, isc__netievent_t *ev0) { - UNUSED(ev0); - REQUIRE(worker->paused == true); - - worker->paused = false; -} - void isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) { isc__netievent_t *event = NULL; @@ -750,7 +792,7 @@ isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) { worker = &nm->workers[tid]; - if (isc_task_privilege(task)) { + if (isc_task_privileged(task)) { event = (isc__netievent_t *) isc__nm_get_netievent_privilegedtask(nm, task); } else { @@ -775,8 +817,7 @@ isc__nm_async_task(isc__networker_t *worker, isc__netievent_t *ev0) { switch (result) { case ISC_R_QUOTA: - isc_nm_task_enqueue(worker->mgr, (isc_task_t *)ievent->task, - isc_nm_tid()); + isc_task_ready(ievent->task); return; case ISC_R_SUCCESS: return; @@ -786,24 +827,52 @@ isc__nm_async_task(isc__networker_t *worker, isc__netievent_t *ev0) { } } +static void +wait_for_priority_queue(isc__networker_t *worker) { + isc_queue_t *queue = worker->ievents_prio; + isc_condition_t *cond = &worker->cond_prio; + bool wait_for_work = true; + + while (true) { + isc__netievent_t *ievent; + LOCK(&worker->lock); + ievent = (isc__netievent_t *)isc_queue_dequeue(queue); + if (wait_for_work) { + while (ievent == NULL) { + WAIT(cond, &worker->lock); + ievent = (isc__netievent_t *)isc_queue_dequeue( + queue); + } + } + UNLOCK(&worker->lock); + wait_for_work = false; + + if (ievent == NULL) { + return; + } + + (void)process_netievent(worker, ievent); + } +} + static bool -process_priority_queue(isc__networker_t *worker) { - return (process_queue(worker, worker->ievents_prio)); +process_priority_queue(isc__networker_t *worker, unsigned int *quantump) { + return (process_queue(worker, worker->ievents_prio, quantump)); } -static void -process_privilege_queue(isc__networker_t *worker) { - (void)process_queue(worker, worker->ievents_priv); +static bool +process_privilege_queue(isc__networker_t *worker, unsigned int *quantump) { + return (process_queue(worker, worker->ievents_priv, quantump)); } -static void -process_tasks_queue(isc__networker_t *worker) { - (void)process_queue(worker, worker->ievents_task); +static bool +process_task_queue(isc__networker_t *worker, unsigned int *quantump) { + return (process_queue(worker, worker->ievents_task, quantump)); } -static void -process_normal_queue(isc__networker_t *worker) { - (void)process_queue(worker, worker->ievents); +static bool +process_normal_queue(isc__networker_t *worker, unsigned int *quantump) { + return (process_queue(worker, worker->ievents, quantump)); } /* @@ -905,16 +974,27 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) { } static bool -process_queue(isc__networker_t *worker, isc_queue_t *queue) { - isc__netievent_t *ievent = NULL; +process_queue(isc__networker_t *worker, isc_queue_t *queue, + unsigned int *quantump) { + while (*quantump > 0) { + isc__netievent_t *ievent = + (isc__netievent_t *)isc_queue_dequeue(queue); + + if (ievent == NULL) { + /* We fully drained this queue */ + return (true); + } + + (*quantump)--; - while ((ievent = (isc__netievent_t *)isc_queue_dequeue(queue)) != NULL) - { if (!process_netievent(worker, ievent)) { + /* Netievent told us to stop */ return (false); } } - return (true); + + /* No more quantum */ + return (false); } void * @@ -1017,7 +1097,7 @@ isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) { */ LOCK(&worker->lock); isc_queue_enqueue(worker->ievents_prio, (uintptr_t)event); - SIGNAL(&worker->cond); + SIGNAL(&worker->cond_prio); UNLOCK(&worker->lock); } else if (event->type == netievent_privilegedtask) { isc_queue_enqueue(worker->ievents_priv, (uintptr_t)event); @@ -1105,7 +1185,14 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) { } /* - * This was a parent socket; free the children. + * This was a parent socket: destroy the listening + * barriers that synchronized the children. + */ + isc_barrier_destroy(&sock->startlistening); + isc_barrier_destroy(&sock->stoplistening); + + /* + * Now free them. */ isc_mem_put(sock->mgr->mctx, sock->children, sock->nchildren * sizeof(*sock)); @@ -1152,7 +1239,6 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) { isc_mem_free(sock->mgr->mctx, sock->ah_frees); isc_mem_free(sock->mgr->mctx, sock->ah_handles); isc_mutex_destroy(&sock->lock); - isc_condition_destroy(&sock->cond); isc_condition_destroy(&sock->scond); isc__nm_tls_cleanup_data(sock); isc__nm_http_cleanup_data(sock); @@ -1399,7 +1485,6 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type, } isc_mutex_init(&sock->lock); - isc_condition_init(&sock->cond); isc_condition_init(&sock->scond); isc_refcount_init(&sock->references, 1); @@ -2690,16 +2775,25 @@ isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0) { bool isc__nm_acquire_interlocked(isc_nm_t *mgr) { + if (!isc__nm_in_netthread()) { + return (false); + } + LOCK(&mgr->lock); bool success = atomic_compare_exchange_strong( &mgr->interlocked, &(int){ ISC_NETMGR_NON_INTERLOCKED }, isc_nm_tid()); + UNLOCK(&mgr->lock); return (success); } void isc__nm_drop_interlocked(isc_nm_t *mgr) { + if (!isc__nm_in_netthread()) { + return; + } + LOCK(&mgr->lock); int tid = atomic_exchange(&mgr->interlocked, ISC_NETMGR_NON_INTERLOCKED); @@ -2710,6 +2804,10 @@ isc__nm_drop_interlocked(isc_nm_t *mgr) { void isc__nm_acquire_interlocked_force(isc_nm_t *mgr) { + if (!isc__nm_in_netthread()) { + return; + } + LOCK(&mgr->lock); while (!atomic_compare_exchange_strong( &mgr->interlocked, &(int){ ISC_NETMGR_NON_INTERLOCKED }, diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 60cf9222c5..c7030ecccc 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,7 @@ failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { static isc_result_t tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; int r; REQUIRE(VALID_NMSOCK(sock)); @@ -302,7 +303,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; - sock->result = ISC_R_DEFAULT; + sock->result = ISC_R_UNSET; sock->fd = (uv_os_sock_t)-1; atomic_init(&sock->client, true); @@ -344,7 +345,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)ievent); } LOCK(&sock->lock); - while (sock->result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_UNSET) { WAIT(&sock->cond, &sock->lock); } atomic_store(&sock->active, true); @@ -375,6 +376,47 @@ isc__nm_tcp_lb_socket(sa_family_t sa_family) { return (sock); } +static void +start_tcp_child(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t *sock, + uv_os_sock_t fd, int tid) { + isc__netievent_tcplisten_t *ievent = NULL; + isc_nmsocket_t *csock = &sock->children[tid]; + + isc__nmsocket_init(csock, mgr, isc_nm_tcpsocket, iface); + csock->parent = sock; + csock->accept_cb = sock->accept_cb; + csock->accept_cbarg = sock->accept_cbarg; + csock->extrahandlesize = sock->extrahandlesize; + csock->backlog = sock->backlog; + csock->tid = tid; + /* + * We don't attach to quota, just assign - to avoid + * increasing quota unnecessarily. + */ + csock->pquota = sock->pquota; + isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); + +#if HAVE_SO_REUSEPORT_LB || defined(WIN32) + UNUSED(fd); + csock->fd = isc__nm_tcp_lb_socket(iface->addr.type.sa.sa_family); +#else + csock->fd = dup(fd); +#endif + REQUIRE(csock->fd >= 0); + + ievent = isc__nm_get_netievent_tcplisten(mgr, csock); + isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], + (isc__netievent_t *)ievent); +} + +static void +enqueue_stoplistening(isc_nmsocket_t *sock) { + isc__netievent_tcpstop_t *ievent = + isc__nm_get_netievent_tcpstop(sock->mgr, sock); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + isc_result_t isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_accept_cb_t accept_cb, void *accept_cbarg, @@ -382,18 +424,15 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t **sockp) { isc_result_t result = ISC_R_SUCCESS; isc_nmsocket_t *sock = NULL; - sa_family_t sa_family = iface->addr.type.sa.sa_family; size_t children_size = 0; -#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) uv_os_sock_t fd = -1; -#endif REQUIRE(VALID_NM(mgr)); sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tcplistener, iface); - sock->rchildren = 0; + atomic_init(&sock->rchildren, 0); #if defined(WIN32) sock->nchildren = 1; #else @@ -403,42 +442,32 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, sock->children = isc_mem_get(mgr->mctx, children_size); memset(sock->children, 0, children_size); - sock->result = ISC_R_DEFAULT; - sock->tid = isc_random_uniform(sock->nchildren); + sock->result = ISC_R_UNSET; + + sock->accept_cb = accept_cb; + sock->accept_cbarg = accept_cbarg; + sock->extrahandlesize = extrahandlesize; + sock->backlog = backlog; + sock->pquota = quota; + + sock->tid = 0; sock->fd = -1; #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) - fd = isc__nm_tcp_lb_socket(sa_family); + fd = isc__nm_tcp_lb_socket(iface->addr.type.sa.sa_family); #endif + isc_barrier_init(&sock->startlistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tcplisten_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + if ((int)i == isc_nm_tid()) { + continue; + } + start_tcp_child(mgr, iface, sock, fd, i); + } - isc__nmsocket_init(csock, mgr, isc_nm_tcpsocket, iface); - csock->parent = sock; - csock->accept_cb = accept_cb; - csock->accept_cbarg = accept_cbarg; - csock->extrahandlesize = extrahandlesize; - csock->backlog = backlog; - csock->tid = i; - /* - * We don't attach to quota, just assign - to avoid - * increasing quota unnecessarily. - */ - csock->pquota = quota; - isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); - -#if HAVE_SO_REUSEPORT_LB || defined(WIN32) - csock->fd = isc__nm_tcp_lb_socket(sa_family); -#else - csock->fd = dup(fd); -#endif - REQUIRE(csock->fd >= 0); - - ievent = isc__nm_get_netievent_tcplisten(mgr, csock); - isc__nm_maybe_enqueue_ievent(&mgr->workers[i], - (isc__netievent_t *)ievent); + if (isc__nm_in_netthread()) { + start_tcp_child(mgr, iface, sock, fd, isc_nm_tid()); } #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) @@ -446,21 +475,21 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, #endif LOCK(&sock->lock); - while (sock->rchildren != sock->nchildren) { + while (atomic_load(&sock->rchildren) != sock->nchildren) { WAIT(&sock->cond, &sock->lock); } result = sock->result; atomic_store(&sock->active, true); - BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); + + INSIST(result != ISC_R_UNSET); if (result == ISC_R_SUCCESS) { - REQUIRE(sock->rchildren == sock->nchildren); + REQUIRE(atomic_load(&sock->rchildren) == sock->nchildren); *sockp = sock; } else { atomic_store(&sock->active, false); - isc__nm_tcp_stoplistening(sock); + enqueue_stoplistening(sock); isc_nmsocket_close(&sock); } @@ -565,16 +594,14 @@ done: sock->pquota = NULL; } - sock->parent->rchildren += 1; - if (sock->parent->result == ISC_R_DEFAULT) { + atomic_fetch_add(&sock->parent->rchildren, 1); + if (sock->parent->result == ISC_R_UNSET) { sock->parent->result = result; } SIGNAL(&sock->parent->cond); - if (!atomic_load(&sock->parent->active)) { - WAIT(&sock->parent->scond, &sock->parent->lock); - } - INSIST(atomic_load(&sock->parent->active)); UNLOCK(&sock->parent->lock); + + isc_barrier_wait(&sock->parent->startlistening); } static void @@ -619,14 +646,6 @@ done: } } -static void -enqueue_stoplistening(isc_nmsocket_t *sock) { - isc__netievent_tcpstop_t *ievent = - isc__nm_get_netievent_tcpstop(sock->mgr, sock); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); -} - void isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -637,7 +656,12 @@ isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) { INSIST(0); ISC_UNREACHABLE(); } - enqueue_stoplistening(sock); + + if (!isc__nm_in_netthread()) { + enqueue_stoplistening(sock); + } else { + stop_tcp_parent(sock); + } } void @@ -1194,8 +1218,6 @@ timer_close_cb(uv_handle_t *handle) { static void stop_tcp_child(isc_nmsocket_t *sock) { - bool last_child = false; - REQUIRE(sock->type == isc_nm_tcpsocket); REQUIRE(sock->tid == isc_nm_tid()); @@ -1206,33 +1228,42 @@ stop_tcp_child(isc_nmsocket_t *sock) { tcp_close_direct(sock); - LOCK(&sock->parent->lock); - sock->parent->rchildren -= 1; - last_child = (sock->parent->rchildren == 0); - UNLOCK(&sock->parent->lock); + atomic_fetch_sub(&sock->parent->rchildren, 1); - if (last_child) { - atomic_store(&sock->parent->closed, true); - isc__nmsocket_prep_destroy(sock->parent); - } + isc_barrier_wait(&sock->parent->stoplistening); } static void stop_tcp_parent(isc_nmsocket_t *sock) { + isc_nmsocket_t *csock = NULL; + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_tcplistener); + isc_barrier_init(&sock->stoplistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tcpstop_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + csock = &sock->children[i]; REQUIRE(VALID_NMSOCK(csock)); - atomic_store(&csock->active, false); + if ((int)i == isc_nm_tid()) { + /* + * We need to schedule closing the other sockets first + */ + continue; + } - ievent = isc__nm_get_netievent_tcpstop(sock->mgr, csock); - isc__nm_enqueue_ievent(&sock->mgr->workers[csock->tid], - (isc__netievent_t *)ievent); + atomic_store(&csock->active, false); + enqueue_stoplistening(csock); } + + csock = &sock->children[isc_nm_tid()]; + atomic_store(&csock->active, false); + stop_tcp_child(csock); + + atomic_store(&sock->closed, true); + isc__nmsocket_prep_destroy(sock); } static void diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index 9d2601b906..0d9bd85f99 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -85,7 +86,7 @@ stop_tcpdns_child(isc_nmsocket_t *sock); static isc_result_t tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; int r; REQUIRE(VALID_NMSOCK(sock)); @@ -269,7 +270,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; - sock->result = ISC_R_DEFAULT; + sock->result = ISC_R_UNSET; atomic_init(&sock->client, true); req = isc__nm_uvreq_get(mgr, sock); @@ -311,7 +312,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, } LOCK(&sock->lock); - while (sock->result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_UNSET) { WAIT(&sock->cond, &sock->lock); } atomic_store(&sock->active, true); @@ -342,6 +343,48 @@ isc__nm_tcpdns_lb_socket(sa_family_t sa_family) { return (sock); } +static void +enqueue_stoplistening(isc_nmsocket_t *sock) { + isc__netievent_tcpdnsstop_t *ievent = + isc__nm_get_netievent_tcpdnsstop(sock->mgr, sock); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + +static void +start_tcpdns_child(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t *sock, + uv_os_sock_t fd, int tid) { + isc__netievent_tcpdnslisten_t *ievent = NULL; + isc_nmsocket_t *csock = &sock->children[tid]; + + isc__nmsocket_init(csock, mgr, isc_nm_tcpdnssocket, iface); + csock->parent = sock; + csock->accept_cb = sock->accept_cb; + csock->accept_cbarg = sock->accept_cbarg; + csock->recv_cb = sock->recv_cb; + csock->recv_cbarg = sock->recv_cbarg; + csock->extrahandlesize = sock->extrahandlesize; + csock->backlog = sock->backlog; + csock->tid = tid; + /* + * We don't attach to quota, just assign - to avoid + * increasing quota unnecessarily. + */ + csock->pquota = sock->pquota; + isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); + +#if HAVE_SO_REUSEPORT_LB || defined(WIN32) + UNUSED(fd); + csock->fd = isc__nm_tcpdns_lb_socket(iface->addr.type.sa.sa_family); +#else + csock->fd = dup(fd); +#endif + REQUIRE(csock->fd >= 0); + + ievent = isc__nm_get_netievent_tcpdnslisten(mgr, csock); + isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], + (isc__netievent_t *)ievent); +} isc_result_t isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t recv_cb, void *recv_cbarg, @@ -350,18 +393,15 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t **sockp) { isc_result_t result = ISC_R_SUCCESS; isc_nmsocket_t *sock = NULL; - sa_family_t sa_family = iface->addr.type.sa.sa_family; size_t children_size = 0; -#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) uv_os_sock_t fd = -1; -#endif REQUIRE(VALID_NM(mgr)); sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tcpdnslistener, iface); - sock->rchildren = 0; + atomic_init(&sock->rchildren, 0); #if defined(WIN32) sock->nchildren = 1; #else @@ -371,44 +411,33 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, sock->children = isc_mem_get(mgr->mctx, children_size); memset(sock->children, 0, children_size); - sock->result = ISC_R_DEFAULT; - sock->tid = isc_random_uniform(sock->nchildren); + sock->result = ISC_R_UNSET; + sock->accept_cb = accept_cb; + sock->accept_cbarg = accept_cbarg; + sock->recv_cb = recv_cb; + sock->recv_cbarg = recv_cbarg; + sock->extrahandlesize = extrahandlesize; + sock->backlog = backlog; + sock->pquota = quota; + + sock->tid = 0; sock->fd = -1; #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) - fd = isc__nm_tcpdns_lb_socket(sa_family); + fd = isc__nm_tcpdns_lb_socket(iface->addr.type.sa.sa_family); #endif + isc_barrier_init(&sock->startlistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tcpdnslisten_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + if ((int)i == isc_nm_tid()) { + continue; + } + start_tcpdns_child(mgr, iface, sock, fd, i); + } - isc__nmsocket_init(csock, mgr, isc_nm_tcpdnssocket, iface); - csock->parent = sock; - csock->accept_cb = accept_cb; - csock->accept_cbarg = accept_cbarg; - csock->recv_cb = recv_cb; - csock->recv_cbarg = recv_cbarg; - csock->extrahandlesize = extrahandlesize; - csock->backlog = backlog; - csock->tid = i; - /* - * We don't attach to quota, just assign - to avoid - * increasing quota unnecessarily. - */ - csock->pquota = quota; - isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); - -#if HAVE_SO_REUSEPORT_LB || defined(WIN32) - csock->fd = isc__nm_tcpdns_lb_socket(sa_family); -#else - csock->fd = dup(fd); -#endif - REQUIRE(csock->fd >= 0); - - ievent = isc__nm_get_netievent_tcpdnslisten(mgr, csock); - isc__nm_maybe_enqueue_ievent(&mgr->workers[i], - (isc__netievent_t *)ievent); + if (isc__nm_in_netthread()) { + start_tcpdns_child(mgr, iface, sock, fd, isc_nm_tid()); } #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) @@ -416,21 +445,21 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, #endif LOCK(&sock->lock); - while (sock->rchildren != sock->nchildren) { + while (atomic_load(&sock->rchildren) != sock->nchildren) { WAIT(&sock->cond, &sock->lock); } result = sock->result; atomic_store(&sock->active, true); - BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); + + INSIST(result != ISC_R_UNSET); if (result == ISC_R_SUCCESS) { - REQUIRE(sock->rchildren == sock->nchildren); + REQUIRE(atomic_load(&sock->rchildren) == sock->nchildren); *sockp = sock; } else { atomic_store(&sock->active, false); - isc__nm_tcpdns_stoplistening(sock); + enqueue_stoplistening(sock); isc_nmsocket_close(&sock); } @@ -446,7 +475,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) { int r; int flags = 0; isc_nmsocket_t *sock = NULL; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; REQUIRE(VALID_NMSOCK(ievent->sock)); REQUIRE(ievent->sock->tid == isc_nm_tid()); @@ -534,16 +563,14 @@ done: sock->pquota = NULL; } - sock->parent->rchildren += 1; - if (sock->parent->result == ISC_R_DEFAULT) { + atomic_fetch_add(&sock->parent->rchildren, 1); + if (sock->parent->result == ISC_R_UNSET) { sock->parent->result = result; } SIGNAL(&sock->parent->cond); - if (!atomic_load(&sock->parent->active)) { - WAIT(&sock->parent->scond, &sock->parent->lock); - } - INSIST(atomic_load(&sock->parent->active)); UNLOCK(&sock->parent->lock); + + isc_barrier_wait(&sock->parent->startlistening); } static void @@ -589,14 +616,6 @@ done: } } -static void -enqueue_stoplistening(isc_nmsocket_t *sock) { - isc__netievent_tcpdnsstop_t *ievent = - isc__nm_get_netievent_tcpdnsstop(sock->mgr, sock); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); -} - void isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -607,7 +626,12 @@ isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) { INSIST(0); ISC_UNREACHABLE(); } - enqueue_stoplistening(sock); + + if (!isc__nm_in_netthread()) { + enqueue_stoplistening(sock); + } else { + stop_tcpdns_parent(sock); + } } void @@ -1224,8 +1248,6 @@ timer_close_cb(uv_handle_t *timer) { static void stop_tcpdns_child(isc_nmsocket_t *sock) { - bool last_child = false; - REQUIRE(sock->type == isc_nm_tcpdnssocket); REQUIRE(sock->tid == isc_nm_tid()); @@ -1236,33 +1258,42 @@ stop_tcpdns_child(isc_nmsocket_t *sock) { tcpdns_close_direct(sock); - LOCK(&sock->parent->lock); - sock->parent->rchildren -= 1; - last_child = (sock->parent->rchildren == 0); - UNLOCK(&sock->parent->lock); + atomic_fetch_sub(&sock->parent->rchildren, 1); - if (last_child) { - atomic_store(&sock->parent->closed, true); - isc__nmsocket_prep_destroy(sock->parent); - } + isc_barrier_wait(&sock->parent->stoplistening); } static void stop_tcpdns_parent(isc_nmsocket_t *sock) { + isc_nmsocket_t *csock = NULL; + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_tcpdnslistener); + isc_barrier_init(&sock->stoplistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tcpdnsstop_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + csock = &sock->children[i]; REQUIRE(VALID_NMSOCK(csock)); - atomic_store(&csock->active, false); + if ((int)i == isc_nm_tid()) { + /* + * We need to schedule closing the other sockets first + */ + continue; + } - ievent = isc__nm_get_netievent_tcpdnsstop(sock->mgr, csock); - isc__nm_enqueue_ievent(&sock->mgr->workers[csock->tid], - (isc__netievent_t *)ievent); + atomic_store(&csock->active, false); + enqueue_stoplistening(csock); } + + csock = &sock->children[isc_nm_tid()]; + atomic_store(&csock->active, false); + stop_tcpdns_child(csock); + + atomic_store(&sock->closed, true); + isc__nmsocket_prep_destroy(sock); } static void diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index bb7ea76a3c..212d81539c 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -97,7 +98,7 @@ can_log_tlsdns_quota(void) { static isc_result_t tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; int r; REQUIRE(VALID_NMSOCK(sock)); @@ -324,7 +325,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; - sock->result = ISC_R_DEFAULT; + sock->result = ISC_R_UNSET; sock->tls.ctx = sslctx; atomic_init(&sock->client, true); atomic_init(&sock->connecting, true); @@ -364,7 +365,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)ievent); } LOCK(&sock->lock); - while (sock->result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_UNSET) { WAIT(&sock->cond, &sock->lock); } atomic_store(&sock->active, true); @@ -407,6 +408,51 @@ isc__nm_tlsdns_lb_socket(sa_family_t sa_family) { return (sock); } +static void +start_tlsdns_child(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t *sock, + uv_os_sock_t fd, int tid) { + isc__netievent_tlsdnslisten_t *ievent = NULL; + isc_nmsocket_t *csock = &sock->children[tid]; + + isc__nmsocket_init(csock, mgr, isc_nm_tlsdnssocket, iface); + csock->parent = sock; + csock->accept_cb = sock->accept_cb; + csock->accept_cbarg = sock->accept_cbarg; + csock->recv_cb = sock->recv_cb; + csock->recv_cbarg = sock->recv_cbarg; + csock->extrahandlesize = sock->extrahandlesize; + csock->backlog = sock->backlog; + csock->tid = tid; + csock->tls.ctx = sock->tls.ctx; + + /* + * We don't attach to quota, just assign - to avoid + * increasing quota unnecessarily. + */ + csock->pquota = sock->pquota; + isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); + +#if HAVE_SO_REUSEPORT_LB || defined(WIN32) + UNUSED(fd); + csock->fd = isc__nm_tlsdns_lb_socket(iface->addr.type.sa.sa_family); +#else + csock->fd = dup(fd); +#endif + REQUIRE(csock->fd >= 0); + + ievent = isc__nm_get_netievent_tlsdnslisten(mgr, csock); + isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], + (isc__netievent_t *)ievent); +} + +static void +enqueue_stoplistening(isc_nmsocket_t *sock) { + isc__netievent_tlsdnsstop_t *ievent = + isc__nm_get_netievent_tlsdnsstop(sock->mgr, sock); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + isc_result_t isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t recv_cb, void *recv_cbarg, @@ -415,18 +461,15 @@ isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp) { isc_result_t result = ISC_R_SUCCESS; isc_nmsocket_t *sock = NULL; - sa_family_t sa_family = iface->addr.type.sa.sa_family; size_t children_size = 0; -#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) uv_os_sock_t fd = -1; -#endif REQUIRE(VALID_NM(mgr)); sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tlsdnslistener, iface); - sock->rchildren = 0; + atomic_init(&sock->rchildren, 0); #if defined(WIN32) sock->nchildren = 1; #else @@ -436,47 +479,35 @@ isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, sock->children = isc_mem_get(mgr->mctx, children_size); memset(sock->children, 0, children_size); - sock->result = ISC_R_DEFAULT; - sock->tid = isc_random_uniform(sock->nchildren); - sock->fd = -1; + sock->result = ISC_R_UNSET; + sock->accept_cb = accept_cb; + sock->accept_cbarg = accept_cbarg; + sock->recv_cb = recv_cb; + sock->recv_cbarg = recv_cbarg; + sock->extrahandlesize = extrahandlesize; + sock->backlog = backlog; + sock->pquota = quota; + sock->tls.ctx = sslctx; + sock->tid = 0; + sock->fd = -1; + #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) - fd = isc__nm_tlsdns_lb_socket(sa_family); + fd = isc__nm_tlsdns_lb_socket(iface->addr.type.sa.sa_family); #endif + isc_barrier_init(&sock->startlistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tlsdnslisten_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + if ((int)i == isc_nm_tid()) { + continue; + } + start_tlsdns_child(mgr, iface, sock, fd, i); + } - isc__nmsocket_init(csock, mgr, isc_nm_tlsdnssocket, iface); - csock->parent = sock; - csock->accept_cb = accept_cb; - csock->accept_cbarg = accept_cbarg; - csock->recv_cb = recv_cb; - csock->recv_cbarg = recv_cbarg; - csock->extrahandlesize = extrahandlesize; - csock->backlog = backlog; - csock->tid = i; - csock->tls.ctx = sslctx; - - /* - * We don't attach to quota, just assign - to avoid - * increasing quota unnecessarily. - */ - csock->pquota = quota; - isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); - -#if HAVE_SO_REUSEPORT_LB || defined(WIN32) - csock->fd = isc__nm_tlsdns_lb_socket(sa_family); -#else - csock->fd = dup(fd); -#endif - REQUIRE(csock->fd >= 0); - - ievent = isc__nm_get_netievent_tlsdnslisten(mgr, csock); - isc__nm_maybe_enqueue_ievent(&mgr->workers[i], - (isc__netievent_t *)ievent); + if (isc__nm_in_netthread()) { + start_tlsdns_child(mgr, iface, sock, fd, isc_nm_tid()); } #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) @@ -484,21 +515,21 @@ isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, #endif LOCK(&sock->lock); - while (sock->rchildren != sock->nchildren) { + while (atomic_load(&sock->rchildren) != sock->nchildren) { WAIT(&sock->cond, &sock->lock); } result = sock->result; atomic_store(&sock->active, true); - BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); + + INSIST(result != ISC_R_UNSET); if (result == ISC_R_SUCCESS) { - REQUIRE(sock->rchildren == sock->nchildren); + REQUIRE(atomic_load(&sock->rchildren) == sock->nchildren); *sockp = sock; } else { atomic_store(&sock->active, false); - isc__nm_tlsdns_stoplistening(sock); + enqueue_stoplistening(sock); isc_nmsocket_close(&sock); } @@ -514,7 +545,7 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) { int r; int flags = 0; isc_nmsocket_t *sock = NULL; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; REQUIRE(VALID_NMSOCK(ievent->sock)); REQUIRE(ievent->sock->tid == isc_nm_tid()); @@ -603,16 +634,14 @@ done: sock->pquota = NULL; } - sock->parent->rchildren += 1; - if (sock->parent->result == ISC_R_DEFAULT) { + atomic_fetch_add(&sock->parent->rchildren, 1); + if (sock->parent->result == ISC_R_UNSET) { sock->parent->result = result; } SIGNAL(&sock->parent->cond); - if (!atomic_load(&sock->parent->active)) { - WAIT(&sock->parent->scond, &sock->parent->lock); - } - INSIST(atomic_load(&sock->parent->active)); UNLOCK(&sock->parent->lock); + + isc_barrier_wait(&sock->parent->startlistening); } static void @@ -658,14 +687,6 @@ done: } } -static void -enqueue_stoplistening(isc_nmsocket_t *sock) { - isc__netievent_tlsdnsstop_t *ievent = - isc__nm_get_netievent_tlsdnsstop(sock->mgr, sock); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); -} - void isc__nm_tlsdns_stoplistening(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -676,7 +697,12 @@ isc__nm_tlsdns_stoplistening(isc_nmsocket_t *sock) { INSIST(0); ISC_UNREACHABLE(); } - enqueue_stoplistening(sock); + + if (!isc__nm_in_netthread()) { + enqueue_stoplistening(sock); + } else { + stop_tlsdns_parent(sock); + } } static void @@ -1770,8 +1796,6 @@ timer_close_cb(uv_handle_t *handle) { static void stop_tlsdns_child(isc_nmsocket_t *sock) { - bool last_child = false; - REQUIRE(sock->type == isc_nm_tlsdnssocket); REQUIRE(sock->tid == isc_nm_tid()); @@ -1782,34 +1806,43 @@ stop_tlsdns_child(isc_nmsocket_t *sock) { tlsdns_close_direct(sock); - LOCK(&sock->parent->lock); - sock->parent->rchildren -= 1; - last_child = (sock->parent->rchildren == 0); - UNLOCK(&sock->parent->lock); + atomic_fetch_sub(&sock->parent->rchildren, 1); - if (last_child) { - atomic_store(&sock->parent->closed, true); - isc__nmsocket_prep_destroy(sock->parent); - } + isc_barrier_wait(&sock->parent->stoplistening); } static void stop_tlsdns_parent(isc_nmsocket_t *sock) { + isc_nmsocket_t *csock = NULL; + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_tlsdnslistener); + isc_barrier_init(&sock->stoplistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_tlsdnsstop_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + csock = &sock->children[i]; REQUIRE(VALID_NMSOCK(csock)); - atomic_store(&csock->active, false); + if ((int)i == isc_nm_tid()) { + /* + * We need to schedule closing the other sockets first + */ + continue; + } - ievent = isc__nm_get_netievent_tlsdnsstop(sock->mgr, csock); - isc__nm_enqueue_ievent(&sock->mgr->workers[csock->tid], - (isc__netievent_t *)ievent); + atomic_store(&csock->active, false); + enqueue_stoplistening(csock); } + + csock = &sock->children[isc_nm_tid()]; + atomic_store(&csock->active, false); + stop_tlsdns_child(csock); + + atomic_store(&sock->closed, true); + isc__nmsocket_prep_destroy(sock); } static void diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index 264ffcde41..ec339a738a 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -621,7 +621,7 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface, tlssock->tlsstream.server_iface = *iface; ISC_LINK_INIT(&tlssock->tlsstream.server_iface.addr, link); tlssock->iface = &tlssock->tlsstream.server_iface; - tlssock->result = ISC_R_DEFAULT; + tlssock->result = ISC_R_UNSET; tlssock->accept_cb = accept_cb; tlssock->accept_cbarg = accept_cbarg; tlssock->extrahandlesize = extrahandlesize; @@ -643,19 +643,12 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface, /* wait for listen result */ isc__nmsocket_attach(tlssock->outer, &tsock); - LOCK(&tlssock->outer->lock); - while (tlssock->outer->rchildren != tlssock->outer->nchildren) { - WAIT(&tlssock->outer->cond, &tlssock->outer->lock); - } - result = tlssock->outer->result; tlssock->result = result; atomic_store(&tlssock->active, true); INSIST(tlssock->outer->tlsstream.tlslistener == NULL); isc__nmsocket_attach(tlssock, &tlssock->outer->tlsstream.tlslistener); - BROADCAST(&tlssock->outer->scond); - UNLOCK(&tlssock->outer->lock); isc__nmsocket_detach(&tsock); - INSIST(result != ISC_R_DEFAULT); + INSIST(result != ISC_R_UNSET); if (result == ISC_R_SUCCESS) { atomic_store(&tlssock->listening, true); @@ -849,6 +842,12 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_tlslistener); + if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, + true)) { + INSIST(0); + ISC_UNREACHABLE(); + } + atomic_store(&sock->listening, false); atomic_store(&sock->closed, true); sock->recv_cb = NULL; @@ -885,7 +884,7 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, ISC_LINK_INIT(&nsock->tlsstream.local_iface.addr, link); nsock->iface = &nsock->tlsstream.local_iface; nsock->extrahandlesize = extrahandlesize; - nsock->result = ISC_R_DEFAULT; + nsock->result = ISC_R_UNSET; nsock->connect_cb = cb; nsock->connect_cbarg = cbarg; nsock->connect_timeout = timeout; diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index ef404d93da..ba61418ce0 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -77,18 +78,52 @@ isc__nm_udp_lb_socket(sa_family_t sa_family) { return (sock); } +static void +start_udp_child(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nmsocket_t *sock, + uv_os_sock_t fd, int tid) { + isc_nmsocket_t *csock; + isc__netievent_udplisten_t *ievent = NULL; + + csock = &sock->children[tid]; + + isc__nmsocket_init(csock, mgr, isc_nm_udpsocket, iface); + csock->parent = sock; + csock->iface = sock->iface; + csock->reading = true; + csock->recv_cb = sock->recv_cb; + csock->recv_cbarg = sock->recv_cbarg; + csock->extrahandlesize = sock->extrahandlesize; + csock->tid = tid; + +#if HAVE_SO_REUSEPORT_LB || defined(WIN32) + UNUSED(fd); + csock->fd = isc__nm_udp_lb_socket(iface->addr.type.sa.sa_family); +#else + csock->fd = dup(fd); +#endif + REQUIRE(csock->fd >= 0); + + ievent = isc__nm_get_netievent_udplisten(mgr, csock); + isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], + (isc__netievent_t *)ievent); +} + +static void +enqueue_stoplistening(isc_nmsocket_t *sock) { + isc__netievent_udpstop_t *ievent = + isc__nm_get_netievent_udpstop(sock->mgr, sock); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + isc_result_t isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, void *cbarg, size_t extrahandlesize, isc_nmsocket_t **sockp) { isc_result_t result = ISC_R_SUCCESS; isc_nmsocket_t *sock = NULL; - sa_family_t sa_family = iface->addr.type.sa.sa_family; size_t children_size = 0; -#if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) - uv_os_sock_t fd = -1; -#endif - REQUIRE(VALID_NM(mgr)); + uv_os_sock_t fd = -1; /* * We are creating mgr->nworkers duplicated sockets, one @@ -97,7 +132,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t)); isc__nmsocket_init(sock, mgr, isc_nm_udplistener, iface); - sock->rchildren = 0; + atomic_init(&sock->rchildren, 0); #if defined(WIN32) sock->nchildren = 1; #else @@ -111,37 +146,26 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, sock->recv_cb = cb; sock->recv_cbarg = cbarg; sock->extrahandlesize = extrahandlesize; - sock->result = ISC_R_DEFAULT; - sock->tid = isc_random_uniform(sock->nchildren); + sock->result = ISC_R_UNSET; + + sock->tid = 0; sock->fd = -1; #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) - fd = isc__nm_udp_lb_socket(sa_family); + fd = isc__nm_udp_lb_socket(iface->addr.type.sa.sa_family); #endif + isc_barrier_init(&sock->startlistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_udplisten_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + if ((int)i == isc_nm_tid()) { + continue; + } + start_udp_child(mgr, iface, sock, fd, i); + } - isc__nmsocket_init(csock, mgr, isc_nm_udpsocket, iface); - csock->parent = sock; - csock->iface = sock->iface; - csock->reading = true; - csock->recv_cb = cb; - csock->recv_cbarg = cbarg; - csock->extrahandlesize = sock->extrahandlesize; - csock->tid = i; - -#if HAVE_SO_REUSEPORT_LB || defined(WIN32) - csock->fd = isc__nm_udp_lb_socket(sa_family); -#else - csock->fd = dup(fd); -#endif - REQUIRE(csock->fd >= 0); - - ievent = isc__nm_get_netievent_udplisten(mgr, csock); - isc__nm_maybe_enqueue_ievent(&mgr->workers[i], - (isc__netievent_t *)ievent); + if (isc__nm_in_netthread()) { + start_udp_child(mgr, iface, sock, fd, isc_nm_tid()); } #if !HAVE_SO_REUSEPORT_LB && !defined(WIN32) @@ -149,21 +173,21 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, #endif LOCK(&sock->lock); - while (sock->rchildren != sock->nchildren) { + while (atomic_load(&sock->rchildren) != sock->nchildren) { WAIT(&sock->cond, &sock->lock); } result = sock->result; atomic_store(&sock->active, true); - BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); + + INSIST(result != ISC_R_UNSET); if (result == ISC_R_SUCCESS) { - REQUIRE(sock->rchildren == sock->nchildren); + REQUIRE(atomic_load(&sock->rchildren) == sock->nchildren); *sockp = sock; } else { atomic_store(&sock->active, false); - isc__nm_udp_stoplistening(sock); + enqueue_stoplistening(sock); isc_nmsocket_close(&sock); } @@ -181,7 +205,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) { int r, uv_bind_flags = 0; int uv_init_flags = 0; sa_family_t sa_family; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; REQUIRE(VALID_NMSOCK(ievent->sock)); REQUIRE(ievent->sock->tid == isc_nm_tid()); @@ -269,24 +293,14 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) { done: result = isc__nm_uverr2result(r); - sock->parent->rchildren += 1; - if (sock->parent->result == ISC_R_DEFAULT) { + atomic_fetch_add(&sock->parent->rchildren, 1); + if (sock->parent->result == ISC_R_UNSET) { sock->parent->result = result; } SIGNAL(&sock->parent->cond); - if (!atomic_load(&sock->parent->active)) { - WAIT(&sock->parent->scond, &sock->parent->lock); - } - INSIST(atomic_load(&sock->parent->active)); UNLOCK(&sock->parent->lock); -} -static void -enqueue_stoplistening(isc_nmsocket_t *sock) { - isc__netievent_udpstop_t *ievent = - isc__nm_get_netievent_udpstop(sock->mgr, sock); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); + isc_barrier_wait(&sock->parent->startlistening); } void @@ -300,7 +314,11 @@ isc__nm_udp_stoplistening(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } - enqueue_stoplistening(sock); + if (!isc__nm_in_netthread()) { + enqueue_stoplistening(sock); + } else { + stop_udp_parent(sock); + } } /* @@ -321,9 +339,6 @@ isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0) { return; } - /* - * If network manager is paused, re-enqueue the event for later. - */ stop_udp_parent(sock); } @@ -590,7 +605,7 @@ static isc_result_t udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; int uv_bind_flags = UV_UDP_REUSEADDR; - isc_result_t result = ISC_R_DEFAULT; + isc_result_t result = ISC_R_UNSET; int tries = 3; int r; @@ -690,7 +705,6 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->parent == NULL); REQUIRE(sock->tid == isc_nm_tid()); - req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr); result = udp_connect_direct(sock, req); if (result != ISC_R_SUCCESS) { atomic_store(&sock->active, false); @@ -734,7 +748,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->read_timeout = timeout; sock->extrahandlesize = extrahandlesize; sock->peer = peer->addr; - sock->result = ISC_R_DEFAULT; + sock->result = ISC_R_UNSET; atomic_init(&sock->client, true); req = isc__nm_uvreq_get(mgr, sock); @@ -742,6 +756,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, req->cbarg = cbarg; req->peer = peer->addr; req->local = local->addr; + req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr); result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &sock->fd); if (result != ISC_R_SUCCESS) { @@ -782,7 +797,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)event); } LOCK(&sock->lock); - while (sock->result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_UNSET) { WAIT(&sock->cond, &sock->lock); } atomic_store(&sock->active, true); @@ -970,8 +985,6 @@ stop_udp_child(isc_nmsocket_t *sock) { REQUIRE(sock->type == isc_nm_udpsocket); REQUIRE(sock->tid == isc_nm_tid()); - bool last_child = false; - if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, true)) { return; @@ -979,33 +992,42 @@ stop_udp_child(isc_nmsocket_t *sock) { udp_close_direct(sock); - LOCK(&sock->parent->lock); - sock->parent->rchildren -= 1; - last_child = (sock->parent->rchildren == 0); - UNLOCK(&sock->parent->lock); + atomic_fetch_sub(&sock->parent->rchildren, 1); - if (last_child) { - atomic_store(&sock->parent->closed, true); - isc__nmsocket_prep_destroy(sock->parent); - } + isc_barrier_wait(&sock->parent->stoplistening); } static void stop_udp_parent(isc_nmsocket_t *sock) { + isc_nmsocket_t *csock = NULL; + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_udplistener); + isc_barrier_init(&sock->stoplistening, sock->nchildren); + for (size_t i = 0; i < sock->nchildren; i++) { - isc__netievent_udpstop_t *ievent = NULL; - isc_nmsocket_t *csock = &sock->children[i]; + csock = &sock->children[i]; REQUIRE(VALID_NMSOCK(csock)); - atomic_store(&csock->active, false); + if ((int)i == isc_nm_tid()) { + /* + * We need to schedule closing the other sockets first + */ + continue; + } - ievent = isc__nm_get_netievent_udpstop(sock->mgr, csock); - isc__nm_enqueue_ievent(&sock->mgr->workers[i], - (isc__netievent_t *)ievent); + atomic_store(&csock->active, false); + enqueue_stoplistening(csock); } + + csock = &sock->children[isc_nm_tid()]; + atomic_store(&csock->active, false); + stop_udp_child(csock); + + atomic_store(&sock->closed, true); + isc__nmsocket_prep_destroy(sock); } static void diff --git a/lib/isc/netmgr_p.h b/lib/isc/netmgr_p.h new file mode 100644 index 0000000000..8f33c84160 --- /dev/null +++ b/lib/isc/netmgr_p.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include + +void +isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netgmrp); +/*%< + * Creates a new network manager with 'workers' worker threads, + * and starts it running. + */ + +void +isc__netmgr_destroy(isc_nm_t **netmgrp); +/*%< + * Similar to isc_nm_detach(), but actively waits for all other references + * to be gone before returning. + */ + +void +isc__netmgr_shutdown(isc_nm_t *mgr); +/*%< + * Shut down all active connections, freeing associated resources; + * prevent new connections from being established. + */ diff --git a/lib/isc/socket_p.h b/lib/isc/socket_p.h new file mode 100644 index 0000000000..2ac133fd13 --- /dev/null +++ b/lib/isc/socket_p.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks, int nthreads); +/*%< + * Create a socket manager. If "maxsocks" is non-zero, it specifies the + * maximum number of sockets that the created manager should handle. + * + * Notes: + * + *\li All memory will be allocated in memory context 'mctx'. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'managerp' points to a NULL isc_socketmgr_t. + * + * Ensures: + * + *\li '*managerp' is a valid isc_socketmgr_t. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + *\li #ISC_R_NOTIMPLEMENTED + */ + +void +isc__socketmgr_destroy(isc_socketmgr_t **managerp); +/*%< + * Destroy a socket manager. + * + * Notes: + * + *\li This routine blocks until there are no sockets left in the manager, + * so if the caller holds any socket references using the manager, it + * must detach them before calling isc_socketmgr_destroy() or it will + * block forever. + * + * Requires: + * + *\li '*managerp' is a valid isc_socketmgr_t. + * + *\li All sockets managed by this manager are fully detached. + * + * Ensures: + * + *\li *managerp == NULL + * + *\li All resources used by the manager have been freed. + */ + +#if !WIN32 + +#include + +typedef struct isc_socketwait isc_socketwait_t; +int +isc__socketmgr_waitevents(isc_socketmgr_t *, struct timeval *, + isc_socketwait_t **); +isc_result_t +isc__socketmgr_dispatch(isc_socketmgr_t *, isc_socketwait_t *); + +#endif diff --git a/lib/isc/task.c b/lib/isc/task.c index b8996a7f0e..9849faeafc 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -44,9 +45,7 @@ #include #endif /* HAVE_JSON_C */ -#ifdef OPENSSL_LEAKS -#include -#endif /* ifdef OPENSSL_LEAKS */ +#include "task_p.h" /* * Task manager is built around 'as little locking as possible' concept. @@ -104,6 +103,7 @@ struct isc_task { task_state_t state; int pause_cnt; isc_refcount_t references; + isc_refcount_t running; isc_eventlist_t events; isc_eventlist_t on_shutdown; unsigned int nevents; @@ -114,21 +114,14 @@ struct isc_task { void *tag; bool bound; /* Protected by atomics */ - atomic_uint_fast32_t flags; + atomic_bool shuttingdown; + atomic_bool privileged; /* Locked by task manager lock. */ LINK(isc_task_t) link; }; -#define TASK_F_SHUTTINGDOWN 0x01 -#define TASK_F_PRIVILEGED 0x02 - -#define TASK_SHUTTINGDOWN(t) \ - ((atomic_load_acquire(&(t)->flags) & TASK_F_SHUTTINGDOWN) != 0) -#define TASK_PRIVILEGED(t) \ - ((atomic_load_acquire(&(t)->flags) & TASK_F_PRIVILEGED) != 0) - -#define TASK_FLAG_SET(t, f) atomic_fetch_or_release(&(t)->flags, (f)) -#define TASK_FLAG_CLR(t, f) atomic_fetch_and_release(&(t)->flags, ~(f)) +#define TASK_SHUTTINGDOWN(t) (atomic_load_acquire(&(t)->shuttingdown)) +#define TASK_PRIVILEGED(t) (atomic_load_acquire(&(t)->privileged)) #define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M') #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC) @@ -139,20 +132,16 @@ struct isc_taskmgr { isc_refcount_t references; isc_mem_t *mctx; isc_mutex_t lock; - atomic_uint_fast32_t tasks_running; - atomic_uint_fast32_t tasks_ready; atomic_uint_fast32_t tasks_count; - isc_nm_t *nm; + isc_nm_t *netmgr; /* Locked by task manager lock. */ unsigned int default_quantum; LIST(isc_task_t) tasks; + atomic_uint_fast32_t mode; atomic_bool exclusive_req; atomic_bool exiting; - /* Locked by halt_lock */ - unsigned int halted; - /* * Multiple threads can read/write 'excl' at the same time, so we need * to protect the access. We can't use 'lock' since isc_task_detach() @@ -163,9 +152,6 @@ struct isc_taskmgr { }; #define DEFAULT_DEFAULT_QUANTUM 25 -#define FINISHED(m) \ - (atomic_load_relaxed(&((m)->exiting)) && \ - atomic_load(&(m)->tasks_count) == 0) /*% * The following are intended for internal use (indicated by "isc__" @@ -195,6 +181,7 @@ task_finished(isc_task_t *task) { XTRACE("task_finished"); + isc_refcount_destroy(&task->running); isc_refcount_destroy(&task->references); LOCK(&manager->lock); @@ -253,11 +240,13 @@ isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum, task->pause_cnt = 0; isc_refcount_init(&task->references, 1); + isc_refcount_init(&task->running, 0); INIT_LIST(task->events); INIT_LIST(task->on_shutdown); task->nevents = 0; task->quantum = (quantum > 0) ? quantum : manager->default_quantum; - atomic_init(&task->flags, 0); + atomic_init(&task->shuttingdown, false); + atomic_init(&task->privileged, false); task->now = 0; isc_time_settoepoch(&task->tnow); memset(task->name, 0, sizeof(task->name)); @@ -313,9 +302,9 @@ task_shutdown(isc_task_t *task) { XTRACE("task_shutdown"); - if (!TASK_SHUTTINGDOWN(task)) { + if (atomic_compare_exchange_strong(&task->shuttingdown, + &(bool){ false }, true)) { XTRACE("shutting down"); - TASK_FLAG_SET(task, TASK_F_SHUTTINGDOWN); if (task->state == task_state_idle) { INSIST(EMPTY(task->events)); task->state = task_state_ready; @@ -352,7 +341,14 @@ task_ready(isc_task_t *task) { REQUIRE(VALID_MANAGER(manager)); XTRACE("task_ready"); - isc_nm_task_enqueue(manager->nm, task, task->threadid); + + isc_refcount_increment0(&task->running); + isc_nm_task_enqueue(manager->netmgr, task, task->threadid); +} + +void +isc_task_ready(isc_task_t *task) { + task_ready(task); } static inline bool @@ -822,8 +818,7 @@ task_run(isc_task_t *task) { * and task lock to avoid deadlocks, just bail then. */ if (task->state != task_state_ready) { - UNLOCK(&task->lock); - return (ISC_R_SUCCESS); + goto done; } INSIST(task->state == task_state_ready); @@ -888,7 +883,6 @@ task_run(isc_task_t *task) { * The task is done. */ XTRACE("done"); - finished = true; task->state = task_state_done; } else { if (task->state == task_state_running) { @@ -922,6 +916,13 @@ task_run(isc_task_t *task) { break; } } + +done: + if (isc_refcount_decrement(&task->running) == 1 && + task->state == task_state_done) + { + finished = true; + } UNLOCK(&task->lock); if (finished) { @@ -939,7 +940,7 @@ isc_task_run(isc_task_t *task) { static void manager_free(isc_taskmgr_t *manager) { isc_refcount_destroy(&manager->references); - isc_nm_detach(&manager->nm); + isc_nm_detach(&manager->netmgr); isc_mutex_destroy(&manager->lock); isc_mutex_destroy(&manager->excl_lock); @@ -967,8 +968,8 @@ isc_taskmgr_detach(isc_taskmgr_t *manager) { } isc_result_t -isc_taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, - isc_taskmgr_t **managerp) { +isc__taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, + isc_taskmgr_t **managerp) { isc_taskmgr_t *manager; /* @@ -990,14 +991,12 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, manager->default_quantum = default_quantum; if (nm != NULL) { - isc_nm_attach(nm, &manager->nm); + isc_nm_attach(nm, &manager->netmgr); } INIT_LIST(manager->tasks); - atomic_init(&manager->tasks_count, 0); - atomic_init(&manager->tasks_running, 0); - atomic_init(&manager->tasks_ready, 0); atomic_init(&manager->exiting, false); + atomic_init(&manager->mode, isc_taskmgrmode_normal); atomic_store_relaxed(&manager->exclusive_req, false); isc_mem_attach(mctx, &manager->mctx); @@ -1010,19 +1009,12 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, } void -isc_taskmgr_destroy(isc_taskmgr_t **managerp) { - isc_taskmgr_t *manager; +isc__taskmgr_shutdown(isc_taskmgr_t *manager) { isc_task_t *task; - /* - * Destroy '*managerp'. - */ - - REQUIRE(managerp != NULL); - manager = *managerp; REQUIRE(VALID_MANAGER(manager)); - XTHREADTRACE("isc_taskmgr_destroy"); + XTHREADTRACE("isc_taskmgr_shutdown"); /* * Only one non-worker thread may ever call this routine. * If a worker thread wants to initiate shutdown of the @@ -1072,16 +1064,39 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) { } UNLOCK(&manager->lock); +} - isc_taskmgr_detach(manager); +void +isc__taskmgr_destroy(isc_taskmgr_t **managerp) { + REQUIRE(managerp != NULL && VALID_MANAGER(*managerp)); + isc_taskmgr_t *manager = *managerp; *managerp = NULL; + + XTHREADTRACE("isc_taskmgr_destroy"); + +#ifdef ISC_TASK_TRACE + int counter = 0; + while (isc_refcount_current(&manager->references) > 1 && + counter++ < 1000) { + usleep(10 * 1000); + } +#else + while (isc_refcount_current(&manager->references) > 1) { + usleep(10 * 1000); + } +#endif + + REQUIRE(isc_refcount_decrement(&manager->references) == 1); + manager_free(manager); } void isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task) { REQUIRE(VALID_MANAGER(mgr)); REQUIRE(VALID_TASK(task)); + REQUIRE(task->threadid == 0); + LOCK(&mgr->excl_lock); if (mgr->excl != NULL) { isc_task_detach(&mgr->excl); @@ -1130,7 +1145,7 @@ isc_task_beginexclusive(isc_task_t *task) { return (ISC_R_LOCKBUSY); } - isc_nm_pause(manager->nm); + isc_nm_pause(manager->netmgr); return (ISC_R_SUCCESS); } @@ -1143,7 +1158,7 @@ isc_task_endexclusive(isc_task_t *task) { REQUIRE(task->state == task_state_running); manager = task->manager; - isc_nm_resume(manager->nm); + isc_nm_resume(manager->netmgr); REQUIRE(atomic_compare_exchange_strong(&manager->exclusive_req, &(bool){ true }, false)); } @@ -1207,32 +1222,37 @@ isc_task_unpause(isc_task_t *task) { } } +void +isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode) { + atomic_store(&manager->mode, mode); +} + +isc_taskmgrmode_t +isc_taskmgr_mode(isc_taskmgr_t *manager) { + return (atomic_load(&manager->mode)); +} + void isc_task_setprivilege(isc_task_t *task, bool priv) { REQUIRE(VALID_TASK(task)); - uint_fast32_t oldflags, newflags; - oldflags = atomic_load_acquire(&task->flags); - do { - if (priv) { - newflags = oldflags | TASK_F_PRIVILEGED; - } else { - newflags = oldflags & ~TASK_F_PRIVILEGED; - } - if (newflags == oldflags) { - return; - } - } while (!atomic_compare_exchange_weak_acq_rel(&task->flags, &oldflags, - newflags)); + atomic_store_release(&task->privileged, priv); } bool -isc_task_privilege(isc_task_t *task) { +isc_task_getprivilege(isc_task_t *task) { REQUIRE(VALID_TASK(task)); return (TASK_PRIVILEGED(task)); } +bool +isc_task_privileged(isc_task_t *task) { + REQUIRE(VALID_TASK(task)); + + return (isc_taskmgr_mode(task->manager) && TASK_PRIVILEGED(task)); +} + bool isc_task_exiting(isc_task_t *task) { REQUIRE(VALID_TASK(task)); @@ -1269,21 +1289,6 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr, void *writer0) { mgr->default_quantum)); TRY0(xmlTextWriterEndElement(writer)); /* default-quantum */ - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-count")); - TRY0(xmlTextWriterWriteFormatString( - writer, "%d", (int)atomic_load_relaxed(&mgr->tasks_count))); - TRY0(xmlTextWriterEndElement(writer)); /* tasks-count */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running")); - TRY0(xmlTextWriterWriteFormatString( - writer, "%d", (int)atomic_load_relaxed(&mgr->tasks_running))); - TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */ - - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready")); - TRY0(xmlTextWriterWriteFormatString( - writer, "%d", (int)atomic_load_relaxed(&mgr->tasks_ready))); - TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */ - TRY0(xmlTextWriterEndElement(writer)); /* thread-model */ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks")); @@ -1373,18 +1378,6 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr, void *tasks0) { CHECKMEM(obj); json_object_object_add(tasks, "default-quantum", obj); - obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_count)); - CHECKMEM(obj); - json_object_object_add(tasks, "tasks-count", obj); - - obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_running)); - CHECKMEM(obj); - json_object_object_add(tasks, "tasks-running", obj); - - obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_ready)); - CHECKMEM(obj); - json_object_object_add(tasks, "tasks-ready", obj); - array = json_object_new_array(); CHECKMEM(array); diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h new file mode 100644 index 0000000000..4dda7d63ba --- /dev/null +++ b/lib/isc/task_p.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include +#include + +isc_result_t +isc__taskmgr_create(isc_mem_t *mctx, unsigned int default_quantum, isc_nm_t *nm, + isc_taskmgr_t **managerp); +/*%< + * Create a new task manager. + * + * Notes: + * + *\li If 'default_quantum' is non-zero, then it will be used as the default + * quantum value when tasks are created. If zero, then an implementation + * defined default quantum will be used. + * + *\li If 'nm' is set then netmgr is paused when an exclusive task mode + * is requested. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li managerp != NULL && *managerp == NULL + * + * Ensures: + * + *\li On success, '*managerp' will be attached to the newly created task + * manager. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NOTHREADS No threads could be created. + *\li #ISC_R_UNEXPECTED An unexpected error occurred. + *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task + * manager shutting down. + */ + +void +isc__taskmgr_destroy(isc_taskmgr_t **managerp); +/*%< + * Destroy '*managerp'. + * + * Notes: + * + *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by + * *managerp that haven't already been shutdown. The call will block + * until all tasks have entered the done state. + * + *\li isc_taskmgr_destroy() must not be called by a task event action, + * because it would block forever waiting for the event action to + * complete. An event action that wants to cause task manager shutdown + * should request some non-event action thread of execution to do the + * shutdown, e.g. by signaling a condition variable or using + * isc_app_shutdown(). + * + *\li Task manager references are not reference counted, so the caller + * must ensure that no attempt will be made to use the manager after + * isc_taskmgr_destroy() returns. + * + * Requires: + * + *\li '*managerp' is a valid task manager. + * + *\li 'isc__taskmgr_shutdown()' and isc__netmgr_shutdown() have been + * called. + */ + +void +isc__taskmgr_shutdown(isc_taskmgr_t *manager); +/*%> + * Shutdown 'manager'. + * + * Notes: + * + *\li Calling isc__taskmgr_shutdown() will shut down all tasks managed by + * *managerp that haven't already been shut down. + * + * Requires: + * + *\li 'manager' is a valid task manager. + * + *\li isc_taskmgr_destroy() has not be called previously on '*managerp'. + * + * Ensures: + * + *\li All resources used by the task manager, and any tasks it managed, + * have been freed. + */ diff --git a/lib/isc/tests/Makefile.am b/lib/isc/tests/Makefile.am index 1cee32d754..c8da51d3ee 100644 --- a/lib/isc/tests/Makefile.am +++ b/lib/isc/tests/Makefile.am @@ -10,7 +10,7 @@ LDADD += \ check_LTLIBRARIES = libisctest.la libisctest_la_SOURCES = \ - ../unix/socket_p.h \ + ../socket_p.h \ isctest.c \ isctest.h \ uv_wrap.h diff --git a/lib/isc/tests/doh_test.c b/lib/isc/tests/doh_test.c index a0a93584d2..1fa9d51fd3 100644 --- a/lib/isc/tests/doh_test.c +++ b/lib/isc/tests/doh_test.c @@ -43,6 +43,7 @@ #include "../netmgr/netmgr-int.h" #include "../netmgr/uv-compat.c" #include "../netmgr/uv-compat.h" +#include "../netmgr_p.h" #include "isctest.h" #define MAX_NM 2 @@ -319,7 +320,7 @@ nm_setup(void **state) { nm = isc_mem_get(test_mctx, MAX_NM * sizeof(nm[0])); for (size_t i = 0; i < MAX_NM; i++) { - nm[i] = isc_nm_start(test_mctx, nworkers); + isc__netmgr_create(test_mctx, nworkers, &nm[i]); assert_non_null(nm[i]); } @@ -339,7 +340,7 @@ nm_teardown(void **state) { isc_nm_t **nm = (isc_nm_t **)*state; for (size_t i = 0; i < MAX_NM; i++) { - isc_nm_destroy(&nm[i]); + isc__netmgr_destroy(&nm[i]); assert_null(nm[i]); } isc_mem_put(test_mctx, nm, MAX_NM * sizeof(nm[0])); @@ -498,7 +499,7 @@ doh_noop(void **state) { .length = send_msg.len }, noop_read_cb, NULL, atomic_load(&use_TLS), 30000); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); assert_int_equal(0, atomic_load(&csends)); assert_int_equal(0, atomic_load(&creads)); @@ -545,7 +546,7 @@ doh_noresponse(void **state) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -666,7 +667,7 @@ doh_timeout_recovery(void **state) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -792,7 +793,7 @@ doh_recv_one(void **state) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(csends); X(creads); @@ -913,7 +914,7 @@ doh_recv_two(void **state) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(csends); X(creads); @@ -979,7 +980,7 @@ doh_recv_send(void **state) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -1050,7 +1051,7 @@ doh_recv_half_send(void **state) { isc_thread_yield(); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); for (size_t i = 0; i < nthreads; i++) { isc_thread_join(threads[i], NULL); @@ -1134,7 +1135,7 @@ doh_half_recv_send(void **state) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(csends); X(creads); @@ -1202,7 +1203,7 @@ doh_half_recv_half_send(void **state) { isc_thread_yield(); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); diff --git a/lib/isc/tests/isctest.c b/lib/isc/tests/isctest.c index c9b6b6929f..6975501ef7 100644 --- a/lib/isc/tests/isctest.c +++ b/lib/isc/tests/isctest.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -58,18 +59,10 @@ cleanup_managers(void) { isc_task_shutdown(maintask); isc_task_destroy(&maintask); } - if (socketmgr != NULL) { - isc_socketmgr_destroy(&socketmgr); - } - if (taskmgr != NULL) { - isc_taskmgr_destroy(&taskmgr); - } - if (netmgr != NULL) { - isc_nm_destroy(&netmgr); - } - if (timermgr != NULL) { - isc_timermgr_destroy(&timermgr); - } + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, + taskmgr == NULL ? NULL : &taskmgr, + timermgr == NULL ? NULL : &timermgr, + socketmgr == NULL ? NULL : &socketmgr); } static isc_result_t @@ -87,14 +80,12 @@ create_managers(unsigned int workers) { INSIST(workers != 0); isc_hp_init(6 * workers); + isc_managers_create(test_mctx, workers, 0, 0, &netmgr, &taskmgr, + &timermgr, &socketmgr); - netmgr = isc_nm_start(test_mctx, workers); - CHECK(isc_taskmgr_create(test_mctx, 0, netmgr, &taskmgr)); - CHECK(isc_task_create(taskmgr, 0, &maintask)); + CHECK(isc_task_create_bound(taskmgr, 0, &maintask, 0)); isc_taskmgr_setexcltask(taskmgr, maintask); - CHECK(isc_timermgr_create(test_mctx, &timermgr)); - CHECK(isc_socketmgr_create(test_mctx, &socketmgr)); return (ISC_R_SUCCESS); cleanup: @@ -150,9 +141,6 @@ isc_test_end(void) { if (maintask != NULL) { isc_task_detach(&maintask); } - if (taskmgr != NULL) { - isc_taskmgr_destroy(&taskmgr); - } cleanup_managers(); diff --git a/lib/isc/tests/netmgr_test.c b/lib/isc/tests/netmgr_test.c index d062dbb799..2a1516bffc 100644 --- a/lib/isc/tests/netmgr_test.c +++ b/lib/isc/tests/netmgr_test.c @@ -37,6 +37,7 @@ #include "../netmgr/udp.c" #include "../netmgr/uv-compat.c" #include "../netmgr/uv-compat.h" +#include "../netmgr_p.h" #include "isctest.h" typedef void (*stream_connect_function)(isc_nm_t *nm); @@ -335,12 +336,12 @@ nm_setup(void **state __attribute__((unused))) { return (-1); } - listen_nm = isc_nm_start(test_mctx, workers); + isc__netmgr_create(test_mctx, workers, &listen_nm); assert_non_null(listen_nm); isc_nm_settimeouts(listen_nm, T_INIT, T_IDLE, T_KEEPALIVE, T_ADVERTISED); - connect_nm = isc_nm_start(test_mctx, workers); + isc__netmgr_create(test_mctx, workers, &connect_nm); assert_non_null(connect_nm); isc_nm_settimeouts(connect_nm, T_INIT, T_IDLE, T_KEEPALIVE, T_ADVERTISED); @@ -358,10 +359,10 @@ static int nm_teardown(void **state __attribute__((unused))) { UNUSED(state); - isc_nm_destroy(&connect_nm); + isc__netmgr_destroy(&connect_nm); assert_null(connect_nm); - isc_nm_destroy(&listen_nm); + isc__netmgr_destroy(&listen_nm); assert_null(listen_nm); WAIT_FOR_EQ(active_cconnects, 0); @@ -677,7 +678,7 @@ mock_udpconnect_uv_udp_open(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); RESET_RETURN; } @@ -691,7 +692,7 @@ mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); RESET_RETURN; } @@ -706,7 +707,7 @@ mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); RESET_RETURN; } @@ -721,7 +722,7 @@ mock_udpconnect_uv_recv_buffer_size(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); RESET_RETURN; } @@ -735,7 +736,7 @@ mock_udpconnect_uv_send_buffer_size(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); RESET_RETURN; } @@ -758,7 +759,7 @@ udp_noop(void **state __attribute__((unused))) { isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); atomic_assert_int_eq(cconnects, 0); atomic_assert_int_eq(csends, 0); @@ -787,7 +788,7 @@ udp_noresponse(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -860,7 +861,7 @@ udp_timeout_recovery(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -889,7 +890,7 @@ udp_recv_one(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -937,7 +938,7 @@ udp_recv_two(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -980,7 +981,7 @@ udp_recv_send(void **state __attribute__((unused))) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -1020,7 +1021,7 @@ udp_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -1073,7 +1074,7 @@ udp_half_recv_send(void **state __attribute__((unused))) { /* Try to send a little while longer */ isc_test_nap((esends / 2) * 10000); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -1115,7 +1116,7 @@ udp_half_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -1218,7 +1219,7 @@ stream_noop(void **state __attribute__((unused))) { connect_readcb = NULL; isc_refcount_increment0(&active_cconnects); stream_connect(connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); atomic_assert_int_eq(cconnects, 0); atomic_assert_int_eq(csends, 0); @@ -1244,7 +1245,7 @@ stream_noresponse(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1294,7 +1295,7 @@ stream_timeout_recovery(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -1322,7 +1323,7 @@ stream_recv_one(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1367,7 +1368,7 @@ stream_recv_two(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1416,7 +1417,7 @@ stream_recv_send(void **state __attribute__((unused))) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -1462,7 +1463,7 @@ stream_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -1521,7 +1522,7 @@ stream_half_recv_send(void **state __attribute__((unused))) { /* Try to send a little while longer */ isc_test_nap((esends / 2) * 10000); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -1569,7 +1570,7 @@ stream_half_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -1767,7 +1768,7 @@ tcpdns_noop(void **state __attribute__((unused))) { isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL, T_CONNECT, 0); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); atomic_assert_int_eq(cconnects, 0); atomic_assert_int_eq(csends, 0); @@ -1801,7 +1802,7 @@ tcpdns_noresponse(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1856,7 +1857,7 @@ tcpdns_timeout_recovery(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -1886,7 +1887,7 @@ tcpdns_recv_one(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1936,7 +1937,7 @@ tcpdns_recv_two(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -1980,7 +1981,7 @@ tcpdns_recv_send(void **state __attribute__((unused))) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -2021,7 +2022,7 @@ tcpdns_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -2075,7 +2076,7 @@ tcpdns_half_recv_send(void **state __attribute__((unused))) { /* Try to send a little while longer */ isc_test_nap((esends / 2) * 10000); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -2118,7 +2119,7 @@ tcpdns_half_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -2355,7 +2356,7 @@ tlsdns_noop(void **state __attribute__((unused))) { connect_connect_cb, NULL, T_CONNECT, 0, tcp_connect_tlsctx); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); atomic_assert_int_eq(cconnects, 0); atomic_assert_int_eq(csends, 0); @@ -2391,7 +2392,7 @@ tlsdns_noresponse(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -2452,7 +2453,7 @@ tlsdns_timeout_recovery(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); } static void @@ -2484,7 +2485,7 @@ tlsdns_recv_one(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -2537,7 +2538,7 @@ tlsdns_recv_two(void **state __attribute__((unused))) { isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); X(cconnects); X(csends); @@ -2582,7 +2583,7 @@ tlsdns_recv_send(void **state __attribute__((unused))) { isc_thread_join(threads[i], NULL); } - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -2624,7 +2625,7 @@ tlsdns_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -2679,7 +2680,7 @@ tlsdns_half_recv_send(void **state __attribute__((unused))) { /* Try to send a little while longer */ isc_test_nap((esends / 2) * 10000); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); DONE(); for (size_t i = 0; i < workers; i++) { @@ -2723,7 +2724,7 @@ tlsdns_half_recv_half_send(void **state __attribute__((unused))) { WAIT_FOR_GE(ssends, esends / 2); WAIT_FOR_GE(creads, esends / 2); - isc_nm_closedown(connect_nm); + isc__netmgr_shutdown(connect_nm); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c index 47e98a7b46..28a436b7d2 100644 --- a/lib/isc/tests/socket_test.c +++ b/lib/isc/tests/socket_test.c @@ -12,6 +12,7 @@ /*! \file */ #if HAVE_CMOCKA +#include #include /* IWYU pragma: keep */ #include #include @@ -30,7 +31,7 @@ #include #include -#include "../unix/socket_p.h" +#include "../socket_p.h" #include "isctest.h" static bool recv_dscp; @@ -79,14 +80,14 @@ _teardown(void **state) { typedef struct { atomic_bool done; + atomic_uintptr_t socket; isc_result_t result; - isc_socket_t *socket; } completion_t; static void completion_init(completion_t *completion) { atomic_init(&completion->done, false); - completion->socket = NULL; + atomic_init(&completion->socket, (uintptr_t)NULL); } static void @@ -99,7 +100,7 @@ accept_done(isc_task_t *task, isc_event_t *event) { completion->result = nevent->result; atomic_store(&completion->done, true); if (completion->result == ISC_R_SUCCESS) { - completion->socket = nevent->newsocket; + atomic_store(&completion->socket, (uintptr_t)nevent->newsocket); } isc_event_free(&event); @@ -136,35 +137,24 @@ event_done(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); } -static isc_result_t +static void waitfor(completion_t *completion) { int i = 0; while (!atomic_load(&completion->done) && i++ < 5000) { - isc_test_nap(1000); + isc_test_nap(10000); } - if (atomic_load(&completion->done)) { - return (ISC_R_SUCCESS); - } - return (ISC_R_FAILURE); + assert_true(atomic_load(&completion->done)); } static void -waitbody(void) { - isc_test_nap(1000); -} - -static isc_result_t waitfor2(completion_t *c1, completion_t *c2) { int i = 0; while (!(atomic_load(&c1->done) && atomic_load(&c2->done)) && i++ < 5000) { - waitbody(); + isc_test_nap(10000); } - if (atomic_load(&c1->done) && atomic_load(&c2->done)) { - return (ISC_R_SUCCESS); - } - return (ISC_R_FAILURE); + assert_true(atomic_load(&c1->done) && atomic_load(&c2->done)); } /* @@ -525,7 +515,7 @@ tcp_dscp_v4_test(void **state) { assert_int_equal(completion.result, ISC_R_SUCCESS); assert_true(atomic_load(&completion2.done)); assert_int_equal(completion2.result, ISC_R_SUCCESS); - s3 = completion2.socket; + s3 = (isc_socket_t *)atomic_load(&completion2.socket); isc_socket_dscp(s2, 056); /* EF */ @@ -613,7 +603,7 @@ tcp_dscp_v6_test(void **state) { assert_int_equal(completion.result, ISC_R_SUCCESS); assert_true(atomic_load(&completion2.done)); assert_int_equal(completion2.result, ISC_R_SUCCESS); - s3 = completion2.socket; + s3 = (isc_socket_t *)atomic_load(&completion2.socket); isc_socket_dscp(s2, 056); /* EF */ diff --git a/lib/isc/tests/task_test.c b/lib/isc/tests/task_test.c index f6b40f203d..b47770bfff 100644 --- a/lib/isc/tests/task_test.c +++ b/lib/isc/tests/task_test.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -215,18 +216,19 @@ privileged_events(void **state) { * queue without things happening while we do it. */ isc_nm_pause(netmgr); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); result = isc_task_create(taskmgr, 0, &task1); assert_int_equal(result, ISC_R_SUCCESS); isc_task_setname(task1, "privileged", NULL); - assert_false(isc_task_privilege(task1)); + assert_false(isc_task_getprivilege(task1)); isc_task_setprivilege(task1, true); - assert_true(isc_task_privilege(task1)); + assert_true(isc_task_getprivilege(task1)); result = isc_task_create(taskmgr, 0, &task2); assert_int_equal(result, ISC_R_SUCCESS); isc_task_setname(task2, "normal", NULL); - assert_false(isc_task_privilege(task2)); + assert_false(isc_task_getprivilege(task2)); /* First event: privileged */ event = isc_event_allocate(test_mctx, task1, ISC_TASKEVENT_TEST, set, @@ -295,7 +297,7 @@ privileged_events(void **state) { assert_int_equal(atomic_load(&counter), 6); isc_task_setprivilege(task1, false); - assert_false(isc_task_privilege(task1)); + assert_false(isc_task_getprivilege(task1)); isc_task_destroy(&task1); assert_null(task1); @@ -329,18 +331,19 @@ privilege_drop(void **state) { * without things happening while we do it. */ isc_nm_pause(netmgr); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); result = isc_task_create(taskmgr, 0, &task1); assert_int_equal(result, ISC_R_SUCCESS); isc_task_setname(task1, "privileged", NULL); - assert_false(isc_task_privilege(task1)); + assert_false(isc_task_getprivilege(task1)); isc_task_setprivilege(task1, true); - assert_true(isc_task_privilege(task1)); + assert_true(isc_task_getprivilege(task1)); result = isc_task_create(taskmgr, 0, &task2); assert_int_equal(result, ISC_R_SUCCESS); isc_task_setname(task2, "normal", NULL); - assert_false(isc_task_privilege(task2)); + assert_false(isc_task_getprivilege(task2)); /* First event: privileged */ event = isc_event_allocate(test_mctx, task1, ISC_TASKEVENT_TEST, @@ -705,12 +708,16 @@ task_exclusive(void **state) { tasks[i] = NULL; - result = isc_task_create(taskmgr, 0, &tasks[i]); - assert_int_equal(result, ISC_R_SUCCESS); - - /* task chosen from the middle of the range */ if (i == 6) { + /* task chosen from the middle of the range */ + result = isc_task_create_bound(taskmgr, 0, &tasks[i], + 0); + assert_int_equal(result, ISC_R_SUCCESS); + isc_taskmgr_setexcltask(taskmgr, tasks[6]); + } else { + result = isc_task_create(taskmgr, 0, &tasks[i]); + assert_int_equal(result, ISC_R_SUCCESS); } v = isc_mem_get(test_mctx, sizeof *v); @@ -784,7 +791,6 @@ maxtask_cb(isc_task_t *task, isc_event_t *event) { static void manytasks(void **state) { isc_mem_t *mctx = NULL; - isc_result_t result; isc_event_t *event = NULL; uintptr_t ntasks = 10000; @@ -801,9 +807,7 @@ manytasks(void **state) { isc_mem_debugging = ISC_MEM_DEBUGRECORD; isc_mem_create(&mctx); - netmgr = isc_nm_start(mctx, 4); - result = isc_taskmgr_create(mctx, 0, netmgr, &taskmgr); - assert_int_equal(result, ISC_R_SUCCESS); + isc_managers_create(mctx, 4, 0, 0, &netmgr, &taskmgr, NULL, NULL); atomic_init(&done, false); @@ -818,8 +822,8 @@ manytasks(void **state) { } UNLOCK(&lock); - isc_taskmgr_destroy(&taskmgr); - isc_nm_destroy(&netmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); + isc_mem_destroy(&mctx); isc_condition_destroy(&cv); isc_mutex_destroy(&lock); @@ -899,7 +903,7 @@ sd_event2(isc_task_t *task, isc_event_t *event) { } static void -shutdown(void **state) { +task_shutdown(void **state) { isc_result_t result; isc_eventtype_t event_type; isc_event_t *event = NULL; @@ -1545,7 +1549,8 @@ main(int argc, char **argv) { cmocka_unit_test_setup_teardown(purgeevent_notpurge, _setup, _teardown), cmocka_unit_test_setup_teardown(purgerange, _setup, _teardown), - cmocka_unit_test_setup_teardown(shutdown, _setup4, _teardown), + cmocka_unit_test_setup_teardown(task_shutdown, _setup4, + _teardown), cmocka_unit_test_setup_teardown(task_exclusive, _setup4, _teardown), }; diff --git a/lib/isc/tests/taskpool_test.c b/lib/isc/tests/taskpool_test.c index 9878599721..58e0094f72 100644 --- a/lib/isc/tests/taskpool_test.c +++ b/lib/isc/tests/taskpool_test.c @@ -164,9 +164,9 @@ set_privilege(void **state) { assert_true(VALID_TASK(task2)); assert_true(VALID_TASK(task3)); - assert_true(isc_task_privilege(task1)); - assert_true(isc_task_privilege(task2)); - assert_true(isc_task_privilege(task3)); + assert_true(isc_task_getprivilege(task1)); + assert_true(isc_task_getprivilege(task2)); + assert_true(isc_task_getprivilege(task3)); isc_task_destroy(&task1); isc_task_destroy(&task2); diff --git a/lib/isc/timer.c b/lib/isc/timer.c index af49801660..a29d966726 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -29,9 +29,7 @@ #include #include -#ifdef OPENSSL_LEAKS -#include -#endif /* ifdef OPENSSL_LEAKS */ +#include "timer_p.h" #ifdef ISC_TIMER_TRACE #define XTRACE(s) fprintf(stderr, "%s\n", (s)) @@ -630,10 +628,6 @@ static isc_threadresult_t } UNLOCK(&manager->lock); -#ifdef OPENSSL_LEAKS - ERR_remove_state(0); -#endif /* ifdef OPENSSL_LEAKS */ - return ((isc_threadresult_t)0); } @@ -663,7 +657,7 @@ set_index(void *what, unsigned int index) { } isc_result_t -isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { isc_timermgr_t *manager; isc_result_t result; @@ -707,7 +701,7 @@ isc_timermgr_poke(isc_timermgr_t *manager) { } void -isc_timermgr_destroy(isc_timermgr_t **managerp) { +isc__timermgr_destroy(isc_timermgr_t **managerp) { isc_timermgr_t *manager; /* diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h new file mode 100644 index 0000000000..dca9d72466 --- /dev/null +++ b/lib/isc/timer_p.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include +#include + +isc_result_t +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); +/*%< + * Create a timer manager. + * + * Notes: + * + *\li All memory will be allocated in memory context 'mctx'. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'managerp' points to a NULL isc_timermgr_t. + * + * Ensures: + * + *\li '*managerp' is a valid isc_timermgr_t. + * + * Returns: + * + *\li Success + *\li No memory + *\li Unexpected error + */ + +void +isc__timermgr_destroy(isc_timermgr_t **managerp); +/*%< + * Destroy a timer manager. + * + * Notes: + * + *\li This routine blocks until there are no timers left in the manager, + * so if the caller holds any timer references using the manager, it + * must detach them before calling isc_timermgr_destroy() or it will + * block forever. + * + * Requires: + * + *\li '*managerp' is a valid isc_timermgr_t. + * + * Ensures: + * + *\li *managerp == NULL + * + *\li All resources used by the manager have been freed. + */ diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 03923b79c7..c196874483 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -74,6 +74,7 @@ #include #include "errno2result.h" +#include "socket_p.h" #ifdef ENABLE_TCP_FASTOPEN #include @@ -3752,12 +3753,7 @@ cleanup_thread(isc_mem_t *mctx, isc__socketthread_t *thread) { } isc_result_t -isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { - return (isc_socketmgr_create2(mctx, managerp, 0, 1)); -} - -isc_result_t -isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp, unsigned int maxsocks, int nthreads) { int i; isc_socketmgr_t *manager; @@ -3828,7 +3824,7 @@ isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) { } void -isc_socketmgr_destroy(isc_socketmgr_t **managerp) { +isc__socketmgr_destroy(isc_socketmgr_t **managerp) { isc_socketmgr_t *manager; /* diff --git a/lib/isc/unix/socket_p.h b/lib/isc/unix/socket_p.h deleted file mode 100644 index e6dd818d3c..0000000000 --- a/lib/isc/unix/socket_p.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -#ifndef ISC_SOCKET_P_H -#define ISC_SOCKET_P_H - -/*! \file */ - -#include - -typedef struct isc_socketwait isc_socketwait_t; -int -isc__socketmgr_waitevents(isc_socketmgr_t *, struct timeval *, - isc_socketwait_t **); -isc_result_t -isc__socketmgr_dispatch(isc_socketmgr_t *, isc_socketwait_t *); -#endif /* ISC_SOCKET_P_H */ diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index 9160199e6d..db582009ad 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -96,14 +96,12 @@ isc_socket_send isc_socket_sendto isc_socket_sendto2 isc_socket_setname -isc_socketmgr_create -isc_socketmgr_create2 -isc_socketmgr_destroy isc_socketmgr_getmaxsockets isc_socketmgr_setreserved isc_socketmgr_setstats isc_task_getname isc_task_gettag +isc_task_ready isc_task_run isc_task_unsendrange isc_taskmgr_attach @@ -352,6 +350,8 @@ isc_logconfig_create isc_logconfig_destroy isc_logconfig_use isc_logfile_roll +isc_managers_create +isc_managers_destroy isc_md_new isc_md_init isc_md_reset @@ -452,8 +452,6 @@ isc_nmhandle_peeraddr isc_nmhandle_setdata isc_nmhandle_settimeout isc_nm_cancelread -isc_nm_closedown -isc_nm_destroy isc_nm_detach isc_nm_http_endpoint isc_nm_httpconnect @@ -469,7 +467,6 @@ isc_nm_read isc_nm_resumeread isc_nm_send isc_nm_setstats -isc_nm_start isc_nm_stoplistening isc_nm_tcpconnect isc_nm_tcpdnsconnect @@ -638,9 +635,10 @@ isc_task_endexclusive isc_task_exiting isc_task_getcurrenttime isc_task_getcurrenttimex +isc_task_getprivilege isc_task_onshutdown isc_task_pause -isc_task_privilege +isc_task_privileged isc_task_purge isc_task_purgeevent isc_task_purgerange @@ -653,9 +651,8 @@ isc_task_setprivilege isc_task_shutdown isc_task_unpause isc_task_unsend -isc_taskmgr_create -isc_taskmgr_destroy isc_taskmgr_excltask +isc_taskmgr_mode @IF NOTYET isc_taskmgr_renderjson @END NOTYET @@ -663,6 +660,7 @@ isc_taskmgr_renderjson isc_taskmgr_renderxml @END LIBXML2 isc_taskmgr_setexcltask +isc_taskmgr_setmode isc_taskpool_create isc_taskpool_destroy isc_taskpool_expand @@ -706,8 +704,6 @@ isc_timer_detach isc_timer_gettype isc_timer_reset isc_timer_touch -isc_timermgr_create -isc_timermgr_destroy isc_timermgr_poke isc_tls_get_http2_alpn isc_tls_create diff --git a/lib/isc/win32/libisc.vcxproj.filters.in b/lib/isc/win32/libisc.vcxproj.filters.in index c859f3e46d..ce7b6e7edd 100644 --- a/lib/isc/win32/libisc.vcxproj.filters.in +++ b/lib/isc/win32/libisc.vcxproj.filters.in @@ -44,6 +44,9 @@ Library Header Files + + Library Header Files + Library Header Files @@ -140,6 +143,9 @@ Library Header Files + + Library Header Files + Library Header Files @@ -530,6 +536,9 @@ Library Source Files + + Library Source Files + Library Source Files diff --git a/lib/isc/win32/libisc.vcxproj.in b/lib/isc/win32/libisc.vcxproj.in index 19439387ed..6f73664314 100644 --- a/lib/isc/win32/libisc.vcxproj.in +++ b/lib/isc/win32/libisc.vcxproj.in @@ -269,6 +269,7 @@ copy InstallFiles ..\Build\Release\ + @@ -302,6 +303,7 @@ copy InstallFiles ..\Build\Release\ + @@ -412,6 +414,7 @@ copy InstallFiles ..\Build\Release\ + diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index cf101189f8..3fecf3ee40 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -82,6 +82,7 @@ #endif /* HAVE_LIBXML2 */ #include "errno2result.h" +#include "socket_p.h" /* * Set by the -T dscp option on the command line. If set to a value @@ -2548,12 +2549,7 @@ SocketIoThread(LPVOID ThreadContext) { * Create a new socket manager. */ isc_result_t -isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { - return (isc_socketmgr_create2(mctx, managerp, 0, 1)); -} - -isc_result_t -isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp, unsigned int maxsocks, int nthreads) { isc_socketmgr_t *manager; @@ -2611,7 +2607,7 @@ isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) { } void -isc_socketmgr_destroy(isc_socketmgr_t **managerp) { +isc__socketmgr_destroy(isc_socketmgr_t **managerp) { isc_socketmgr_t *manager; /* diff --git a/lib/ns/client.c b/lib/ns/client.c index 16e14be4c9..bc0afe1a19 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1629,15 +1629,13 @@ ns__client_put_cb(void *client0) { void ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *arg) { - ns_client_t *client; - ns_clientmgr_t *mgr; - ns_interface_t *ifp; + ns_client_t *client = NULL; isc_result_t result; isc_result_t sigresult = ISC_R_SUCCESS; - isc_buffer_t *buffer; + isc_buffer_t *buffer = NULL; isc_buffer_t tbuffer; - dns_rdataset_t *opt; - const dns_name_t *signame; + dns_rdataset_t *opt = NULL; + const dns_name_t *signame = NULL; bool ra; /* Recursion available. */ isc_netaddr_t netaddr; int match; @@ -1645,29 +1643,24 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult, unsigned int flags; bool notimp; size_t reqsize; - dns_aclenv_t *env; + dns_aclenv_t *env = NULL; #ifdef HAVE_DNSTAP dns_dtmsgtype_t dtmsgtype; #endif /* ifdef HAVE_DNSTAP */ - ifp = (ns_interface_t *)arg; if (eresult != ISC_R_SUCCESS) { return; } - mgr = ifp->clientmgr; - if (mgr == NULL) { - /* The interface was shut down in the meantime, just bail */ - return; - } - - REQUIRE(VALID_MANAGER(mgr)); - client = isc_nmhandle_getdata(handle); if (client == NULL) { + ns_interface_t *ifp = (ns_interface_t *)arg; + + INSIST(VALID_MANAGER(ifp->clientmgr)); + client = isc_nmhandle_getextra(handle); - result = ns__client_setup(client, mgr, true); + result = ns__client_setup(client, ifp->clientmgr, true); if (result != ISC_R_SUCCESS) { return; } diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 173a5c80e7..6cf7ac91a9 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,6 @@ isc_taskmgr_t *taskmgr = NULL; isc_task_t *maintask = NULL; isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; -isc_nm_t *nm = NULL; dns_zonemgr_t *zonemgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; ns_clientmgr_t *clientmgr = NULL; @@ -198,28 +198,12 @@ cleanup_managers(void) { if (interfacemgr != NULL) { ns_interfacemgr_detach(&interfacemgr); } - if (socketmgr != NULL) { - isc_socketmgr_destroy(&socketmgr); - } - ns_test_nap(500000); - if (nm != NULL) { - /* - * Force something in the workqueue as a workaround - * for libuv bug - not sending uv_close callback. - */ - isc_nm_pause(nm); - isc_nm_resume(nm); - isc_nm_detach(&nm); - } - if (taskmgr != NULL) { - isc_taskmgr_destroy(&taskmgr); - } - if (netmgr != NULL) { - isc_nm_destroy(&netmgr); - } - if (timermgr != NULL) { - isc_timermgr_destroy(&timermgr); - } + + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, + taskmgr == NULL ? NULL : &taskmgr, + timermgr == NULL ? NULL : &timermgr, + socketmgr == NULL ? NULL : &socketmgr); + if (app_running) { isc_app_finish(); } @@ -241,24 +225,18 @@ create_managers(void) { isc_event_t *event = NULL; ncpus = isc_os_ncpus(); - netmgr = isc_nm_start(mctx, ncpus); - CHECK(isc_taskmgr_create(mctx, 0, netmgr, &taskmgr)); - CHECK(isc_task_create(taskmgr, 0, &maintask)); + isc_managers_create(mctx, ncpus, 0, 0, &netmgr, &taskmgr, &timermgr, + &socketmgr); + CHECK(isc_task_create_bound(taskmgr, 0, &maintask, 0)); isc_taskmgr_setexcltask(taskmgr, maintask); CHECK(isc_task_onshutdown(maintask, shutdown_managers, NULL)); - CHECK(isc_timermgr_create(mctx, &timermgr)); - - CHECK(isc_socketmgr_create(mctx, &socketmgr)); - - nm = isc_nm_start(mctx, ncpus); - CHECK(ns_server_create(mctx, matchview, &sctx)); CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, socketmgr, - nm, dispatchmgr, maintask, ncpus, NULL, + netmgr, dispatchmgr, maintask, ncpus, NULL, ncpus, &interfacemgr)); CHECK(ns_listenlist_default(mctx, port, -1, true, &listenon)); diff --git a/util/copyrights b/util/copyrights index 1e37f6a4c7..96f8dd7eec 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1852,6 +1852,7 @@ ./lib/isc/include/isc/atomic.h C 2018,2019,2020,2021 ./lib/isc/include/isc/attributes.h C 2020,2021 ./lib/isc/include/isc/backtrace.h C 2009,2016,2018,2019,2020,2021 +./lib/isc/include/isc/barrier.h C 2021 ./lib/isc/include/isc/base32.h C 2008,2014,2016,2018,2019,2020,2021 ./lib/isc/include/isc/base64.h C 1999,2000,2001,2004,2005,2006,2007,2016,2018,2019,2020,2021 ./lib/isc/include/isc/bind9.h C 2009,2013,2016,2018,2019,2020,2021 @@ -1887,6 +1888,7 @@ ./lib/isc/include/isc/list.h C 1997,1998,1999,2000,2001,2002,2004,2006,2007,2011,2012,2013,2016,2018,2019,2020,2021 ./lib/isc/include/isc/log.h C 1999,2000,2001,2002,2004,2005,2006,2007,2009,2014,2016,2017,2018,2019,2020,2021 ./lib/isc/include/isc/magic.h C 1999,2000,2001,2004,2005,2006,2007,2016,2017,2018,2019,2020,2021 +./lib/isc/include/isc/managers.h C 2021 ./lib/isc/include/isc/md.h C 2018,2019,2020,2021 ./lib/isc/include/isc/mem.h C 1997,1998,1999,2000,2001,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2015,2016,2017,2018,2019,2020,2021 ./lib/isc/include/isc/meminfo.h C 2015,2016,2018,2019,2020,2021 @@ -1944,6 +1946,7 @@ ./lib/isc/lib.c C 1999,2000,2001,2004,2005,2007,2009,2013,2014,2015,2016,2018,2019,2020,2021 ./lib/isc/lib_p.h C 2021 ./lib/isc/log.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2009,2011,2012,2013,2014,2016,2017,2018,2019,2020,2021 +./lib/isc/managers.c C 2021 ./lib/isc/md.c C 2018,2019,2020,2021 ./lib/isc/mem.c C 1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 ./lib/isc/mem_p.h C 2018,2019,2020,2021 @@ -1960,6 +1963,7 @@ ./lib/isc/netmgr/uv-compat.c C 2020,2021 ./lib/isc/netmgr/uv-compat.h C 2019,2020,2021 ./lib/isc/netmgr/uverr2result.c C 2019,2020,2021 +./lib/isc/netmgr_p.h C 2021 ./lib/isc/netscope.c C 2002,2004,2005,2006,2007,2016,2018,2019,2020,2021 ./lib/isc/nonce.c C 2018,2019,2020,2021 ./lib/isc/openssl_shim.c C 2018,2019,2020,2021 @@ -1989,10 +1993,12 @@ ./lib/isc/serial.c C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021 ./lib/isc/siphash.c C 2019,2020,2021 ./lib/isc/sockaddr.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2010,2011,2012,2014,2015,2016,2017,2018,2019,2020,2021 +./lib/isc/socket_p.h C 2021 ./lib/isc/stats.c C 2009,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 ./lib/isc/string.c C 1999,2000,2001,2003,2004,2005,2006,2007,2011,2012,2014,2015,2016,2018,2019,2020,2021 ./lib/isc/symtab.c C 1996,1997,1998,1999,2000,2001,2004,2005,2007,2011,2012,2013,2016,2018,2019,2020,2021 ./lib/isc/task.c C 1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 +./lib/isc/task_p.h C 2021 ./lib/isc/taskpool.c C 1999,2000,2001,2004,2005,2007,2011,2012,2013,2016,2018,2019,2020,2021 ./lib/isc/tests/aes_test.c C 2014,2016,2018,2019,2020,2021 ./lib/isc/tests/buffer_test.c C 2014,2015,2016,2017,2018,2019,2020,2021 @@ -2031,6 +2037,7 @@ ./lib/isc/tests/timer_test.c C 2018,2019,2020,2021 ./lib/isc/tests/uv_wrap.h C 2020,2021 ./lib/isc/timer.c C 1998,1999,2000,2001,2002,2004,2005,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 +./lib/isc/timer_p.h C 2021 ./lib/isc/tls.c C 2021 ./lib/isc/tls_p.h C 2021 ./lib/isc/tm.c C 2014,2016,2018,2019,2020,2021 @@ -2059,7 +2066,6 @@ ./lib/isc/unix/pk11_api.c C 2014,2016,2018,2019,2020,2021 ./lib/isc/unix/resource.c C 2000,2001,2004,2007,2008,2009,2016,2018,2019,2020,2021 ./lib/isc/unix/socket.c C 1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 -./lib/isc/unix/socket_p.h C 2000,2001,2004,2005,2007,2008,2009,2016,2018,2019,2020,2021 ./lib/isc/unix/stdio.c C 2000,2001,2004,2007,2011,2012,2013,2014,2016,2018,2019,2020,2021 ./lib/isc/unix/stdtime.c C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021 ./lib/isc/unix/syslog.c C 2001,2004,2005,2007,2016,2018,2019,2020,2021