t_tasks.c 51.1 KB
Newer Older
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
Brian Wellington's avatar
Brian Wellington committed
3
 * Copyright (C) 1998-2001  Internet Software Consortium.
4
 *
5 6 7
 * Permission to use, copy, modify, and 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.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * 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.
16 17
 */

18
/* $Id: t_tasks.c,v 1.35 2005/07/18 05:03:09 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

20
#include <config.h>
21

22 23
#include <stdlib.h>
#include <unistd.h>
24

25 26
#include <isc/condition.h>
#include <isc/mem.h>
27
#include <isc/platform.h>
28 29 30 31
#include <isc/task.h>
#include <isc/time.h>
#include <isc/timer.h>
#include <isc/util.h>
32

33
#include <tests/t_api.h>
34

35 36 37 38 39 40
#ifdef ISC_PLATFORM_USETHREADS
isc_boolean_t threaded = ISC_TRUE;
#else
isc_boolean_t threaded = ISC_FALSE;
#endif

41 42
static int senders[4];

43 44 45
static void
require_threads(void) {
	t_info("This test requires threads\n");
46
	t_result(T_THREADONLY);
47 48 49
	return;
}

50
static void
51
t1_callback(isc_task_t *task, isc_event_t *event) {
52 53 54
	int	i;
	int	j;

David Lawrence's avatar
David Lawrence committed
55 56
	UNUSED(task);

57
	j = 0;
David Lawrence's avatar
David Lawrence committed
58

59 60 61
	for (i = 0; i < 1000000; i++)
		j += 100;

62
	t_info("task %s\n", (char *)event->ev_arg);
63 64 65 66 67
	isc_event_free(&event);
}

static void
t1_shutdown(isc_task_t *task, isc_event_t *event) {
David Lawrence's avatar
David Lawrence committed
68
	UNUSED(task);
69

70
	t_info("shutdown %s\n", (char *)event->ev_arg);
71 72 73 74
	isc_event_free(&event);
}

static void
75
my_tick(isc_task_t *task, isc_event_t *event) {
David Lawrence's avatar
David Lawrence committed
76 77
	UNUSED(task);

78
	t_info("%s\n", (char *)event->ev_arg);
79 80 81 82 83 84 85 86
	isc_event_free(&event);
}

/*
 * Adapted from RTH's original task_test program
 */

static int
David Lawrence's avatar
David Lawrence committed
87
t_tasks1(void) {
88
	char			*p;
David Lawrence's avatar
David Lawrence committed
89
	isc_mem_t		*mctx;
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
	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;
David Lawrence's avatar
David Lawrence committed
109
	mctx = NULL;
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131

	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);
	}

Bob Halley's avatar
Bob Halley committed
132
	isc_result = isc_task_create(manager, 0, &task1);
133 134 135 136 137
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %d\n", isc_result);
		return(T_FAIL);
	}

Bob Halley's avatar
Bob Halley committed
138
	isc_result = isc_task_create(manager, 0, &task2);
139 140 141 142 143
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %d\n", isc_result);
		return(T_FAIL);
	}

Bob Halley's avatar
Bob Halley committed
144
	isc_result = isc_task_create(manager, 0, &task3);
145 146 147 148 149
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %d\n", isc_result);
		return(T_FAIL);
	}

Bob Halley's avatar
Bob Halley committed
150
	isc_result = isc_task_create(manager, 0, &task4);
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
	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);
	}

209

210 211 212 213 214 215 216 217 218 219 220
	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",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
221
				   sizeof(*event));
222 223 224 225 226
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

227
	isc_task_send(task1, &event);
228 229

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
230
				   sizeof(*event));
231 232 233 234 235
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

236
	isc_task_send(task1, &event);
237 238

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
239
				   sizeof(*event));
240 241 242 243 244
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

245
	isc_task_send(task1, &event);
246 247

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
248
				   sizeof(*event));
249 250 251 252 253
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

254
	isc_task_send(task1, &event);
255 256

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
257
				   sizeof(*event));
