summaryrefslogtreecommitdiffstats
path: root/bin/tests/tasks/t_tasks.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/tests/tasks/t_tasks.c')
-rw-r--r--bin/tests/tasks/t_tasks.c2293
1 files changed, 2293 insertions, 0 deletions
diff --git a/bin/tests/tasks/t_tasks.c b/bin/tests/tasks/t_tasks.c
new file mode 100644
index 0000000..b8a4d24
--- /dev/null
+++ b/bin/tests/tasks/t_tasks.c
@@ -0,0 +1,2293 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: t_tasks.c,v 1.40 2007/06/19 23:47:07 tbox Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h> /* uintptr_t */
+#endif
+#include <isc/condition.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <tests/t_api.h>
+
+
+#ifdef ISC_PLATFORM_USETHREADS
+isc_boolean_t threaded = ISC_TRUE;
+#else
+isc_boolean_t threaded = ISC_FALSE;
+#endif
+
+static int senders[4];
+
+static void
+require_threads(void) {
+ t_info("This test requires threads\n");
+ t_result(T_THREADONLY);
+ return;
+}
+
+static void
+t1_callback(isc_task_t *task, isc_event_t *event) {
+ int i;
+ int j;
+
+ UNUSED(task);
+
+ j = 0;
+
+ for (i = 0; i < 1000000; i++)
+ j += 100;
+
+ t_info("task %s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+static void
+t1_shutdown(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ t_info("shutdown %s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+static void
+my_tick(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ t_info("%s\n", (char *)event->ev_arg);
+ isc_event_free(&event);
+}
+
+/*
+ * Adapted from RTH's original task_test program
+ */
+
+static int
+t_tasks1(void) {
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *manager;
+ isc_task_t *task1;
+ isc_task_t *task2;
+ isc_task_t *task3;
+ isc_task_t *task4;
+ isc_event_t *event;
+ unsigned int workers;
+ isc_timermgr_t *timgr;
+ isc_timer_t *ti1;
+ isc_timer_t *ti2;
+ isc_result_t isc_result;
+ struct isc_time absolute;
+ struct isc_interval interval;
+
+ manager = NULL;
+ task1 = NULL;
+ task2 = NULL;
+ task3 = NULL;
+ task4 = NULL;
+ mctx = NULL;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+ if (workers < 1) {
+ t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &manager);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_create(manager, 0, &task1);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_create(manager, 0, &task2);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_create(manager, 0, &task3);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_create(manager, 0, &task4);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_onshutdown(task1, t1_shutdown, "1");
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_onshutdown(task2, t1_shutdown, "2");
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_onshutdown(task3, t1_shutdown, "3");
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_onshutdown(task4, t1_shutdown, "4");
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ timgr = NULL;
+ isc_result = isc_timermgr_create(mctx, &timgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_timermgr_create %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ ti1 = NULL;
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ isc_result = isc_timer_create(timgr, isc_timertype_ticker,
+ &absolute, &interval,
+ task1, my_tick, "tick", &ti1);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_timer_create %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ ti2 = NULL;
+ isc_time_settoepoch(&absolute);
+ isc_interval_set(&interval, 1, 0);
+ isc_result = isc_timer_create(timgr, isc_timertype_ticker,
+ &absolute, &interval,
+ task2, my_tick, "tock", &ti2);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_timer_create %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+
+ sleep(2);
+
+ /*
+ * Note: (void *)1 is used as a sender here, since some compilers
+ * don't like casting a function pointer to a (void *).
+ *
+ * In a real use, it is more likely the sender would be a
+ * structure (socket, timer, task, etc) but this is just a test
+ * program.
+ */
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task1, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "2",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task2, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "3",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task3, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "4",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task4, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "2",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task2, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "3",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task3, &event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "4",
+ sizeof(*event));
+ if (event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_send(task4, &event);
+
+ (void)isc_task_purge(task3, NULL, 0, 0);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+ isc_task_detach(&task4);
+
+ sleep(10);
+ isc_timer_detach(&ti1);
+ isc_timer_detach(&ti2);
+ isc_timermgr_destroy(&timgr);
+ isc_taskmgr_destroy(&manager);
+
+ isc_mem_destroy(&mctx);
+ return(T_PASS);
+}
+
+static const char *a1 = "The task subsystem can create and manage tasks";
+
+static void
+t1(void) {
+ int result;
+
+ t_assert("tasks", 1, T_REQUIRED, a1);
+ result = t_tasks1();
+ t_result(result);
+}
+
+#define T2_NTASKS 10000
+
+static isc_event_t *T2_event;
+static isc_taskmgr_t *T2_manager;
+static isc_mem_t *T2_mctx;
+static isc_condition_t T2_cv;
+static isc_mutex_t T2_mx;
+static int T2_done;
+static int T2_nprobs;
+static int T2_nfails;
+static int T2_ntasks;
+
+static void
+t2_shutdown(isc_task_t *task, isc_event_t *event) {
+
+ isc_result_t isc_result;
+
+ task = task; /* notused */
+
+ if (event->ev_arg != NULL) {
+ isc_task_destroy((isc_task_t**) &event->ev_arg);
+ }
+ else {
+ isc_result = isc_mutex_lock(&T2_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %d\n", isc_result);
+ ++T2_nprobs;
+ }
+
+ T2_done = 1;
+
+ isc_result = isc_condition_signal(&T2_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %d\n", isc_result);
+ ++T2_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T2_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %d\n", isc_result);
+ ++T2_nprobs;
+ }
+
+ isc_event_free(&T2_event);
+ isc_taskmgr_destroy(&T2_manager);
+ isc_mem_destroy(&T2_mctx);
+ }
+}
+
+static void
+t2_callback(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+ isc_task_t *newtask;
+
+ ++T2_ntasks;
+
+ if (T_debug && ((T2_ntasks % 100) == 0)) {
+ t_info("T2_ntasks %d\n", T2_ntasks);
+ }
+
+ if (event->ev_arg) {
+
+ event->ev_arg = (void *)(((uintptr_t) event->ev_arg) - 1);
+
+ /*
+ * Create a new task and forward the message.
+ */
+ newtask = NULL;
+ isc_result = isc_task_create(T2_manager, 0, &newtask);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ ++T2_nfails;
+ return;
+ }
+
+ isc_result = isc_task_onshutdown(newtask, t2_shutdown,
+ (void *)task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown failed %d\n",
+ isc_result);
+ ++T2_nfails;
+ return;
+ }
+
+ isc_task_send(newtask, &event);
+ } else {
+ /*
+ * Time to unwind, shutdown should perc back up.
+ */
+ isc_task_destroy(&task);
+ }
+}
+
+static int
+t_tasks2(void) {
+ uintptr_t ntasks;
+ int result;
+ char *p;
+ isc_event_t *event;
+ unsigned int workers;
+ isc_result_t isc_result;
+
+ T2_manager = NULL;
+ T2_done = 0;
+ T2_nprobs = 0;
+ T2_nfails = 0;
+ T2_ntasks = 0;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+ if (workers < 1) {
+ t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
+ return(T_UNRESOLVED);
+ }
+
+ p = t_getenv("ISC_TASKS_MIN");
+ if (p != NULL)
+ ntasks = atoi(p);
+ else
+ ntasks = T2_NTASKS;
+ if (ntasks == 0U) {
+ t_info("Bad config value for ISC_TASKS_MIN, %lu\n",
+ (unsigned long)ntasks);
+ return(T_UNRESOLVED);
+ }
+
+ t_info("Testing with %lu tasks\n", (unsigned long)ntasks);
+
+ isc_result = isc_mutex_init(&T2_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_init(&T2_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mem_create(0, 0, &T2_mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_taskmgr_create(T2_mctx, workers, 0, &T2_manager);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ T2_event = isc_event_allocate(T2_mctx, (void *)1, 1, t2_callback,
+ (void *)ntasks, sizeof(*event));
+ if (T2_event == NULL) {
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_lock(&T2_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ t2_callback(NULL, T2_event);
+
+ while (T2_done == 0) {
+ isc_result = isc_condition_wait(&T2_cv, &T2_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_wait failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+ }
+
+ result = T_UNRESOLVED;
+
+ if ((T2_nfails == 0) && (T2_nprobs == 0))
+ result = T_PASS;
+ else if (T2_nfails != 0)
+ result = T_FAIL;
+
+ return(result);
+}
+
+static const char *a2 = "The task subsystem can create ISC_TASKS_MIN tasks";
+
+static void
+t2(void) {
+ t_assert("tasks", 2, T_REQUIRED, a2);
+
+ if (threaded)
+ t_result(t_tasks2());
+ else
+ require_threads();
+}
+
+#define T3_NEVENTS 256
+
+static int T3_flag;
+static int T3_nevents;
+static int T3_nsdevents;
+static isc_mutex_t T3_mx;
+static isc_condition_t T3_cv;
+static int T3_nfails;
+static int T3_nprobs;
+
+static void
+t3_sde1(isc_task_t *task, isc_event_t *event) {
+ task = task;
+
+ if (T3_nevents != T3_NEVENTS) {
+ t_info("Some events were not processed\n");
+ ++T3_nprobs;
+ }
+ if (T3_nsdevents == 1) {
+ ++T3_nsdevents;
+ } else {
+ t_info("Shutdown events not processed in LIFO order\n");
+ ++T3_nfails;
+ }
+ isc_event_free(&event);
+}
+
+static void
+t3_sde2(isc_task_t *task, isc_event_t *event) {
+
+ task = task;
+
+ if (T3_nevents != T3_NEVENTS) {
+ t_info("Some events were not processed\n");
+ ++T3_nprobs;
+ }
+ if (T3_nsdevents == 0) {
+ ++T3_nsdevents;
+ } else {
+ t_info("Shutdown events not processed in LIFO order\n");
+ ++T3_nfails;
+ }
+ isc_event_free(&event);
+}
+
+static void
+t3_event1(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ task = task;
+
+ isc_result = isc_mutex_lock(&T3_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T3_nprobs;
+ }
+ while (T3_flag != 1) {
+ (void) isc_condition_wait(&T3_cv, &T3_mx);
+ }
+
+ isc_result = isc_mutex_unlock(&T3_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T3_nprobs;
+ }
+ isc_event_free(&event);
+}
+
+static void
+t3_event2(isc_task_t *task, isc_event_t *event) {
+ task = task;
+
+ ++T3_nevents;
+ isc_event_free(&event);
+}
+
+static int
+t_tasks3(void) {
+ int cnt;
+ int result;
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *tmgr;
+ isc_task_t *task;
+ unsigned int workers;
+ isc_event_t *event;
+ isc_result_t isc_result;
+ isc_eventtype_t event_type;
+
+ T3_flag = 0;
+ T3_nevents = 0;
+ T3_nsdevents = 0;
+ T3_nfails = 0;
+ T3_nprobs = 0;
+
+ event_type = 3;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+
+ mctx = NULL;
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %s\n",
+ isc_result_totext(isc_result));
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_init(&T3_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_init(&T3_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ tmgr = NULL;
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_lock(&T3_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ task = NULL;
+ isc_result = isc_task_create(tmgr, 0, &task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mutex_unlock(&T3_mx);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ /*
+ * This event causes the task to wait on T3_cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, t3_event1,
+ NULL, sizeof(*event));
+ isc_task_send(task, &event);
+
+ /*
+ * Now we fill up the task's event queue with some events.
+ */
+ for (cnt = 0; cnt < T3_NEVENTS; ++cnt) {
+ event = isc_event_allocate(mctx, &senders[1], event_type,
+ t3_event2, NULL, sizeof(*event));
+ isc_task_send(task, &event);
+ }
+
+ /*
+ * Now we register two shutdown events.
+ */
+ isc_result = isc_task_onshutdown(task, t3_sde1, NULL);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_send failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mutex_unlock(&T3_mx);
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_task_onshutdown(task, t3_sde2, NULL);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_send failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mutex_unlock(&T3_mx);
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_task_shutdown(task);
+
+ /*
+ * Now we free the task by signaling T3_cv.
+ */
+ T3_flag = 1;
+ isc_result = isc_condition_signal(&T3_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_send failed %s\n",
+ isc_result_totext(isc_result));
+ ++T3_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T3_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_send failed %s\n",
+ isc_result_totext(isc_result));
+ ++T3_nprobs;
+ }
+
+
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+
+ if (T3_nsdevents != 2) {
+ t_info("T3_nsdevents == %d, expected 2\n", T3_nsdevents);
+ ++T3_nfails;
+ }
+
+ if (T3_nevents != T3_nevents) {
+ t_info("T3_nevents == %d, expected 2\n", T3_nevents);
+ ++T3_nfails;
+ }
+
+ result = T_UNRESOLVED;
+
+ if (T3_nfails != 0)
+ result = T_FAIL;
+ else if ((T3_nfails == 0) && (T3_nprobs == 0))
+ result = T_PASS;
+
+ return(result);
+}
+
+static const char *a3 = "When isc_task_shutdown() is called, any shutdown "
+ "events that have been requested via prior "
+ "isc_task_onshutdown() calls are posted in "
+ "LIFO order.";
+static void
+t3(void) {
+ t_assert("tasks", 3, T_REQUIRED, a3);
+
+ if (threaded)
+ t_result(t_tasks3());
+ else
+ require_threads();
+}
+
+static isc_mutex_t T4_mx;
+static isc_condition_t T4_cv;
+static int T4_flag;
+static int T4_nprobs;
+static int T4_nfails;
+
+static void
+t4_event1(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ UNUSED(task);
+
+ isc_result = isc_mutex_lock(&T4_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T4_nprobs;
+ }
+ while (T4_flag != 1) {
+ (void) isc_condition_wait(&T4_cv, &T4_mx);
+ }
+
+ isc_result = isc_mutex_unlock(&T4_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T4_nprobs;
+ }
+ isc_event_free(&event);
+}
+
+static void
+t4_sde(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ /*
+ * No-op.
+ */
+
+ isc_event_free(&event);
+}
+
+static int
+t_tasks4(void) {
+ int result;
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *tmgr;
+ isc_task_t *task;
+ unsigned int workers;
+ isc_result_t isc_result;
+ isc_eventtype_t event_type;
+ isc_event_t *event;
+
+ T4_nprobs = 0;
+ T4_nfails = 0;
+ T4_flag = 0;
+
+ result = T_UNRESOLVED;
+ event_type = 4;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+
+ mctx = NULL;
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %s\n",
+ isc_result_totext(isc_result));
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_init(&T4_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_init(&T4_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T4_mx);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ tmgr = NULL;
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T4_mx);
+ isc_condition_destroy(&T4_cv);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_lock(&T4_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T4_mx);
+ isc_condition_destroy(&T4_cv);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ task = NULL;
+ isc_result = isc_task_create(tmgr, 0, &task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T4_mx);
+ isc_condition_destroy(&T4_cv);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ /*
+ * This event causes the task to wait on T4_cv.
+ */
+ event = isc_event_allocate(mctx, &senders[1], event_type, t4_event1,
+ NULL, sizeof(*event));
+ isc_task_send(task, &event);
+
+ isc_task_shutdown(task);
+
+ isc_result = isc_task_onshutdown(task, t4_sde, NULL);
+ if (isc_result != ISC_R_SHUTTINGDOWN) {
+ t_info("isc_task_onshutdown returned %s\n",
+ isc_result_totext(isc_result));
+ ++T4_nfails;
+ }
+
+ /*
+ * Release the task.
+ */
+ T4_flag = 1;
+
+ isc_result = isc_condition_signal(&T4_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++T4_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T4_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T4_nprobs;
+ }
+
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ isc_condition_destroy(&T4_cv);
+ DESTROYLOCK(&T4_mx);
+
+ result = T_UNRESOLVED;
+
+ if (T4_nfails != 0)
+ result = T_FAIL;
+ else if ((T4_nfails == 0) && (T4_nprobs == 0))
+ result = T_PASS;
+
+ return(result);
+}
+
+static const char *a4 =
+ "After isc_task_shutdown() has been called, any call to "
+ "isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.";
+
+static void
+t4(void) {
+ t_assert("tasks", 4, T_REQUIRED, a4);
+
+ if (threaded)
+ t_result(t_tasks4());
+ else
+ require_threads();
+}
+
+static int T7_nprobs;
+static int T7_eflag;
+static int T7_sdflag;
+static isc_mutex_t T7_mx;
+static isc_condition_t T7_cv;
+
+static int T7_nfails;
+
+static void
+t7_event1(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++T7_eflag;
+
+ isc_event_free(&event);
+}
+
+static void
+t7_sde(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ UNUSED(task);
+
+ isc_result = isc_mutex_lock(&T7_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T7_nprobs;
+ }
+
+ ++T7_sdflag;
+
+ isc_result = isc_condition_signal(&T7_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++T7_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T7_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T7_nprobs;
+ }
+
+ isc_event_free(&event);
+}
+
+static int
+t_tasks7(void) {
+ int result;
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *tmgr;
+ isc_task_t *task;
+ unsigned int workers;
+ isc_result_t isc_result;
+ isc_eventtype_t event_type;
+ isc_event_t *event;
+ isc_time_t now;
+ isc_interval_t interval;
+
+ T7_nprobs = 0;
+ T7_nfails = 0;
+ T7_sdflag = 0;
+ T7_eflag = 0;
+
+ result = T_UNRESOLVED;
+ event_type = 7;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+
+ mctx = NULL;
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %s\n",
+ isc_result_totext(isc_result));
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_init(&T7_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_init(&T7_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ tmgr = NULL;
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_lock(&T7_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_FAIL);
+ }
+
+ task = NULL;
+ isc_result = isc_task_create(tmgr, 0, &task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_FAIL);
+ }
+
+ isc_result = isc_task_onshutdown(task, t7_sde, NULL);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown returned %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ event = isc_event_allocate(mctx, &senders[1], event_type, t7_event1,
+ NULL, sizeof(*event));
+ isc_task_send(task, &event);
+
+ isc_task_shutdown(task);
+
+ interval.seconds = 5;
+ interval.nanoseconds = 0;
+
+ while (T7_sdflag == 0) {
+ isc_result = isc_time_nowplusinterval(&now, &interval);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_time_nowplusinterval failed %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_waituntil(&T7_cv, &T7_mx, &now);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_waituntil returned %s\n",
+ isc_result_totext(isc_result));
+ DESTROYLOCK(&T7_mx);
+ isc_condition_destroy(&T7_cv);
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ return(T_FAIL);
+ }
+ }
+
+ isc_result = isc_mutex_unlock(&T7_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T7_nprobs;
+ }
+
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ isc_condition_destroy(&T7_cv);
+ DESTROYLOCK(&T7_mx);
+
+ result = T_UNRESOLVED;
+
+ if (T7_eflag == 0)
+ ++T7_nfails;
+
+ if (T7_nfails != 0)
+ result = T_FAIL;
+ else if ((T7_nfails == 0) && (T7_nprobs == 0))
+ result = T_PASS;
+
+ return(result);
+}
+
+static const char *a7 = "A call to isc_task_create() creates a task that can "
+ "receive events.";
+
+static void
+t7(void) {
+ t_assert("tasks", 7, T_REQUIRED, a7);
+
+ if (threaded)
+ t_result(t_tasks7());
+ else
+ require_threads();
+}
+
+#define T10_SENDERCNT 3
+#define T10_TYPECNT 4
+#define T10_TAGCNT 5
+#define T10_NEVENTS (T10_SENDERCNT*T10_TYPECNT*T10_TAGCNT)
+#define T_CONTROL 99999
+
+static int T10_nprobs;
+static int T10_nfails;
+static int T10_startflag;
+static int T10_shutdownflag;
+static int T10_eventcnt;
+static isc_mutex_t T10_mx;
+static isc_condition_t T10_cv;
+
+static void *T10_purge_sender;
+static isc_eventtype_t T10_purge_type_first;
+static isc_eventtype_t T10_purge_type_last;
+static void *T10_purge_tag;
+static int T10_testrange;
+
+static void
+t10_event1(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ task = task;
+
+ isc_result = isc_mutex_lock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+
+ while (T10_startflag == 0) {
+ isc_result = isc_condition_wait(&T10_cv, &T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+ }
+
+ isc_result = isc_mutex_unlock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+t10_event2(isc_task_t *task, isc_event_t *event) {
+
+ int sender_match;
+ int type_match;
+ int tag_match;
+
+ task = task;
+
+ sender_match = 0;
+ type_match = 0;
+ tag_match = 0;
+
+ if (T_debug) {
+ t_info("Event %p,%d,%p,%s\n",
+ event->ev_sender,
+ (int)event->ev_type,
+ event->ev_tag,
+ event->ev_attributes & ISC_EVENTATTR_NOPURGE ?
+ "NP" : "P");
+ }
+
+ if ((T10_purge_sender == NULL) ||
+ (T10_purge_sender == event->ev_sender)) {
+ sender_match = 1;
+ }
+ if (T10_testrange == 0) {
+ if (T10_purge_type_first == event->ev_type) {
+ type_match = 1;
+ }
+ } else {
+ if ((T10_purge_type_first <= event->ev_type) &&
+ (event->ev_type <= T10_purge_type_last)) {
+ type_match = 1;
+ }
+ }
+ if ((T10_purge_tag == NULL) ||
+ (T10_purge_tag == event->ev_tag)) {
+ tag_match = 1;
+ }
+
+ if (sender_match && type_match && tag_match) {
+ if (event->ev_attributes & ISC_EVENTATTR_NOPURGE) {
+ t_info("event %p,%d,%p matched but was not purgable\n",
+ event->ev_sender, (int)event->ev_type,
+ event->ev_tag);
+ ++T10_eventcnt;
+ } else {
+ t_info("*** event %p,%d,%p not purged\n",
+ event->ev_sender, (int)event->ev_type,
+ event->ev_tag);
+ }
+ } else {
+ ++T10_eventcnt;
+ }
+ isc_event_free(&event);
+}
+
+
+static void
+t10_sde(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ task = task;
+
+ isc_result = isc_mutex_lock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+
+ ++T10_shutdownflag;
+
+ isc_result = isc_condition_signal(&T10_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T10_nprobs;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+t_taskpurge_x(int sender, int type, int tag, void *purge_sender,
+ int purge_type_first, int purge_type_last, void *purge_tag,
+ int exp_nevents, int *nfails, int *nprobs, int testrange)
+{
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *tmgr;
+ isc_task_t *task;
+ unsigned int workers;
+ isc_result_t isc_result;
+ isc_event_t *event;
+ isc_time_t now;
+ isc_interval_t interval;
+ int sender_cnt;
+ int type_cnt;
+ int tag_cnt;
+ int event_cnt;
+ int cnt;
+ int nevents;
+ isc_event_t *eventtab[T10_NEVENTS];
+
+
+ T10_startflag = 0;
+ T10_shutdownflag = 0;
+ T10_eventcnt = 0;
+ T10_purge_sender = purge_sender;
+ T10_purge_type_first = (isc_eventtype_t) purge_type_first;
+ T10_purge_type_last = (isc_eventtype_t) purge_type_last;
+ T10_purge_tag = purge_tag;
+ T10_testrange = testrange;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+
+ mctx = NULL;
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %s\n",
+ isc_result_totext(isc_result));
+ ++*nprobs;
+ return;
+ }
+
+ isc_result = isc_mutex_init(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ ++*nprobs;
+ return;
+ }
+
+ isc_result = isc_condition_init(&T10_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ ++*nprobs;
+ return;
+ }
+
+ tmgr = NULL;
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nprobs;
+ return;
+ }
+
+ task = NULL;
+ isc_result = isc_task_create(tmgr, 0, &task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nprobs;
+ return;
+ }
+
+ isc_result = isc_task_onshutdown(task, t10_sde, NULL);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown returned %s\n",
+ isc_result_totext(isc_result));
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nprobs;
+ return;
+ }
+
+ /*
+ * Block the task on T10_cv.
+ */
+ event = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)T_CONTROL,
+ t10_event1, NULL, sizeof(*event));
+
+ isc_task_send(task, &event);
+
+ /*
+ * Fill the task's queue with some messages with varying
+ * sender, type, tag, and purgable attribute values.
+ */
+
+ event_cnt = 0;
+ for (sender_cnt = 0; sender_cnt < T10_SENDERCNT; ++sender_cnt) {
+ for (type_cnt = 0; type_cnt < T10_TYPECNT; ++type_cnt) {
+ for (tag_cnt = 0; tag_cnt < T10_TAGCNT; ++tag_cnt) {
+ eventtab[event_cnt] =
+ isc_event_allocate(mctx,
+ &senders[sender + sender_cnt],
+ (isc_eventtype_t)(type + type_cnt),
+ t10_event2, NULL, sizeof(*event));
+
+ eventtab[event_cnt]->ev_tag =
+ (void *)((uintptr_t)tag + tag_cnt);
+
+ /*
+ * Make all odd message non-purgable.
+ */
+ if ((sender_cnt % 2) && (type_cnt %2) &&
+ (tag_cnt %2))
+ eventtab[event_cnt]->ev_attributes |=
+ ISC_EVENTATTR_NOPURGE;
+ ++event_cnt;
+ }
+ }
+ }
+
+ for (cnt = 0; cnt < event_cnt; ++cnt)
+ isc_task_send(task, &eventtab[cnt]);
+
+ if (T_debug)
+ t_info("%d events queued\n", cnt);
+
+ if (testrange == 0) {
+ /*
+ * We're testing isc_task_purge.
+ */
+ nevents = isc_task_purge(task, purge_sender,
+ (isc_eventtype_t)purge_type_first,
+ purge_tag);
+ if (nevents != exp_nevents) {
+ t_info("*** isc_task_purge returned %d, expected %d\n",
+ nevents, exp_nevents);
+ ++*nfails;
+ } else if (T_debug)
+ t_info("isc_task_purge returned %d\n", nevents);
+ } else {
+ /*
+ * We're testing isc_task_purgerange.
+ */
+ nevents = isc_task_purgerange(task, purge_sender,
+ (isc_eventtype_t)purge_type_first,
+ (isc_eventtype_t)purge_type_last,
+ purge_tag);
+ if (nevents != exp_nevents) {
+ t_info("*** isc_task_purgerange returned %d, "
+ "expected %d\n", nevents, exp_nevents);
+ ++*nfails;
+ } else if (T_debug)
+ t_info("isc_task_purgerange returned %d\n", nevents);
+ }
+
+ isc_result = isc_mutex_lock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nprobs;
+ return;
+ }
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ T10_startflag = 1;
+ isc_result = isc_condition_signal(&T10_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++*nprobs;
+ }
+
+ isc_task_shutdown(task);
+
+ interval.seconds = 5;
+ interval.nanoseconds = 0;
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (T10_shutdownflag == 0) {
+ isc_result = isc_time_nowplusinterval(&now, &interval);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_time_nowplusinterval failed %s\n",
+ isc_result_totext(isc_result));
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nprobs;
+ return;
+ }
+
+ isc_result = isc_condition_waituntil(&T10_cv, &T10_mx, &now);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_waituntil returned %s\n",
+ isc_result_totext(isc_result));
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+ ++*nfails;
+ return;
+ }
+ }
+
+ isc_result = isc_mutex_unlock(&T10_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++*nprobs;
+ }
+
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T10_mx);
+ isc_condition_destroy(&T10_cv);
+
+ if (T_debug)
+ t_info("task processed %d events\n", T10_eventcnt);
+
+ if ((T10_eventcnt + nevents) != event_cnt) {
+ t_info("*** processed %d, purged %d, total %d\n",
+ T10_eventcnt, nevents, event_cnt);
+ ++*nfails;
+ }
+}
+
+static int
+t_tasks10(void) {
+ int result;
+
+ T10_nprobs = 0;
+ T10_nfails = 0;
+
+ /*
+ * Try purging on a specific sender.
+ */
+ t_info("testing purge on 2,4,8 expecting 1\n");
+ t_taskpurge_x(1, 4, 7, &senders[2], 4, 4, (void *)8, 1, &T10_nfails,
+ &T10_nprobs, 0);
+
+ /*
+ * Try purging on all senders.
+ */
+ t_info("testing purge on 0,4,8 expecting 3\n");
+ t_taskpurge_x(1, 4, 7, NULL, 4, 4, (void *)8, 3, &T10_nfails,
+ &T10_nprobs, 0);
+
+ /*
+ * Try purging on all senders, specified type, all tags.
+ */
+ t_info("testing purge on 0,4,0 expecting 15\n");
+ t_taskpurge_x(1, 4, 7, NULL, 4, 4, NULL, 15, &T10_nfails,
+ &T10_nprobs, 0);
+
+ /*
+ * Try purging on a specified tag, no such type.
+ */
+ t_info("testing purge on 0,99,8 expecting 0\n");
+ t_taskpurge_x(1, 4, 7, NULL, 99, 99, (void *)8, 0, &T10_nfails,
+ &T10_nprobs, 0);
+
+ /*
+ * Try purging on specified sender, type, all tags.
+ */
+ t_info("testing purge on 0,5,0 expecting 5\n");
+ t_taskpurge_x(1, 4, 7, &senders[3], 5, 5, NULL, 5, &T10_nfails,
+ &T10_nprobs, 0);
+
+ result = T_UNRESOLVED;
+
+ if ((T10_nfails == 0) && (T10_nprobs == 0))
+ result = T_PASS;
+ else if (T10_nfails != 0)
+ result = T_FAIL;
+
+ return(result);
+}
+
+static const char *a10 =
+ "A call to isc_task_purge(task, sender, type, tag) "
+ "purges all events of type 'type' and with tag 'tag' "
+ "not marked as unpurgable from sender from the task's "
+ "queue and returns the number of events purged.";
+
+static void
+t10(void) {
+ t_assert("tasks", 10, T_REQUIRED, a10);
+
+ if (threaded)
+ t_result(t_tasks10());
+ else
+ require_threads();
+}
+
+static int T11_nprobs;
+static int T11_nfails;
+static int T11_startflag;
+static int T11_shutdownflag;
+static int T11_eventcnt;
+static isc_mutex_t T11_mx;
+static isc_condition_t T11_cv;
+
+static void
+t11_event1(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ task = task;
+
+ isc_result = isc_mutex_lock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ while (T11_startflag == 0) {
+ isc_result = isc_condition_wait(&T11_cv, &T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+ }
+
+ isc_result = isc_mutex_unlock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+t11_event2(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+
+ ++T11_eventcnt;
+ isc_event_free(&event);
+}
+
+
+static void
+t11_sde(isc_task_t *task, isc_event_t *event) {
+ isc_result_t isc_result;
+
+ UNUSED(task);
+
+ isc_result = isc_mutex_lock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ ++T11_shutdownflag;
+
+ isc_result = isc_condition_signal(&T11_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_result = isc_mutex_unlock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_event_free(&event);
+}
+
+static int
+t_tasks11(int purgable) {
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *tmgr;
+ isc_task_t *task;
+ isc_boolean_t rval;
+ unsigned int workers;
+ isc_result_t isc_result;
+ isc_event_t *event1;
+ isc_event_t *event2, *event2_clone;
+ isc_time_t now;
+ isc_interval_t interval;
+ int result;
+
+ T11_startflag = 0;
+ T11_shutdownflag = 0;
+ T11_eventcnt = 0;
+
+ workers = 2;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+
+ mctx = NULL;
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %s\n",
+ isc_result_totext(isc_result));
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mutex_init(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_condition_init(&T11_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_init failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T11_mx);
+ return(T_UNRESOLVED);
+ }
+
+ tmgr = NULL;
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T11_mx);
+ isc_condition_destroy(&T11_cv);
+ return(T_UNRESOLVED);
+ }
+
+ task = NULL;
+ isc_result = isc_task_create(tmgr, 0, &task);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %s\n",
+ isc_result_totext(isc_result));
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T11_mx);
+ isc_condition_destroy(&T11_cv);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_task_onshutdown(task, t11_sde, NULL);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_onshutdown returned %s\n",
+ isc_result_totext(isc_result));
+ isc_task_destroy(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T11_mx);
+ isc_condition_destroy(&T11_cv);
+ return(T_UNRESOLVED);
+ }
+
+ /*
+ * Block the task on T11_cv.
+ */
+ event1 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ t11_event1, NULL, sizeof(*event1));
+
+ isc_task_send(task, &event1);
+
+ event2 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
+ t11_event2, NULL, sizeof(*event2));
+ event2_clone = event2;
+ if (purgable)
+ event2->ev_attributes &= ~ISC_EVENTATTR_NOPURGE;
+ else
+ event2->ev_attributes |= ISC_EVENTATTR_NOPURGE;
+
+ isc_task_send(task, &event2);
+
+ rval = isc_task_purgeevent(task, event2_clone);
+ if (rval != (purgable ? ISC_TRUE : ISC_FALSE)) {
+ t_info("isc_task_purgeevent returned %s, expected %s\n",
+ (rval ? "ISC_TRUE" : "ISC_FALSE"),
+ (purgable ? "ISC_TRUE" : "ISC_FALSE"));
+ ++T11_nfails;
+ }
+
+ isc_result = isc_mutex_lock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_lock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ /*
+ * Unblock the task, allowing event processing.
+ */
+ T11_startflag = 1;
+ isc_result = isc_condition_signal(&T11_cv);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_signal failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_task_shutdown(task);
+
+ interval.seconds = 5;
+ interval.nanoseconds = 0;
+
+ /*
+ * Wait for shutdown processing to complete.
+ */
+ while (T11_shutdownflag == 0) {
+ isc_result = isc_time_nowplusinterval(&now, &interval);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_time_nowplusinterval failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_result = isc_condition_waituntil(&T11_cv, &T11_mx, &now);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_condition_waituntil returned %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+ }
+
+ isc_result = isc_mutex_unlock(&T11_mx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mutex_unlock failed %s\n",
+ isc_result_totext(isc_result));
+ ++T11_nprobs;
+ }
+
+ isc_task_detach(&task);
+ isc_taskmgr_destroy(&tmgr);
+ isc_mem_destroy(&mctx);
+ DESTROYLOCK(&T11_mx);
+ isc_condition_destroy(&T11_cv);
+
+ if (T11_eventcnt != (purgable ? 0 : 1)) {
+ t_info("Event was %s purged\n",
+ (purgable ? "not" : "unexpectedly"));
+ ++T11_nfails;
+ }
+
+ result = T_UNRESOLVED;
+
+ if ((T11_nfails == 0) && (T11_nprobs == 0))
+ result = T_PASS;
+ else if (T11_nfails)
+ result = T_FAIL;
+
+ return(result);
+}
+
+static const char *a11 =
+ "When the event is marked as purgable, a call to "
+ "isc_task_purgeevent(task, event) purges the event 'event' "
+ "from the task's queue and returns ISC_TRUE.";
+
+static void
+t11(void) {
+ t_assert("tasks", 11, T_REQUIRED, a11);
+
+ if (threaded)
+ t_result(t_tasks11(1));
+ else
+ require_threads();
+}
+
+static const char *a12 =
+ "When the event is not marked as purgable, a call to "
+ "isc_task_purgeevent(task, event) does not purge the "
+ "event 'event' from the task's queue and returns "
+ "ISC_FALSE.";
+
+static int
+t_tasks12(void) {
+ return(t_tasks11(0));
+}
+
+static void
+t12(void) {
+ t_assert("tasks", 12, T_REQUIRED, a12);
+
+ if (threaded)
+ t_result(t_tasks12());
+ else
+ require_threads();
+}
+
+static int T13_nfails;
+static int T13_nprobs;
+
+static const char *a13 =
+ "A call to "
+ "isc_event_purgerange(task, sender, first, last, tag) "
+ "purges all events not marked unpurgable from "
+ "sender 'sender' and of type within the range 'first' "
+ "to 'last' inclusive from the task's event queue and "
+ "returns the number of tasks purged.";
+
+static int
+t_tasks13(void) {
+ int result;
+
+ T13_nfails = 0;
+ T13_nprobs = 0;
+
+ /*
+ * First let's try the same cases we used in t10.
+ */
+
+ /*
+ * Try purging on a specific sender.
+ */
+ t_info("testing purge on 2,4,8 expecting 1\n");
+ t_taskpurge_x(1, 4, 7, &senders[2], 4, 4, (void *)8, 1,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on all senders.
+ */
+ t_info("testing purge on 0,4,8 expecting 3\n");
+ t_taskpurge_x(1, 4, 7, NULL, 4, 4, (void *)8, 3,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on all senders, specified type, all tags.
+ */
+ t_info("testing purge on 0,4,0 expecting 15\n");
+ t_taskpurge_x(1, 4, 7, NULL, 4, 4, NULL, 15, &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on a specified tag, no such type.
+ */
+ t_info("testing purge on 0,99,8 expecting 0\n");
+ t_taskpurge_x(1, 4, 7, NULL, 99, 99, (void *)8, 0,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on specified sender, type, all tags.
+ */
+ t_info("testing purge on 3,5,0 expecting 5\n");
+ t_taskpurge_x(1, 4, 7, &senders[3], 5, 5, 0, 5, &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Now let's try some ranges.
+ */
+
+ t_info("testing purgerange on 2,4-5,8 expecting 2\n");
+ t_taskpurge_x(1, 4, 7, &senders[2], 4, 5, (void *)8, 1,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on all senders.
+ */
+ t_info("testing purge on 0,4-5,8 expecting 5\n");
+ t_taskpurge_x(1, 4, 7, NULL, 4, 5, (void *)8, 5,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on all senders, specified type, all tags.
+ */
+ t_info("testing purge on 0,5-6,0 expecting 28\n");
+ t_taskpurge_x(1, 4, 7, NULL, 5, 6, NULL, 28, &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on a specified tag, no such type.
+ */
+ t_info("testing purge on 0,99-101,8 expecting 0\n");
+ t_taskpurge_x(1, 4, 7, NULL, 99, 101, (void *)8, 0,
+ &T13_nfails, &T13_nprobs, 1);
+
+ /*
+ * Try purging on specified sender, type, all tags.
+ */
+ t_info("testing purge on 3,5-6,0 expecting 10\n");
+ t_taskpurge_x(1, 4, 7, &senders[3], 5, 6, NULL, 10, &T13_nfails,
+ &T13_nprobs, 1);
+
+ result = T_UNRESOLVED;
+
+ if ((T13_nfails == 0) && (T13_nprobs == 0))
+ result = T_PASS;
+ else if (T13_nfails)
+ result = T_FAIL;
+
+ return (result);
+}
+
+static void
+t13(void) {
+ t_assert("tasks", 13, T_REQUIRED, a13);
+
+ if (threaded)
+ t_result(t_tasks13());
+ else
+ require_threads();
+}
+
+#define T14_NTASKS 10
+#define T14_EXCLTASK 6
+
+int t14_exclusiveerror = ISC_R_SUCCESS;
+int t14_error = 0;
+int t14_done = 0;
+
+int spin(int n);
+
+int t14_active[T14_NTASKS];
+
+static void
+t14_callback(isc_task_t *task, isc_event_t *event) {
+ int taskno = *(int *)(event->ev_arg);
+
+
+ t_info("task enter %d\n", taskno);
+ if (taskno == T14_EXCLTASK) {
+ int i;
+ t14_exclusiveerror = isc_task_beginexclusive(task);
+ if (t14_exclusiveerror == ISC_R_SUCCESS)
+ t_info("task %d got exclusive access\n", taskno);
+ else
+ t_info("task %d failed to got exclusive access: %d\n",
+ taskno, t14_exclusiveerror);
+ for (i = 0; i < T14_NTASKS; i++) {
+ t_info("task %d state %d\n", i , t14_active[i]);
+ if (t14_active[i])
+ t14_error++;
+ }
+ isc_task_endexclusive(task);
+ t14_done = 1;
+ } else {
+ t14_active[taskno]++;
+ (void) spin(10000000);
+ t14_active[taskno]--;
+ }
+ t_info("task exit %d\n", taskno);
+ if (t14_done) {
+ isc_mem_put(event->ev_destroy_arg, event->ev_arg, sizeof (int));
+ isc_event_free(&event);
+ } else {
+ isc_task_send(task, &event);
+ }
+}
+
+int spin(int n) {
+ int i;
+ int r = 0;
+ for (i = 0; i < n; i++) {
+ r += i;
+ if (r > 1000000)
+ r = 0;
+ }
+ return (r);
+}
+
+static int
+t_tasks14(void) {
+ char *p;
+ isc_mem_t *mctx;
+ isc_taskmgr_t *manager;
+ isc_task_t *tasks[T14_NTASKS];
+ unsigned int workers;
+ isc_result_t isc_result;
+ int i;
+
+ manager = NULL;
+ mctx = NULL;
+
+ for (i = 0; i < T14_NTASKS; i++)
+ tasks[i] = NULL;
+
+ workers = 4;
+ p = t_getenv("ISC_TASK_WORKERS");
+ if (p != NULL)
+ workers = atoi(p);
+ if (workers < 1) {
+ t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_mem_create(0, 0, &mctx);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_mem_create failed %d\n", isc_result);
+ return(T_UNRESOLVED);
+ }
+
+ isc_result = isc_taskmgr_create(mctx, workers, 0, &manager);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_taskmgr_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ for (i = 0; i < T14_NTASKS; i++) {
+ isc_event_t *event;
+ int *v;
+
+ isc_result = isc_task_create(manager, 0, &tasks[i]);
+ if (isc_result != ISC_R_SUCCESS) {
+ t_info("isc_task_create failed %d\n", isc_result);
+ return(T_FAIL);
+ }
+
+ v = isc_mem_get(mctx, sizeof *v);
+ if (v == NULL) {
+ isc_task_detach(&tasks[i]);
+ t_info("isc_mem_get failed\n");
+ return(T_FAIL);
+ }
+ *v = i;
+
+ event = isc_event_allocate(mctx, NULL, 1, t14_callback,
+ v, sizeof(*event));
+ if (event == NULL) {
+ isc_mem_put(mctx, v, sizeof *v);
+ t_info("isc_event_allocate failed\n");
+ return(T_UNRESOLVED);
+ }
+ isc_task_send(tasks[i], &event);
+ }
+
+ for (i = 0; i < T14_NTASKS; i++) {
+ isc_task_detach(&tasks[i]);
+ }
+
+ isc_taskmgr_destroy(&manager);
+
+ if (t14_exclusiveerror != ISC_R_SUCCESS || t14_error) {
+ if (t14_exclusiveerror != ISC_R_SUCCESS)
+ t_info("isc_task_beginexclusive() failed\n");
+ if (t14_error)
+ t_info("mutual access occurred\n");
+ return(T_FAIL);
+ }
+
+ isc_mem_destroy(&mctx);
+ return(T_PASS);
+}
+
+static void
+t14(void) {
+ int result;
+
+ t_assert("tasks", 14, T_REQUIRED,
+ "isc_task_beginexclusive() gets exclusive access");
+ result = t_tasks14();
+ t_result(result);
+}
+
+testspec_t T_testlist[] = {
+ { t1, "basic task subsystem" },
+ { t2, "maxtasks" },
+ { t3, "isc_task_shutdown" },
+ { t4, "isc_task_shutdown" },
+ { t7, "isc_task_create" },
+ { t10, "isc_task_purge" },
+ { t11, "isc_task_purgeevent" },
+ { t12, "isc_task_purgeevent" },
+ { t13, "isc_task_purgerange" },
+ { t14, "isc_task_beginexclusive" },
+ { NULL, NULL }
+};