diff --git a/CHANGES b/CHANGES index da08d55cf5..d7ac8e7d5b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3353. [bug] Use a single task for task exclusive operations. + [RT #29872] + 3352. [bug] Ensure that learned server attributes timeout of the adb cache. [RT #29856] diff --git a/bin/named/server.c b/bin/named/server.c index c2f1b07fa4..cb592dfffd 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5603,11 +5603,13 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { /* * Setup the server task, which is responsible for coordinating - * startup and shutdown of the server. + * startup and shutdown of the server, as well as all exclusive + * tasks. */ CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), "creating server task"); isc_task_setname(server->task, "server", server); + isc_taskmgr_setexcltask(ns_g_taskmgr, server->task); CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), "isc_task_onshutdown"); CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 13432567f4..535624cdac 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -111,6 +111,7 @@ struct dns_adb { isc_taskmgr_t *taskmgr; isc_task_t *task; + isc_task_t *excl; isc_interval_t tick_interval; int next_cleanbucket; @@ -1653,10 +1654,12 @@ new_adbname(dns_adb_t *adb, dns_name_t *dnsname) { LOCK(&adb->namescntlock); adb->namescnt++; inc_adbstats(adb, dns_adbstats_namescnt); - if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) { + if (!adb->grownames_sent && adb->excl != NULL && + adb->namescnt > (adb->nnames * 8)) + { isc_event_t *event = &adb->grownames; inc_adb_irefcnt(adb); - isc_task_send(adb->task, &event); + isc_task_send(adb->excl, &event); adb->grownames_sent = ISC_TRUE; } UNLOCK(&adb->namescntlock); @@ -1779,8 +1782,9 @@ new_adbentry(dns_adb_t *adb) { LOCK(&adb->entriescntlock); adb->entriescnt++; inc_adbstats(adb, dns_adbstats_entriescnt); - if (!adb->growentries_sent && - adb->entriescnt > (adb->nentries * 8)) { + if (!adb->growentries_sent && adb->growentries_sent && + adb->entriescnt > (adb->nentries * 8)) + { isc_event_t *event = &adb->growentries; inc_adb_irefcnt(adb); isc_task_send(adb->task, &event); @@ -2356,6 +2360,7 @@ destroy(dns_adb_t *adb) { adb->magic = 0; isc_task_detach(&adb->task); + isc_task_detach(&adb->excl); isc_mempool_destroy(&adb->nmp); isc_mempool_destroy(&adb->nhmp); @@ -2439,6 +2444,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, adb->aimp = NULL; adb->afmp = NULL; adb->task = NULL; + adb->excl = NULL; adb->mctx = NULL; adb->view = view; adb->taskmgr = taskmgr; @@ -2474,6 +2480,16 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, adb, NULL, NULL); adb->grownames_sent = ISC_FALSE; + result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl); + if (result != ISC_R_SUCCESS) { + DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, " + "intializing table sizes to %u\n", + nbuckets[11]); + adb->nentries = nbuckets[11]; + adb->nnames= nbuckets[11]; + + } + isc_mem_attach(mem, &adb->mctx); result = isc_mutex_init(&adb->lock); @@ -2586,11 +2602,13 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, result = isc_task_create(adb->taskmgr, 0, &adb->task); if (result != ISC_R_SUCCESS) goto fail3; + isc_task_setname(adb->task, "ADB", adb); result = isc_stats_create(adb->mctx, &view->adbstats, dns_adbstats_max); if (result != ISC_R_SUCCESS) goto fail3; + set_adbstat(adb, adb->nentries, dns_adbstats_nentries); set_adbstat(adb, adb->nnames, dns_adbstats_nnames); diff --git a/lib/isc/include/isc/namespace.h b/lib/isc/include/isc/namespace.h index 444e814348..1dbb1a766b 100644 --- a/lib/isc/include/isc/namespace.h +++ b/lib/isc/include/isc/namespace.h @@ -153,6 +153,8 @@ #define isc_taskmgr_setmode isc__taskmgr_setmode #define isc_taskmgr_mode isc__taskmgr_mode #define isc_taskmgr_destroy isc__taskmgr_destroy +#define isc_taskmgr_setexcltask isc__taskmgr_setexcltask +#define isc_taskmgr_excltask isc__taskmgr_excltask #define isc_task_beginexclusive isc__task_beginexclusive #define isc_task_endexclusive isc__task_endexclusive #define isc_task_setprivilege isc__task_setprivilege diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h index 594d80f345..31234b7618 100644 --- a/lib/isc/include/isc/task.h +++ b/lib/isc/include/isc/task.h @@ -115,6 +115,8 @@ typedef struct isc_taskmgrmethods { isc_result_t (*taskcreate)(isc_taskmgr_t *manager, unsigned int quantum, isc_task_t **taskp); + void (*setexcltask)(isc_taskmgr_t *mgr, isc_task_t *task); + isc_result_t (*excltask)(isc_taskmgr_t *mgr, isc_task_t **taskp); } isc_taskmgrmethods_t; typedef struct isc_taskmethods { @@ -759,6 +761,31 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp); * have been freed. */ +void +isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task); +/*%< + * Set a task which will be used for all task-exclusive operations. + * + * Requires: + *\li 'manager' is a valid task manager. + * + *\li 'task' is a valid task. + */ + +isc_result_t +isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp); +/*%< + * Attach '*taskp' to the task set by isc_taskmgr_getexcltask(). + * This task should be used whenever running in task-exclusive mode, + * so as to prevent deadlock between two exclusive tasks. + * + * Requires: + *\li 'manager' is a valid task manager. + + *\li taskp != NULL && *taskp == NULL + */ + + #ifdef HAVE_LIBXML2 void diff --git a/lib/isc/task.c b/lib/isc/task.c index 5a6455de55..ba2920b163 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -158,6 +158,7 @@ struct isc__taskmgr { isc_boolean_t pause_requested; isc_boolean_t exclusive_requested; isc_boolean_t exiting; + isc__task_t *excl; #ifdef USE_SHARED_MANAGER unsigned int refs; #endif /* ISC_PLATFORM_USETHREADS */ @@ -227,6 +228,10 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, unsigned int default_quantum, isc_taskmgr_t **managerp); ISC_TASKFUNC_SCOPE void isc__taskmgr_destroy(isc_taskmgr_t **managerp); +ISC_TASKFUNC_SCOPE void +isc__taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0); +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp); ISC_TASKFUNC_SCOPE isc_result_t isc__task_beginexclusive(isc_task_t *task); ISC_TASKFUNC_SCOPE void @@ -288,7 +293,9 @@ static isc_taskmgrmethods_t taskmgrmethods = { isc__taskmgr_destroy, isc__taskmgr_setmode, isc__taskmgr_mode, - isc__task_create + isc__task_create, + isc__taskmgr_setexcltask, + isc__taskmgr_excltask }; /*** @@ -1411,6 +1418,7 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, manager->exclusive_requested = ISC_FALSE; manager->pause_requested = ISC_FALSE; manager->exiting = ISC_FALSE; + manager->excl = NULL; isc_mem_attach(mctx, &manager->mctx); @@ -1494,6 +1502,12 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) { * that the startup thread is sleeping on. */ + /* + * Detach the exclusive task before acquiring the manager lock + */ + if (manager->excl != NULL) + isc__task_detach((isc_task_t **) &manager->excl); + /* * Unlike elsewhere, we're going to hold this lock a long time. * We need to do so, because otherwise the list of tasks could @@ -1644,12 +1658,41 @@ isc__taskmgr_resume(isc_taskmgr_t *manager0) { } #endif /* USE_WORKER_THREADS */ +ISC_TASKFUNC_SCOPE void +isc__taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0) { + isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0; + isc__task_t *task = (isc__task_t *) task0; + + REQUIRE(VALID_MANAGER(mgr)); + REQUIRE(VALID_TASK(task)); + if (mgr->excl != NULL) + isc__task_detach((isc_task_t **) &mgr->excl); + isc__task_attach(task0, (isc_task_t **) &mgr->excl); +} + +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp) { + isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0; + + REQUIRE(VALID_MANAGER(mgr)); + REQUIRE(taskp != NULL && *taskp == NULL); + + if (mgr->excl == NULL) + return (ISC_R_NOTFOUND); + + isc__task_attach((isc_task_t *) mgr->excl, taskp); + return (ISC_R_SUCCESS); +} + ISC_TASKFUNC_SCOPE isc_result_t isc__task_beginexclusive(isc_task_t *task0) { #ifdef USE_WORKER_THREADS isc__task_t *task = (isc__task_t *)task0; isc__taskmgr_t *manager = task->manager; + REQUIRE(task->state == task_state_running); + /* XXX: Require task == manager->excl? */ + LOCK(&manager->lock); if (manager->exclusive_requested) { UNLOCK(&manager->lock); diff --git a/lib/isc/task_api.c b/lib/isc/task_api.c index 34510ff64c..f49ab321b2 100644 --- a/lib/isc/task_api.c +++ b/lib/isc/task_api.c @@ -201,6 +201,17 @@ isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag) return (task->methods->purgeevents(task, sender, type, tag)); } +void +isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + return (mgr->methods->setexcltask(mgr, task)); +} + +isc_result_t +isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp) { + return (mgr->methods->excltask(mgr, taskp)); +} + isc_result_t isc_task_beginexclusive(isc_task_t *task) { REQUIRE(ISCAPI_TASK_VALID(task)); diff --git a/lib/isc/tests/isctest.c b/lib/isc/tests/isctest.c index e118bbf2ad..41b09fce6e 100644 --- a/lib/isc/tests/isctest.c +++ b/lib/isc/tests/isctest.c @@ -42,6 +42,7 @@ isc_log_t *lctx = NULL; isc_taskmgr_t *taskmgr = NULL; isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; +isc_task_t *maintask = NULL; int ncpus; static isc_boolean_t hash_active = ISC_FALSE; @@ -63,6 +64,8 @@ static isc_logcategory_t categories[] = { static void cleanup_managers() { + if (maintask != NULL) + isc_task_destroy(&maintask); if (socketmgr != NULL) isc_socketmgr_destroy(&socketmgr); if (taskmgr != NULL) @@ -81,6 +84,9 @@ create_managers() { #endif CHECK(isc_taskmgr_create(mctx, ncpus, 0, &taskmgr)); + CHECK(isc_task_create(taskmgr, 0, &maintask)); + isc_taskmgr_setexcltask(taskmgr, maintask); + CHECK(isc_timermgr_create(mctx, &timermgr)); CHECK(isc_socketmgr_create(mctx, &socketmgr)); return (ISC_R_SUCCESS); @@ -138,6 +144,8 @@ isc_test_begin(FILE *logfile, isc_boolean_t start_managers) { void isc_test_end() { + if (maintask != NULL) + isc_task_detach(&maintask); if (taskmgr != NULL) isc_taskmgr_destroy(&taskmgr); if (lctx != NULL) diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def index e9000d2374..eee911e8ea 100644 --- a/lib/isc/win32/libisc.def +++ b/lib/isc/win32/libisc.def @@ -140,7 +140,9 @@ isc__task_unsend isc__task_unsendrange isc__taskmgr_create isc__taskmgr_destroy +isc__taskmgr_excltask isc__taskmgr_mode +isc__taskmgr_setexcltask isc__taskmgr_setmode isc__timer_attach isc__timer_create @@ -219,9 +221,9 @@ isc_event_free isc_file_absolutepath isc_file_basename isc_file_exists +isc_file_getmodtime isc_file_getsize isc_file_getsizefd -isc_file_getmodtime isc_file_isabsolute isc_file_ischdiridempotent isc_file_iscurrentdir