Remove isc_task_onshutdown()

The isc_task_onshutdown() was used to post event that should be run when
the task is being shutdown.  This could happen explicitly in the
isc_test_shutdown() call or implicitly when we detach the last reference
to the task and there are no more events posted on the task.

This whole task onshutdown mechanism just makes things more complicated,
and it's easier to post the "shutdown" events when we are shutting down
explicitly and the existing code already always knows when it should
shutdown the task that's being used to execute the onshutdown events.

Replace the isc_task_onshutdown() calls with explicit calls to execute
the shutdown tasks.
This commit is contained in:
Ondřej Surý
2022-05-09 11:33:09 +02:00
parent 8fbb75e457
commit 2235edabcf
12 changed files with 80 additions and 446 deletions

View File

@@ -205,17 +205,6 @@ basic_cb(isc_task_t *task, isc_event_t *event) {
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);
@@ -260,15 +249,6 @@ basic(void **state) {
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);
@@ -421,53 +401,39 @@ task_exclusive(void **state) {
* 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);
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 (ntasks-- > 0) {
task = NULL;
event->ev_arg = (void *)ntasks;
/*
* Create a new task and forward the message.
*/
result = isc_task_create(taskmgr, 0, &task);
assert_int_equal(result, ISC_R_SUCCESS);
isc_task_send(task, &event);
isc_task_detach(&task);
} else {
isc_event_free(&event);
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;
if (event->ev_arg != NULL) {
isc_task_t *newtask = NULL;
event->ev_arg = (void *)(((uintptr_t)event->ev_arg) - 1);
/*
* Create a new task and forward the message.
*/
result = isc_task_create(taskmgr, 0, &newtask);
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_event_free(&event);
}
}
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);
@@ -479,14 +445,9 @@ manytasks(void **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);
@@ -497,221 +458,10 @@ manytasks(void **state) {
}
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:
*/
@@ -738,6 +488,11 @@ pge_event1(isc_task_t *task, isc_event_t *event) {
}
UNLOCK(&lock);
LOCK(&lock);
atomic_store(&done, true);
SIGNAL(&cv);
UNLOCK(&lock);
isc_event_free(&event);
}
@@ -749,18 +504,6 @@ pge_event2(isc_task_t *task, isc_event_t *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;
@@ -781,9 +524,6 @@ try_purgeevent(void) {
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.
*/
@@ -847,15 +587,11 @@ purgeevent(void **state) {
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),
};

View File

@@ -81,11 +81,9 @@ _teardown(void **state) {
}
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.
*/
@@ -97,8 +95,6 @@ test_shutdown(isc_task_t *task, isc_event_t *event) {
result = isc_mutex_unlock(&mx);
assert_int_equal(result, ISC_R_SUCCESS);
isc_event_free(&event);
}
static void
@@ -121,9 +117,6 @@ setup_test(isc_timertype_t timertype, isc_interval_t *interval,
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);
@@ -200,6 +193,8 @@ ticktock(isc_task_t *task, isc_event_t *event) {
isc_interval_t interval;
isc_eventtype_t expected_event_type;
UNUSED(task);
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
@@ -247,7 +242,7 @@ ticktock(isc_task_t *task, isc_event_t *event) {
result = isc_time_now(&endtime);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
isc_timer_destroy(&timer);
isc_task_shutdown(task);
test_shutdown();
}
}
@@ -280,6 +275,8 @@ test_idle(isc_task_t *task, isc_event_t *event) {
isc_time_t llim;
isc_interval_t interval;
UNUSED(task);
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
@@ -315,7 +312,7 @@ test_idle(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
isc_timer_destroy(&timer);
isc_task_shutdown(task);
test_shutdown();
}
/* timer type once idles out */
@@ -344,6 +341,8 @@ test_reset(isc_task_t *task, isc_event_t *event) {
isc_time_t llim;
isc_interval_t interval;
UNUSED(task);
int tick = atomic_fetch_add(&eventcnt, 1);
if (verbose) {
@@ -395,7 +394,7 @@ test_reset(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
isc_timer_destroy(&timer);
isc_task_shutdown(task);
test_shutdown();
}
}
@@ -458,7 +457,7 @@ tick_event(isc_task_t *task, isc_event_t *event) {
&interval, true);
subthread_assert_result_equal(result, ISC_R_SUCCESS);
isc_task_shutdown(task);
atomic_store(&shutdownflag, 1);
}
isc_event_free(&event);
@@ -466,6 +465,8 @@ tick_event(isc_task_t *task, isc_event_t *event) {
static void
once_event(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
if (verbose) {
print_message("# once_event\n");
}
@@ -475,24 +476,6 @@ once_event(isc_task_t *task, isc_event_t *event) {
*/
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);
}
@@ -513,9 +496,6 @@ purge(void **state) {
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);