diff options
Diffstat (limited to 'lib/isc/task.c')
-rw-r--r-- | lib/isc/task.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/lib/isc/task.c b/lib/isc/task.c index 02d6e2abaf60..3503801e4517 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012, 2014 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2012, 2014, 2015 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -34,6 +34,7 @@ #include <isc/mem.h> #include <isc/msgs.h> #include <isc/platform.h> +#include <isc/print.h> #include <isc/string.h> #include <isc/task.h> #include <isc/thread.h> @@ -156,6 +157,13 @@ struct isc__taskmgr { isc_boolean_t pause_requested; isc_boolean_t exclusive_requested; isc_boolean_t exiting; + + /* + * 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() + * will try to acquire it. + */ + isc_mutex_t excl_lock; isc__task_t *excl; #ifdef USE_SHARED_MANAGER unsigned int refs; @@ -1307,6 +1315,7 @@ manager_free(isc__taskmgr_t *manager) { isc_mem_free(manager->mctx, manager->threads); #endif /* USE_WORKER_THREADS */ DESTROYLOCK(&manager->lock); + DESTROYLOCK(&manager->excl_lock); manager->common.impmagic = 0; manager->common.magic = 0; mctx = manager->mctx; @@ -1359,6 +1368,11 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, result = isc_mutex_init(&manager->lock); if (result != ISC_R_SUCCESS) goto cleanup_mgr; + result = isc_mutex_init(&manager->excl_lock); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&manager->lock); + goto cleanup_mgr; + } #ifdef USE_WORKER_THREADS manager->workers = 0; @@ -1490,8 +1504,10 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) { /* * Detach the exclusive task before acquiring the manager lock */ + LOCK(&manager->excl_lock); if (manager->excl != NULL) isc__task_detach((isc_task_t **) &manager->excl); + UNLOCK(&manager->excl_lock); /* * Unlike elsewhere, we're going to hold this lock a long time. @@ -1650,23 +1666,29 @@ isc__taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0) { REQUIRE(VALID_MANAGER(mgr)); REQUIRE(VALID_TASK(task)); + LOCK(&mgr->excl_lock); if (mgr->excl != NULL) isc__task_detach((isc_task_t **) &mgr->excl); isc__task_attach(task0, (isc_task_t **) &mgr->excl); + UNLOCK(&mgr->excl_lock); } 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; + isc_result_t result = ISC_R_SUCCESS; REQUIRE(VALID_MANAGER(mgr)); REQUIRE(taskp != NULL && *taskp == NULL); - if (mgr->excl == NULL) - return (ISC_R_NOTFOUND); + LOCK(&mgr->excl_lock); + if (mgr->excl != NULL) + isc__task_attach((isc_task_t *) mgr->excl, taskp); + else + result = ISC_R_NOTFOUND; + UNLOCK(&mgr->excl_lock); - isc__task_attach((isc_task_t *) mgr->excl, taskp); - return (ISC_R_SUCCESS); + return (result); } ISC_TASKFUNC_SCOPE isc_result_t |