minix/external/bsd/bind/dist/bin/tests/tasks/t_tasks.c
David van Moolenbroek 00b67f09dd Import NetBSD named(8)
Also known as ISC bind.  This import adds utilities such as host(1),
dig(1), and nslookup(1), as well as many other tools and libraries.

Change-Id: I035ca46e64f1965d57019e773f4ff0ef035e4aa3
2017-03-21 22:00:06 +00:00

2384 lines
54 KiB
C

/* $NetBSD: t_tasks.c,v 1.7 2014/12/10 04:37:54 christos Exp $ */
/*
* Copyright (C) 2004, 2005, 2007, 2009, 2011, 2013, 2014 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.49 2011/07/27 07:45:55 marka 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 char one[] = "1";
static char two[] = "2";
static char three[] = "3";
static char four[] = "4";
static char tick[] = "tick";
static char tock[] = "tock";
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;
isc_time_t absolute;
isc_interval_t 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, one);
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, two);
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, three);
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, four);
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);
}
#ifndef WIN32
sleep(2);
#else
Sleep(2000);
#endif
/*
* 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, one,
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, one,
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, one,
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, one,
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, one,
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, one,
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, one,
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, one,
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, one,
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, two,
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, three,
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, four,
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, two,
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, three,
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, four,
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);
#ifndef WIN32
sleep(10);
#else
Sleep(10000);
#endif
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, "%s", 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;
UNUSED(task);
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, "%s", 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) {
UNUSED(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) {
UNUSED(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;
UNUSED(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) {
UNUSED(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));
(void) 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));
if (event == NULL) {
t_info("isc_event_allocate failed\n");
(void) isc_mutex_unlock(&T3_mx);
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
return(T_UNRESOLVED);
}
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));
if (event == NULL) {
t_info("isc_event_allocate failed\n");
(void) isc_mutex_unlock(&T3_mx);
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
return(T_UNRESOLVED);
}
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));
(void) 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));
(void) 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_condition_signal 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_mutex_unlock 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;
}
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, "%s", 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;
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);
(void) 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);
(void) 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);
(void) 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));
if (event == NULL) {
t_info("isc_event_allocate failed\n");
DESTROYLOCK(&T4_mx);
isc_task_destroy(&task);
(void) isc_condition_destroy(&T4_cv);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
return(T_UNRESOLVED);
}
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);
(void) 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, "%s", 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;
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);
(void) 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);
(void) 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);
(void) 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);
(void) 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));
if (event == NULL) {
t_info("isc_event_allocate failed\n");
DESTROYLOCK(&T7_mx);
(void) isc_condition_destroy(&T7_cv);
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
return(T_UNRESOLVED);
}
isc_task_send(task, &event);
isc_task_shutdown(task);
isc_interval_set(&interval, 5, 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);
(void) 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);
(void) 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);
(void) 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, "%s", 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;
UNUSED(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;
UNUSED(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;
UNUSED(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);
(void) 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);
(void) 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);
(void) 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));
if (event == NULL) {
t_info("isc_event_allocate failed\n");
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
DESTROYLOCK(&T10_mx);
(void) isc_condition_destroy(&T10_cv);
++*nprobs;
return;
}
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));
if (eventtab[event_cnt] == NULL) {
t_info("isc_event_allocate failed\n");
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
DESTROYLOCK(&T10_mx);
(void) isc_condition_destroy(&T10_cv);
++*nprobs;
return;
}
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);
(void) 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);
isc_interval_set(&interval, 5, 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);
(void) 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);
(void) 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);
(void) 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, "%s", 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;
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;
}
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);
(void) 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);
(void) 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);
(void) 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));
if (event1 == NULL) {
t_info("isc_event_allocate failed\n");
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
DESTROYLOCK(&T11_mx);
(void) isc_condition_destroy(&T11_cv);
return(T_UNRESOLVED);
}
isc_task_send(task, &event1);
event2 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
t11_event2, NULL, sizeof(*event2));
if (event2 == NULL) {
t_info("isc_event_allocate failed\n");
isc_task_destroy(&task);
isc_taskmgr_destroy(&tmgr);
isc_mem_destroy(&mctx);
DESTROYLOCK(&T11_mx);
(void) isc_condition_destroy(&T11_cv);
return(T_UNRESOLVED);
}
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);
isc_interval_set(&interval, 5, 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);
(void) 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, "%s", 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, "%s", 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, "%s", 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, "%s",
"isc_task_beginexclusive() gets exclusive access");
result = t_tasks14();
t_result(result);
}
testspec_t T_testlist[] = {
{ (PFV) t1, "basic task subsystem" },
{ (PFV) t2, "maxtasks" },
{ (PFV) t3, "isc_task_shutdown" },
{ (PFV) t4, "isc_task_shutdown" },
{ (PFV) t7, "isc_task_create" },
{ (PFV) t10, "isc_task_purge" },
{ (PFV) t11, "isc_task_purgeevent" },
{ (PFV) t12, "isc_task_purgeevent" },
{ (PFV) t13, "isc_task_purgerange" },
{ (PFV) t14, "isc_task_beginexclusive" },
{ (PFV) 0, NULL }
};
#ifdef WIN32
int
main(int argc, char **argv) {
t_settests(T_testlist);
return (t_main(argc, argv));
}
#endif