258 259 260 261 262
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

263
	isc_task_send(task1, &event);
264 265

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
266
				   sizeof(*event));
267 268 269 270 271
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

272
	isc_task_send(task1, &event);
273 274

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
275
				   sizeof(*event));
276 277 278 279 280
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

281
	isc_task_send(task1, &event);
282 283

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
284
				   sizeof(*event));
285 286 287 288 289
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

290
	isc_task_send(task1, &event);
291 292

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "1",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
293
				   sizeof(*event));
294 295 296 297 298
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

299
	isc_task_send(task1, &event);
300 301

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "2",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
302
				   sizeof(*event));
303 304 305 306 307
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

308
	isc_task_send(task2, &event);
309 310

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "3",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
311
				   sizeof(*event));
312 313 314 315 316
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

317
	isc_task_send(task3, &event);
318 319

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "4",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
320
				   sizeof(*event));
321 322 323 324 325
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

326
	isc_task_send(task4, &event);
327 328

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "2",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
329
				   sizeof(*event));
330 331 332 333 334
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

335
	isc_task_send(task2, &event);
336 337

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "3",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
338
				   sizeof(*event));
339 340 341 342 343
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

344
	isc_task_send(task3, &event);
345 346

	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, "4",
Andreas Gustafsson's avatar
Andreas Gustafsson committed
347
				   sizeof(*event));
348 349 350 351 352
	if (event == NULL) {
		t_info("isc_event_allocate failed\n");
		return(T_UNRESOLVED);
	}

353
	isc_task_send(task4, &event);
354

355
	(void)isc_task_purge(task3, NULL, 0, 0);
356 357 358 359 360 361 362 363 364 365 366

	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);
367

368 369 370 371
	isc_mem_destroy(&mctx);
	return(T_PASS);
}

David Lawrence's avatar
David Lawrence committed
372
static const char *a1 =	"The task subsystem can create and manage tasks";
373

David Lawrence's avatar
David Lawrence committed
374 375
static void
t1(void) {
376 377 378 379 380 381 382
	int	result;

	t_assert("tasks", 1, T_REQUIRED, a1);
	result = t_tasks1();
	t_result(result);
}

383
#define			T2_NTASKS	10000
384 385 386 387 388 389 390 391 392

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;
393
static int		T2_ntasks;
394 395 396 397 398 399 400 401

static void
t2_shutdown(isc_task_t *task, isc_event_t *event) {

	isc_result_t	isc_result;

	task = task; /* notused */

402 403
	if (event->ev_arg != NULL) {
		isc_task_destroy((isc_task_t**) &event->ev_arg);
404 405 406 407 408 409 410
	}
	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;
		}
411

412 413 414 415 416 417 418
		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;
		}
419

420 421 422 423 424 425 426 427 428 429 430 431 432
		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
433
t2_callback(isc_task_t *task, isc_event_t *event) {
434 435 436
	isc_result_t	isc_result;
	isc_task_t	*newtask;

437 438 439 440 441 442
	++T2_ntasks;

	if (T_debug && ((T2_ntasks % 100) == 0)) {
		t_info("T2_ntasks %d\n", T2_ntasks);
	}

443
	if (event->ev_arg) {
444

445
		event->ev_arg = (void *)(((uintptr_t) event->ev_arg) - 1);
446

447 448 449
		/*
		 * Create a new task and forward the message.
		 */
450
		newtask = NULL;
Bob Halley's avatar
Bob Halley committed
451
		isc_result = isc_task_create(T2_manager, 0, &newtask);
452 453 454 455 456
		if (isc_result != ISC_R_SUCCESS) {
			t_info("isc_task_create failed %d\n", isc_result);
			++T2_nfails;
			return;
		}
457

458
		isc_result = isc_task_onshutdown(newtask, t2_shutdown,
459
						 (void *)task);
460 461 462 463 464 465
		if (isc_result != ISC_R_SUCCESS) {
			t_info("isc_task_onshutdown failed %d\n",
						isc_result);
			++T2_nfails;
			return;
		}
466

467
		isc_task_send(newtask, &event);
468 469 470 471
	} else {
		/*
		 * Time to unwind, shutdown should perc back up.
		 */
472 473 474 475 476 477
		isc_task_destroy(&task);
	}
}

