#include <named/types.h>
-#define NAMED_EVENTCLASS ISC_EVENTCLASS(0x4E43)
-#define NAMED_EVENT_RELOAD (NAMED_EVENTCLASS + 0)
-#define NAMED_EVENT_DELZONE (NAMED_EVENTCLASS + 1)
-#define NAMED_EVENT_COMMAND (NAMED_EVENTCLASS + 2)
-#define NAMED_EVENT_TATSEND (NAMED_EVENTCLASS + 3)
+#define NAMED_EVENTCLASS ISC_EVENTCLASS(0x4E43)
+#define NAMED_EVENT_RELOAD (NAMED_EVENTCLASS + 0)
+#define NAMED_EVENT_DELZONE (NAMED_EVENTCLASS + 1)
+#define NAMED_EVENT_COMMAND (NAMED_EVENTCLASS + 2)
+#define NAMED_EVENT_TATSEND (NAMED_EVENTCLASS + 3)
+#define NAMED_EVENT_SHUTDOWN (NAMED_EVENTCLASS + 4)
/*%
* Name server state. Better here than in lots of separate global variables.
* Destroy a server object, freeing its memory.
*/
+void
+named_server_shutdown(named_server_t *server);
+/*%<
+ * Initiate the server shutdown.
+ */
+
void
named_server_reloadwanted(named_server_t *server);
/*%<
static void
cleanup(void) {
+ named_server_shutdown(named_g_server);
+
destroy_managers();
if (named_g_mapped != NULL) {
isc_event_free(&event);
}
+void
+named_server_shutdown(named_server_t *server) {
+ isc_event_t *event =
+ isc_event_allocate(named_g_mctx, server, NAMED_EVENT_SHUTDOWN,
+ shutdown_server, server, sizeof(*event));
+ isc_task_send(server->task, &event);
+}
+
/*%
* Find a view that matches the source and destination addresses of a query.
*/
server->sctx->fuzznotify = named_fuzz_notify;
#endif /* ifdef ENABLE_AFL */
- CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
- "isc_task_onshutdown");
CHECKFATAL(
isc_app_onrun(named_g_mctx, server->task, run_server, server),
"isc_app_onrun");
}
static void
-shutdown_program(isc_task_t *task, isc_event_t *event) {
- REQUIRE(task == global_task);
- UNUSED(task);
-
+shutdown_program(void) {
ddebug("shutdown_program()");
- isc_event_free(&event);
shuttingdown = true;
maybeshutdown();
result = isc_task_create(taskmgr, 0, &global_task);
check_result(result, "isc_task_create");
- result = isc_task_onshutdown(global_task, shutdown_program, NULL);
- check_result(result, "isc_task_onshutdown");
-
result = dst_lib_init(gmctx, NULL);
check_result(result, "dst_lib_init");
is_dst_up = true;
(void)isc_app_run();
+ shutdown_program();
+
cleanup();
isc_app_finish();
When a task is shutdown:
- Any "on shutdown" events for the task are posted
-
The "shutting down" attribute of the task is set
- Any attempts to add shutdown events with isc_task_onshutdown()
- will fail, since the task is already shutting down
-
Task shutdown can be initiated explicitly, via a call to isc_task_shutdown(),
or implicitly, when the following conditions occur:
The task has an empty event queue
-
Task termination occurs when:
The "shutting down" attribute of the task is set
* If the cleaner task exists, let it free the cache.
*/
if (isc_refcount_decrement(&cache->live_tasks) > 1) {
+ isc_event_t *event = isc_event_allocate(
+ cache->mctx, &cache->cleaner,
+ DNS_EVENT_CACHESHUTDOWN,
+ cleaner_shutdown_action, &cache->cleaner,
+ sizeof(*event));
+ isc_task_send(cache->cleaner.task, &event);
isc_task_shutdown(cache->cleaner.task);
} else {
cache_free(cache);
isc_refcount_increment(&cleaner->cache->live_tasks);
isc_task_setname(cleaner->task, "cachecleaner", cleaner);
- result = isc_task_onshutdown(cleaner->task,
- cleaner_shutdown_action, cache);
- if (result != ISC_R_SUCCESS) {
- isc_refcount_decrement0(&cleaner->cache->live_tasks);
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "cache cleaner: "
- "isc_task_onshutdown() failed: %s",
- isc_result_totext(result));
- goto cleanup;
- }
-
cleaner->resched_event = isc_event_allocate(
cache->mctx, cleaner, DNS_EVENT_CACHECLEAN,
incremental_cleaning_action, cleaner,
#define DNS_EVENT_TRYSTALE (ISC_EVENTCLASS_DNS + 59)
#define DNS_EVENT_ZONEFLUSH (ISC_EVENTCLASS_DNS + 60)
#define DNS_EVENT_CHECKDSSENDTOADDR (ISC_EVENTCLASS_DNS + 61)
+#define DNS_EVENT_CACHESHUTDOWN (ISC_EVENTCLASS_DNS + 62)
* or was marked unpurgeable.
*/
-isc_result_t
-isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg);
-/*%<
- * Send a shutdown event with action 'action' and argument 'arg' when
- * 'task' is shutdown.
- *
- * Notes:
- *
- *\li Shutdown events are posted in LIFO order.
- *
- * Requires:
- *
- *\li 'task' is a valid task.
- *
- *\li 'action' is a valid task action.
- *
- * Ensures:
- *
- *\li When the task is shutdown, shutdown events requested with
- * isc_task_onshutdown() will be appended to the task's event queue.
- *
- *
- * Returns:
- *
- *\li #ISC_R_SUCCESS
- *\li #ISC_R_NOMEMORY
- *\li #ISC_R_SHUTTINGDOWN Task is shutting down.
- */
-
void
isc_task_shutdown(isc_task_t *task);
/*%<
*
* Notes:
*
- *\li Shutting down a task causes any shutdown events requested with
- * isc_task_onshutdown() to be posted (in LIFO order). The task
- * moves into a "shutting down" mode which prevents further calls
- * to isc_task_onshutdown().
+ *\li The task moves into a "shutting down" mode.
*
*\li Trying to shutdown a task that has already been shutdown has no
* effect.
*
*\li 'task' is a valid task.
*
- * Ensures:
- *
- *\li Any shutdown events requested with isc_task_onshutdown() have been
- * posted (in LIFO order).
*/
void
isc_refcount_t references;
isc_refcount_t running;
isc_eventlist_t events;
- isc_eventlist_t on_shutdown;
unsigned int nevents;
unsigned int quantum;
isc_stdtime_t now;
isc_mem_t *mctx = manager->mctx;
REQUIRE(EMPTY(task->events));
REQUIRE(task->nevents == 0);
- REQUIRE(EMPTY(task->on_shutdown));
REQUIRE(task->state == task_state_done);
XTRACE("task_finished");
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->shuttingdown, false);
static bool
task_shutdown(isc_task_t *task) {
bool was_idle = false;
- isc_event_t *event, *prev;
/*
* Caller must be holding the task's lock.
}
INSIST(task->state == task_state_ready ||
task->state == task_state_running);
-
- /*
- * Note that we post shutdown events LIFO.
- */
- for (event = TAIL(task->on_shutdown); event != NULL;
- event = prev) {
- prev = PREV(event, ev_link);
- DEQUEUE(task->on_shutdown, event, ev_link);
- ENQUEUE(task->events, event, ev_link);
- task->nevents++;
- }
}
return (was_idle);
return (true);
}
-isc_result_t
-isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg) {
- bool disallowed = false;
- isc_result_t result = ISC_R_SUCCESS;
- isc_event_t *event;
-
- /*
- * Send a shutdown event with action 'action' and argument 'arg' when
- * 'task' is shutdown.
- */
-
- REQUIRE(VALID_TASK(task));
- REQUIRE(action != NULL);
-
- event = isc_event_allocate(task->manager->mctx, NULL,
- ISC_TASKEVENT_SHUTDOWN, action, arg,
- sizeof(*event));
-
- if (TASK_SHUTTINGDOWN(task)) {
- disallowed = true;
- result = ISC_R_SHUTTINGDOWN;
- } else {
- LOCK(&task->lock);
- ENQUEUE(task->on_shutdown, event, ev_link);
- UNLOCK(&task->lock);
- }
-
- if (disallowed) {
- isc_mem_put(task->manager->mctx, event, sizeof(*event));
- }
-
- return (result);
-}
-
void
isc_task_shutdown(isc_task_t *task) {
bool was_idle;
isc_event_free(&event);
}
-static void
-basic_shutdown(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- if (verbose) {
- print_message("# shutdown %s\n", (char *)event->ev_arg);
- }
-
- isc_event_free(&event);
-}
-
static void
basic_tick(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
result = isc_task_create(taskmgr, 0, &task4);
assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task1, basic_shutdown, one);
- assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task2, basic_shutdown, two);
- assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task3, basic_shutdown, three);
- assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task4, basic_shutdown, four);
- assert_int_equal(result, ISC_R_SUCCESS);
-
isc_interval_set(&interval, 1, 0);
isc_timer_create(timermgr, task1, basic_tick, tick, &ti1);
result = isc_timer_reset(ti1, isc_timertype_ticker, &interval, false);
* Max tasks test:
* The task system can create and execute many tasks. Tests with 10000.
*/
-static void
-maxtask_shutdown(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- if (event->ev_arg != NULL) {
- isc_task_destroy((isc_task_t **)&event->ev_arg);
- } else {
- LOCK(&lock);
- atomic_store(&done, true);
- SIGNAL(&cv);
- UNLOCK(&lock);
- }
-
- isc_event_free(&event);
-}
static void
maxtask_cb(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
+ uintptr_t ntasks = (uintptr_t)event->ev_arg;
- if (event->ev_arg != NULL) {
- isc_task_t *newtask = NULL;
+ if (ntasks-- > 0) {
+ task = NULL;
- event->ev_arg = (void *)(((uintptr_t)event->ev_arg) - 1);
+ event->ev_arg = (void *)ntasks;
/*
* Create a new task and forward the message.
*/
- result = isc_task_create(taskmgr, 0, &newtask);
+ result = isc_task_create(taskmgr, 0, &task);
assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(newtask, maxtask_shutdown,
- (void *)task);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- isc_task_send(newtask, &event);
- } else if (task != NULL) {
- isc_task_destroy(&task);
+ isc_task_send(task, &event);
+ isc_task_detach(&task);
+ } else {
isc_event_free(&event);
+
+ LOCK(&lock);
+ atomic_store(&done, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
}
}
static void
manytasks(void **state) {
- isc_mem_t *mctx = NULL;
isc_event_t *event = NULL;
- uintptr_t ntasks = 10000;
+ uintptr_t ntasks = 2; /* 0000; */
UNUSED(state);
isc_mutex_init(&lock);
isc_condition_init(&cv);
- isc_mem_debugging = ISC_MEM_DEBUGRECORD;
- isc_mem_create(&mctx);
-
- isc_managers_create(mctx, 4, 0, &netmgr, &taskmgr, NULL);
-
atomic_init(&done, false);
- event = isc_event_allocate(mctx, (void *)1, 1, maxtask_cb,
+ event = isc_event_allocate(test_mctx, NULL, 1, maxtask_cb,
(void *)ntasks, sizeof(*event));
assert_non_null(event);
}
UNLOCK(&lock);
- isc_managers_destroy(&netmgr, &taskmgr, NULL);
-
- isc_mem_destroy(&mctx);
isc_condition_destroy(&cv);
isc_mutex_destroy(&lock);
}
-/*
- * Shutdown test:
- * When isc_task_shutdown() is called, shutdown events are posted
- * in LIFO order.
- */
-
-static int nevents = 0;
-static int nsdevents = 0;
-static int senders[4];
-atomic_bool ready, all_done;
-
-static void
-sd_sde1(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- assert_int_equal(nevents, 256);
- assert_int_equal(nsdevents, 1);
- ++nsdevents;
-
- if (verbose) {
- print_message("# shutdown 1\n");
- }
-
- isc_event_free(&event);
-
- atomic_store(&all_done, true);
-}
-
-static void
-sd_sde2(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- assert_int_equal(nevents, 256);
- assert_int_equal(nsdevents, 0);
- ++nsdevents;
-
- if (verbose) {
- print_message("# shutdown 2\n");
- }
-
- isc_event_free(&event);
-}
-
-static void
-sd_event1(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- LOCK(&lock);
- while (!atomic_load(&ready)) {
- WAIT(&cv, &lock);
- }
- UNLOCK(&lock);
-
- if (verbose) {
- print_message("# event 1\n");
- }
-
- isc_event_free(&event);
-}
-
-static void
-sd_event2(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- ++nevents;
-
- if (verbose) {
- print_message("# event 2\n");
- }
-
- isc_event_free(&event);
-}
-
-static void
-task_shutdown(void **state) {
- isc_result_t result;
- isc_eventtype_t event_type;
- isc_event_t *event = NULL;
- isc_task_t *task = NULL;
- int i;
-
- UNUSED(state);
-
- nevents = nsdevents = 0;
- event_type = 3;
- atomic_init(&ready, false);
- atomic_init(&all_done, false);
-
- LOCK(&lock);
-
- result = isc_task_create(taskmgr, 0, &task);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- /*
- * This event causes the task to wait on cv.
- */
- event = isc_event_allocate(test_mctx, &senders[1], event_type,
- sd_event1, NULL, sizeof(*event));
- assert_non_null(event);
- isc_task_send(task, &event);
-
- /*
- * Now we fill up the task's event queue with some events.
- */
- for (i = 0; i < 256; ++i) {
- event = isc_event_allocate(test_mctx, &senders[1], event_type,
- sd_event2, NULL, sizeof(*event));
- assert_non_null(event);
- isc_task_send(task, &event);
- }
-
- /*
- * Now we register two shutdown events.
- */
- result = isc_task_onshutdown(task, sd_sde1, NULL);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- result = isc_task_onshutdown(task, sd_sde2, NULL);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- isc_task_shutdown(task);
- isc_task_detach(&task);
-
- /*
- * Now we free the task by signaling cv.
- */
- atomic_store(&ready, true);
- SIGNAL(&cv);
- UNLOCK(&lock);
-
- while (!atomic_load(&all_done)) {
- isc_test_nap(1000);
- }
-
- assert_int_equal(nsdevents, 2);
-}
-
-/*
- * Post-shutdown test:
- * After isc_task_shutdown() has been called, any call to
- * isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.
- */
-static void
-psd_event1(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- LOCK(&lock);
-
- while (!atomic_load(&done)) {
- WAIT(&cv, &lock);
- }
-
- UNLOCK(&lock);
-
- isc_event_free(&event);
-}
-
-static void
-psd_sde(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- isc_event_free(&event);
-}
-
-static void
-post_shutdown(void **state) {
- isc_result_t result;
- isc_eventtype_t event_type;
- isc_event_t *event;
- isc_task_t *task;
-
- UNUSED(state);
-
- atomic_init(&done, false);
- event_type = 4;
-
- isc_condition_init(&cv);
-
- LOCK(&lock);
-
- task = NULL;
- result = isc_task_create(taskmgr, 0, &task);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- /*
- * This event causes the task to wait on cv.
- */
- event = isc_event_allocate(test_mctx, &senders[1], event_type,
- psd_event1, NULL, sizeof(*event));
- assert_non_null(event);
- isc_task_send(task, &event);
-
- isc_task_shutdown(task);
-
- result = isc_task_onshutdown(task, psd_sde, NULL);
- assert_int_equal(result, ISC_R_SHUTTINGDOWN);
-
- /*
- * Release the task.
- */
- atomic_store(&done, true);
-
- SIGNAL(&cv);
- UNLOCK(&lock);
-
- isc_task_detach(&task);
-}
-
/*
* Helper for the purge tests below:
*/
}
UNLOCK(&lock);
+ LOCK(&lock);
+ atomic_store(&done, true);
+ SIGNAL(&cv);
+ UNLOCK(&lock);
+
isc_event_free(&event);
}
isc_event_free(&event);
}
-static void
-pge_sde(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
-
- LOCK(&lock);
- atomic_store(&done, true);
- SIGNAL(&cv);
- UNLOCK(&lock);
-
- isc_event_free(&event);
-}
-
static void
try_purgeevent(void) {
isc_result_t result;
result = isc_task_create(taskmgr, 0, &task);
assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task, pge_sde, NULL);
- assert_int_equal(result, ISC_R_SUCCESS);
-
/*
* Block the task on cv.
*/
int
main(int argc, char **argv) {
const struct CMUnitTest tests[] = {
- cmocka_unit_test(manytasks),
+ cmocka_unit_test_setup_teardown(manytasks, _setup, _teardown),
cmocka_unit_test_setup_teardown(all_events, _setup, _teardown),
cmocka_unit_test_setup_teardown(basic, _setup2, _teardown),
cmocka_unit_test_setup_teardown(create_task, _setup, _teardown),
- cmocka_unit_test_setup_teardown(post_shutdown, _setup2,
- _teardown),
cmocka_unit_test_setup_teardown(purgeevent, _setup2, _teardown),
- cmocka_unit_test_setup_teardown(task_shutdown, _setup4,
- _teardown),
cmocka_unit_test_setup_teardown(task_exclusive, _setup4,
_teardown),
};
}
static void
-test_shutdown(isc_task_t *task, isc_event_t *event) {
+test_shutdown(void) {
isc_result_t result;
- UNUSED(task);
-
/*
* Signal shutdown processing complete.
*/
result = isc_mutex_unlock(&mx);
assert_int_equal(result, ISC_R_SUCCESS);
-
- isc_event_free(&event);
}
static void
result = isc_task_create(taskmgr, 0, &task);
assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task, test_shutdown, NULL);
- assert_int_equal(result, ISC_R_SUCCESS);
-
isc_mutex_lock(&lasttime_mx);
result = isc_time_now(&lasttime);
isc_mutex_unlock(&lasttime_mx);
isc_interval_t interval;
isc_eventtype_t expected_event_type;
+ UNUSED(task);
+
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
result = isc_time_now(&endtime);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
isc_timer_destroy(&timer);
- isc_task_shutdown(task);
+ test_shutdown();
}
}
isc_time_t llim;
isc_interval_t interval;
+ UNUSED(task);
+
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
isc_event_free(&event);
isc_timer_destroy(&timer);
- isc_task_shutdown(task);
+ test_shutdown();
}
/* timer type once idles out */
isc_time_t llim;
isc_interval_t interval;
+ UNUSED(task);
+
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
isc_event_free(&event);
isc_timer_destroy(&timer);
- isc_task_shutdown(task);
+ test_shutdown();
}
}
&interval, true);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
- isc_task_shutdown(task);
+ atomic_store(&shutdownflag, 1);
}
isc_event_free(&event);
static void
once_event(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
if (verbose) {
print_message("# once_event\n");
}
*/
atomic_store(&startflag, true);
- isc_event_free(&event);
- isc_task_shutdown(task);
-}
-
-static void
-shutdown_purge(isc_task_t *task, isc_event_t *event) {
- UNUSED(task);
- UNUSED(event);
-
- if (verbose) {
- print_message("# shutdown_event\n");
- }
-
- /*
- * Signal shutdown processing complete.
- */
- atomic_store(&shutdownflag, 1);
-
isc_event_free(&event);
}
result = isc_task_create(taskmgr, 0, &task1);
assert_int_equal(result, ISC_R_SUCCESS);
- result = isc_task_onshutdown(task1, shutdown_purge, NULL);
- assert_int_equal(result, ISC_R_SUCCESS);
-
result = isc_task_create(taskmgr, 0, &task2);
assert_int_equal(result, ISC_R_SUCCESS);
shutdown_managers(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
+ isc_event_free(&event);
+
if (interfacemgr != NULL) {
ns_interfacemgr_shutdown(interfacemgr);
ns_interfacemgr_detach(&interfacemgr);
atomic_store(&shutdown_done, true);
atomic_store(&run_managers, false);
-
- isc_event_free(&event);
}
static void
atomic_store(&shutdown_done, false);
if (maintask != NULL) {
+ isc_event_t *event = isc_event_allocate(
+ mctx, NULL, ISC_TASKEVENT_TEST, shutdown_managers, NULL,
+ sizeof(*event));
+ isc_task_send(maintask, &event);
isc_task_shutdown(maintask);
isc_task_destroy(&maintask);
}
isc_managers_create(mctx, ncpus, 0, &netmgr, &taskmgr, &timermgr);
CHECK(isc_task_create_bound(taskmgr, 0, &maintask, 0));
isc_taskmgr_setexcltask(taskmgr, maintask);
- CHECK(isc_task_onshutdown(maintask, shutdown_managers, NULL));
CHECK(ns_server_create(mctx, matchview, &sctx));