static int
t_tasks2(void) {
478
	uintptr_t		ntasks;
479 480 481 482 483 484 485 486 487 488
	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;
489
	T2_ntasks = 0;
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504

	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;
505 506 507
	if (ntasks == 0U) {
		t_info("Bad config value for ISC_TASKS_MIN, %lu\n",
		       (unsigned long)ntasks);
508 509 510
		return(T_UNRESOLVED);
	}

511
	t_info("Testing with %lu tasks\n", (unsigned long)ntasks);
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

	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,
Andreas Gustafsson's avatar
Andreas Gustafsson committed
538
					(void *)ntasks, sizeof(*event));
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
	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);
}

David Lawrence's avatar
David Lawrence committed
570
static const char *a2 = "The task subsystem can create ISC_TASKS_MIN tasks";
571

David Lawrence's avatar
David Lawrence committed
572 573
static void
t2(void) {
574
	t_assert("tasks", 2, T_REQUIRED, a2);
575 576 577 578 579

	if (threaded)
		t_result(t_tasks2());
	else
		require_threads();
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
}

#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;
602
	} else {
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
		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;
620
	} else {
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
		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",
636
		       isc_result_totext(isc_result));
637 638 639 640 641 642 643 644 645
		++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",
646
		       isc_result_totext(isc_result));
647 648 649 650 651 652 653 654 655 656 657 658 659 660
		++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
David Lawrence's avatar
David Lawrence committed
661
t_tasks3(void) {
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
	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",
690
		       isc_result_totext(isc_result));
691 692 693 694 695 696
		return(T_UNRESOLVED);
	}

	isc_result = isc_mutex_init(&T3_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_init failed %s\n",
697
		       isc_result_totext(isc_result));
698 699 700 701 702 703 704
		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",
705
		       isc_result_totext(isc_result));
706 707 708 709 710 711 712 713
		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",
714
		       isc_result_totext(isc_result));
715 716 717 718 719 720 721
		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",
722
		       isc_result_totext(isc_result));
723 724 725 726 727 728
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	task = NULL;
Bob Halley's avatar
Bob Halley committed
729
	isc_result = isc_task_create(tmgr, 0, &task);
730 731
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
732
		       isc_result_totext(isc_result));
733 734 735 736 737 738
		isc_mutex_unlock(&T3_mx);
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

739 740 741
	/*
	 * This event causes the task to wait on T3_cv.
	 */
742 743
	event = isc_event_allocate(mctx, &senders[1], event_type, t3_event1,
				   NULL, sizeof(*event));
744
	isc_task_send(task, &event);
745

746 747 748
	/*
	 * Now we fill up the task's event queue with some events.
	 */
749
	for (cnt = 0; cnt < T3_NEVENTS; ++cnt) {
750
		event = isc_event_allocate(mctx, &senders[1], event_type,
751 752
					   t3_event2, NULL, sizeof(*event));
		isc_task_send(task, &event);
753 754
	}

755 756 757
	/*
	 * Now we register two shutdown events.
	 */
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
	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);

782 783 784
	/*
	 * Now we free the task by signaling T3_cv.
	 */
785 786 787 788 789 790 791 792 793 794 795 796 797 798
	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;
	}
799

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824

	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);
}

David Lawrence's avatar
David Lawrence committed
825
static const char *a3 =	"When isc_task_shutdown() is called, any shutdown "
826 827 828
			"events that have been requested via prior "
			"isc_task_onshutdown() calls are posted in "
			"LIFO order.";
David Lawrence's avatar
David Lawrence committed
829
static void
830 831
t3(void) {
	t_assert("tasks", 3, T_REQUIRED, a3);
832 833 834 835 836

	if (threaded)
		t_result(t_tasks3());
	else
		require_threads();
837 838 839 840 841 842 843 844 845 846 847 848
}

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;

849
	UNUSED(task);
850 851 852 853

	isc_result = isc_mutex_lock(&T4_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
854
		       isc_result_totext(isc_result));
855 856 857 858 859 860 861 862 863
		++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",
864
		       isc_result_totext(isc_result));
865 866 867 868 869 870 871
		++T4_nprobs;
	}
	isc_event_free(&event);
}

static void
t4_sde(isc_task_t *task, isc_event_t *event) {
872
	UNUSED(task);
873

874 875 876
	/*
	 * No-op.
	 */
877 878 879 880 881

	isc_event_free(&event);
}

static int
David Lawrence's avatar
David Lawrence committed
882
t_tasks4(void) {
883 884 885 886 887 888 889 890 891 892
	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;

893 894 895
	T4_nprobs = 0;
	T4_nfails = 0;
	T4_flag = 0;
896 897

	result = T_UNRESOLVED;
898
	event_type = 4;
899 900 901 902 903 904 905 906 907 908

	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",
909
		       isc_result_totext(isc_result));
910 911 912
		return(T_UNRESOLVED);
	}

913
	isc_result = isc_mutex_init(&T4_mx);
914 915
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_init failed %s\n",
916
		       isc_result_totext(isc_result));
917 918 919 920
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

921
	isc_result = isc_condition_init(&T4_cv);
922 923
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_init failed %s\n",
924
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
925
		DESTROYLOCK(&T4_mx);
926 927 928 929 930 931 932 933
		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",
934
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
935
		DESTROYLOCK(&T4_mx);
936
		isc_condition_destroy(&T4_cv);
937 938 939 940
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

941
	isc_result = isc_mutex_lock(&T4_mx);
942 943
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
944
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
945
		DESTROYLOCK(&T4_mx);
946
		isc_condition_destroy(&T4_cv);
947 948 949 950 951 952
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	task = NULL;
Bob Halley's avatar
Bob Halley committed
953
	isc_result = isc_task_create(tmgr, 0, &task);
954 955
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
956
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
957
		DESTROYLOCK(&T4_mx);
958
		isc_condition_destroy(&T4_cv);
959 960 961 962 963
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

964 965 966
	/*
	 * This event causes the task to wait on T4_cv.
	 */
967 968
	event = isc_event_allocate(mctx, &senders[1], event_type, t4_event1,
				   NULL, sizeof(*event));
969
	isc_task_send(task, &event);
970

971
	isc_task_shutdown(task);
972

973 974
	isc_result = isc_task_onshutdown(task, t4_sde, NULL);
	if (isc_result != ISC_R_SHUTTINGDOWN) {
975
		t_info("isc_task_onshutdown returned %s\n",
976
		       isc_result_totext(isc_result));
977
		++T4_nfails;
978 979
	}

980 981 982
	/*
	 * Release the task.
	 */
983
	T4_flag = 1;
984

985 986 987 988 989
	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;
990 991
	}

992
	isc_result = isc_mutex_unlock(&T4_mx);
993 994 995
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
				isc_result_totext(isc_result));
996
		++T4_nprobs;
997 998 999 1000 1001
	}

	isc_task_detach(&task);
	isc_taskmgr_destroy(&tmgr);
	isc_mem_destroy(&mctx);
1002
	isc_condition_destroy(&T4_cv);
Brian Wellington's avatar
Brian Wellington committed
1003
	DESTROYLOCK(&T4_mx);
1004 1005 1006

	result = T_UNRESOLVED;

1007
	if (T4_nfails != 0)
1008
		result = T_FAIL;
1009
	else if ((T4_nfails == 0) && (T4_nprobs == 0))
1010 1011 1012 1013 1014
		result = T_PASS;

	return(result);
}

David Lawrence's avatar
David Lawrence committed
1015 1016 1017
static const char *a4 =
		"After isc_task_shutdown() has been called, any call to "
		"isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.";
1018

David Lawrence's avatar
David Lawrence committed
1019 1020
static void
t4(void) {
1021
	t_assert("tasks", 4, T_REQUIRED, a4);
1022 1023 1024 1025 1026

	if (threaded)
		t_result(t_tasks4());
	else
		require_threads();
1027 1028
}

1029 1030 1031 1032 1033
static int		T7_nprobs;
static int		T7_eflag;
static int		T7_sdflag;
static isc_mutex_t	T7_mx;
static isc_condition_t	T7_cv;
1034

1035 1036
static int		T7_nfails;

1037
static void
1038
t7_event1(isc_task_t *task, isc_event_t *event) {
1039
	UNUSED(task);
1040

1041
	++T7_eflag;
1042 1043 1044 1045 1046

	isc_event_free(&event);
}

static void
1047
t7_sde(isc_task_t *task, isc_event_t *event) {
1048 1049
	isc_result_t	isc_result;

1050
	UNUSED(task);
1051

1052
	isc_result = isc_mutex_lock(&T7_mx);
1053 1054
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
1055
		       isc_result_totext(isc_result));
1056
		++T7_nprobs;
1057 1058
	}

1059
	++T7_sdflag;
1060

1061
	isc_result = isc_condition_signal(&T7_cv);
1062 1063
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_signal failed %s\n",
1064
		       isc_result_totext(isc_result));
1065
		++T7_nprobs;
1066 1067
	}

1068
	isc_result = isc_mutex_unlock(&T7_mx);
1069 1070
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
1071
		       isc_result_totext(isc_result));
1072
		++T7_nprobs;
1073 1074 1075 1076 1077 1078
	}

	isc_event_free(&event);
}

static int
David Lawrence's avatar
David Lawrence committed
1079
t_tasks7(void) {
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
	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;

1092 1093 1094 1095
	T7_nprobs = 0;
	T7_nfails = 0;
	T7_sdflag = 0;
	T7_eflag = 0;
1096 1097

	result = T_UNRESOLVED;
1098
	event_type = 7;
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108

	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",
1109
		       isc_result_totext(isc_result));
1110 1111 1112
		return(T_UNRESOLVED);
	}

1113
	isc_result = isc_mutex_init(&T7_mx);
1114 1115
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_init failed %s\n",
1116
		       isc_result_totext(isc_result));
1117 1118 1119 1120
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

1121
	isc_result = isc_condition_init(&T7_cv);
1122 1123
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_init failed %s\n",
1124
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
1125
		DESTROYLOCK(&T7_mx);
1126 1127 1128 1129 1130 1131 1132 1133
		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",
1134
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
1135
		DESTROYLOCK(&T7_mx);
1136
		isc_condition_destroy(&T7_cv);
1137 1138 1139 1140
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

1141
	isc_result = isc_mutex_lock(&T7_mx);
1142 1143
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
1144
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
1145
		DESTROYLOCK(&T7_mx);
1146
		isc_condition_destroy(&T7_cv);
1147 1148 1149 1150 1151 1152
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

	task = NULL;
Bob Halley's avatar
Bob Halley committed
1153
	isc_result = isc_task_create(tmgr, 0, &task);
1154 1155
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
1156
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
1157
		DESTROYLOCK(&T7_mx);
1158
		isc_condition_destroy(&T7_cv);
1159 1160 1161 1162 1163
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_FAIL);
	}

1164
	isc_result = isc_task_onshutdown(task, t7_sde, NULL);
1165 1166
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_onshutdown returned %s\n",
1167
		       isc_result_totext(isc_result));
Brian Wellington's avatar
Brian Wellington committed
1168
		DESTROYLOCK(&T7_mx);
1169
		isc_condition_destroy(&T7_cv);
1170 1171 1172 1173 1174 1175
		isc_task_destroy(&task);
		isc_taskmgr_destroy(&tmgr);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

1176 1177
	event = isc_event_allocate(mctx, &senders[1], event_type, t7_event1,