1 /*	$NetBSD: t_tasks.c,v 1.7 2014/12/10 04:37:54 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1998-2001  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: t_tasks.c,v 1.49 2011/07/27 07:45:55 marka Exp  */
21 
22 #include <config.h>
23 
24 #include <stdlib.h>
25 #include <unistd.h>
26 #ifdef HAVE_INTTYPES_H
27 #include <inttypes.h> 	/* uintptr_t */
28 #endif
29 #include <isc/condition.h>
30 #include <isc/mem.h>
31 #include <isc/platform.h>
32 #include <isc/task.h>
33 #include <isc/time.h>
34 #include <isc/timer.h>
35 #include <isc/util.h>
36 
37 #include <tests/t_api.h>
38 
39 
40 #ifdef ISC_PLATFORM_USETHREADS
41 isc_boolean_t threaded = ISC_TRUE;
42 #else
43 isc_boolean_t threaded = ISC_FALSE;
44 #endif
45 
46 static int senders[4];
47 
48 static void
49 require_threads(void) {
50 	t_info("This test requires threads\n");
51 	t_result(T_THREADONLY);
52 	return;
53 }
54 
55 static void
56 t1_callback(isc_task_t *task, isc_event_t *event) {
57 	int	i;
58 	int	j;
59 
60 	UNUSED(task);
61 
62 	j = 0;
63 
64 	for (i = 0; i < 1000000; i++)
65 		j += 100;
66 
67 	t_info("task %s\n", (char *)event->ev_arg);
68 	isc_event_free(&event);
69 }
70 
71 static void
72 t1_shutdown(isc_task_t *task, isc_event_t *event) {
73 
74 	UNUSED(task);
75 
76 	t_info("shutdown %s\n", (char *)event->ev_arg);
77 	isc_event_free(&event);
78 }
79 
80 static void
81 my_tick(isc_task_t *task, isc_event_t *event) {
82 
83 	UNUSED(task);
84 
85 	t_info("%s\n", (char *)event->ev_arg);
86 	isc_event_free(&event);
87 }
88 
89 /*
90  * Adapted from RTH's original task_test program
91  */
92 
93 static char one[] = "1";
94 static char two[] = "2";
95 static char three[] = "3";
96 static char four[] = "4";
97 static char tick[] = "tick";
98 static char tock[] = "tock";
99 
100 static int
101 t_tasks1(void) {
102 	char			*p;
103 	isc_mem_t		*mctx;
104 	isc_taskmgr_t		*manager;
105 	isc_task_t		*task1;
106 	isc_task_t		*task2;
107 	isc_task_t		*task3;
108 	isc_task_t		*task4;
109 	isc_event_t		*event;
110 	unsigned int		workers;
111 	isc_timermgr_t		*timgr;
112 	isc_timer_t		*ti1;
113 	isc_timer_t		*ti2;
114 	isc_result_t		isc_result;
115 	isc_time_t		absolute;
116 	isc_interval_t		interval;
117 
118 	manager = NULL;
119 	task1 = NULL;
120 	task2 = NULL;
121 	task3 = NULL;
122 	task4 = NULL;
123 	mctx = NULL;
124 
125 	workers = 2;
126 	p = t_getenv("ISC_TASK_WORKERS");
127 	if (p != NULL)
128 		workers = atoi(p);
129 	if (workers < 1) {
130 		t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
131 		return(T_UNRESOLVED);
132 	}
133 
134 	isc_result = isc_mem_create(0, 0, &mctx);
135 	if (isc_result != ISC_R_SUCCESS) {
136 		t_info("isc_mem_create failed %d\n", isc_result);
137 		return(T_UNRESOLVED);
138 	}
139 
140 	isc_result = isc_taskmgr_create(mctx, workers, 0, &manager);
141 	if (isc_result != ISC_R_SUCCESS) {
142 		t_info("isc_taskmgr_create failed %d\n", isc_result);
143 		return(T_FAIL);
144 	}
145 
146 	isc_result = isc_task_create(manager, 0, &task1);
147 	if (isc_result != ISC_R_SUCCESS) {
148 		t_info("isc_task_create failed %d\n", isc_result);
149 		return(T_FAIL);
150 	}
151 
152 	isc_result = isc_task_create(manager, 0, &task2);
153 	if (isc_result != ISC_R_SUCCESS) {
154 		t_info("isc_task_create failed %d\n", isc_result);
155 		return(T_FAIL);
156 	}
157 
158 	isc_result = isc_task_create(manager, 0, &task3);
159 	if (isc_result != ISC_R_SUCCESS) {
160 		t_info("isc_task_create failed %d\n", isc_result);
161 		return(T_FAIL);
162 	}
163 
164 	isc_result = isc_task_create(manager, 0, &task4);
165 	if (isc_result != ISC_R_SUCCESS) {
166 		t_info("isc_task_create failed %d\n", isc_result);
167 		return(T_FAIL);
168 	}
169 
170 	isc_result = isc_task_onshutdown(task1, t1_shutdown, one);
171 	if (isc_result != ISC_R_SUCCESS) {
172 		t_info("isc_task_onshutdown failed %d\n", isc_result);
173 		return(T_FAIL);
174 	}
175 
176 	isc_result = isc_task_onshutdown(task2, t1_shutdown, two);
177 	if (isc_result != ISC_R_SUCCESS) {
178 		t_info("isc_task_onshutdown failed %d\n", isc_result);
179 		return(T_FAIL);
180 	}
181 
182 	isc_result = isc_task_onshutdown(task3, t1_shutdown, three);
183 	if (isc_result != ISC_R_SUCCESS) {
184 		t_info("isc_task_onshutdown failed %d\n", isc_result);
185 		return(T_FAIL);
186 	}
187 
188 	isc_result = isc_task_onshutdown(task4, t1_shutdown, four);
189 	if (isc_result != ISC_R_SUCCESS) {
190 		t_info("isc_task_onshutdown failed %d\n", isc_result);
191 		return(T_FAIL);
192 	}
193 
194 	timgr = NULL;
195 	isc_result = isc_timermgr_create(mctx, &timgr);
196 	if (isc_result != ISC_R_SUCCESS) {
197 		t_info("isc_timermgr_create %d\n", isc_result);
198 		return(T_UNRESOLVED);
199 	}
200 
201 	ti1 = NULL;
202 	isc_time_settoepoch(&absolute);
203 	isc_interval_set(&interval, 1, 0);
204 	isc_result = isc_timer_create(timgr, isc_timertype_ticker,
205 				&absolute, &interval,
206 				task1, my_tick, tick, &ti1);
207 	if (isc_result != ISC_R_SUCCESS) {
208 		t_info("isc_timer_create %d\n", isc_result);
209 		return(T_UNRESOLVED);
210 	}
211 
212 	ti2 = NULL;
213 	isc_time_settoepoch(&absolute);
214 	isc_interval_set(&interval, 1, 0);
215 	isc_result = isc_timer_create(timgr, isc_timertype_ticker,
216 				       &absolute, &interval,
217 				       task2, my_tick, tock, &ti2);
218 	if (isc_result != ISC_R_SUCCESS) {
219 		t_info("isc_timer_create %d\n", isc_result);
220 		return(T_UNRESOLVED);
221 	}
222 
223 
224 #ifndef WIN32
225 	sleep(2);
226 #else
227 	Sleep(2000);
228 #endif
229 
230 	/*
231 	 * Note:  (void *)1 is used as a sender here, since some compilers
232 	 * don't like casting a function pointer to a (void *).
233 	 *
234 	 * In a real use, it is more likely the sender would be a
235 	 * structure (socket, timer, task, etc) but this is just a test
236 	 * program.
237 	 */
238 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
239 				   sizeof(*event));
240 	if (event == NULL) {
241 		t_info("isc_event_allocate failed\n");
242 		return(T_UNRESOLVED);
243 	}
244 
245 	isc_task_send(task1, &event);
246 
247 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
248 				   sizeof(*event));
249 	if (event == NULL) {
250 		t_info("isc_event_allocate failed\n");
251 		return(T_UNRESOLVED);
252 	}
253 
254 	isc_task_send(task1, &event);
255 
256 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
257 				   sizeof(*event));
258 	if (event == NULL) {
259 		t_info("isc_event_allocate failed\n");
260 		return(T_UNRESOLVED);
261 	}
262 
263 	isc_task_send(task1, &event);
264 
265 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
266 				   sizeof(*event));
267 	if (event == NULL) {
268 		t_info("isc_event_allocate failed\n");
269 		return(T_UNRESOLVED);
270 	}
271 
272 	isc_task_send(task1, &event);
273 
274 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
275 				   sizeof(*event));
276 	if (event == NULL) {
277 		t_info("isc_event_allocate failed\n");
278 		return(T_UNRESOLVED);
279 	}
280 
281 	isc_task_send(task1, &event);
282 
283 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
284 				   sizeof(*event));
285 	if (event == NULL) {
286 		t_info("isc_event_allocate failed\n");
287 		return(T_UNRESOLVED);
288 	}
289 
290 	isc_task_send(task1, &event);
291 
292 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
293 				   sizeof(*event));
294 	if (event == NULL) {
295 		t_info("isc_event_allocate failed\n");
296 		return(T_UNRESOLVED);
297 	}
298 
299 	isc_task_send(task1, &event);
300 
301 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
302 				   sizeof(*event));
303 	if (event == NULL) {
304 		t_info("isc_event_allocate failed\n");
305 		return(T_UNRESOLVED);
306 	}
307 
308 	isc_task_send(task1, &event);
309 
310 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, one,
311 				   sizeof(*event));
312 	if (event == NULL) {
313 		t_info("isc_event_allocate failed\n");
314 		return(T_UNRESOLVED);
315 	}
316 
317 	isc_task_send(task1, &event);
318 
319 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, two,
320 				   sizeof(*event));
321 	if (event == NULL) {
322 		t_info("isc_event_allocate failed\n");
323 		return(T_UNRESOLVED);
324 	}
325 
326 	isc_task_send(task2, &event);
327 
328 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, three,
329 				   sizeof(*event));
330 	if (event == NULL) {
331 		t_info("isc_event_allocate failed\n");
332 		return(T_UNRESOLVED);
333 	}
334 
335 	isc_task_send(task3, &event);
336 
337 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, four,
338 				   sizeof(*event));
339 	if (event == NULL) {
340 		t_info("isc_event_allocate failed\n");
341 		return(T_UNRESOLVED);
342 	}
343 
344 	isc_task_send(task4, &event);
345 
346 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, two,
347 				   sizeof(*event));
348 	if (event == NULL) {
349 		t_info("isc_event_allocate failed\n");
350 		return(T_UNRESOLVED);
351 	}
352 
353 	isc_task_send(task2, &event);
354 
355 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, three,
356 				   sizeof(*event));
357 	if (event == NULL) {
358 		t_info("isc_event_allocate failed\n");
359 		return(T_UNRESOLVED);
360 	}
361 
362 	isc_task_send(task3, &event);
363 
364 	event = isc_event_allocate(mctx, (void *)1, 1, t1_callback, four,
365 				   sizeof(*event));
366 	if (event == NULL) {
367 		t_info("isc_event_allocate failed\n");
368 		return(T_UNRESOLVED);
369 	}
370 
371 	isc_task_send(task4, &event);
372 
373 	(void)isc_task_purge(task3, NULL, 0, 0);
374 
375 	isc_task_detach(&task1);
376 	isc_task_detach(&task2);
377 	isc_task_detach(&task3);
378 	isc_task_detach(&task4);
379 
380 #ifndef WIN32
381 	sleep(10);
382 #else
383 	Sleep(10000);
384 #endif
385 	isc_timer_detach(&ti1);
386 	isc_timer_detach(&ti2);
387 	isc_timermgr_destroy(&timgr);
388 	isc_taskmgr_destroy(&manager);
389 
390 	isc_mem_destroy(&mctx);
391 	return(T_PASS);
392 }
393 
394 static const char *a1 =	"The task subsystem can create and manage tasks";
395 
396 static void
397 t1(void) {
398 	int	result;
399 
400 	t_assert("tasks", 1, T_REQUIRED, "%s", a1);
401 	result = t_tasks1();
402 	t_result(result);
403 }
404 
405 #define			T2_NTASKS	10000
406 
407 static isc_event_t	*T2_event;
408 static isc_taskmgr_t	*T2_manager;
409 static isc_mem_t	*T2_mctx;
410 static isc_condition_t	T2_cv;
411 static isc_mutex_t	T2_mx;
412 static int		T2_done;
413 static int		T2_nprobs;
414 static int		T2_nfails;
415 static int		T2_ntasks;
416 
417 static void
418 t2_shutdown(isc_task_t *task, isc_event_t *event) {
419 
420 	isc_result_t	isc_result;
421 
422 	UNUSED(task);
423 
424 	if (event->ev_arg != NULL) {
425 		isc_task_destroy((isc_task_t**) &event->ev_arg);
426 	}
427 	else {
428 		isc_result = isc_mutex_lock(&T2_mx);
429 		if (isc_result != ISC_R_SUCCESS) {
430 			t_info("isc_mutex_lock failed %d\n", isc_result);
431 			++T2_nprobs;
432 		}
433 
434 		T2_done = 1;
435 
436 		isc_result = isc_condition_signal(&T2_cv);
437 		if (isc_result != ISC_R_SUCCESS) {
438 			t_info("isc_condition_signal failed %d\n", isc_result);
439 			++T2_nprobs;
440 		}
441 
442 		isc_result = isc_mutex_unlock(&T2_mx);
443 		if (isc_result != ISC_R_SUCCESS) {
444 			t_info("isc_mutex_unlock failed %d\n", isc_result);
445 			++T2_nprobs;
446 		}
447 
448 		isc_event_free(&T2_event);
449 		isc_taskmgr_destroy(&T2_manager);
450 		isc_mem_destroy(&T2_mctx);
451 	}
452 }
453 
454 static void
455 t2_callback(isc_task_t *task, isc_event_t *event) {
456 	isc_result_t	isc_result;
457 	isc_task_t	*newtask;
458 
459 	++T2_ntasks;
460 
461 	if (T_debug && ((T2_ntasks % 100) == 0)) {
462 		t_info("T2_ntasks %d\n", T2_ntasks);
463 	}
464 
465 	if (event->ev_arg) {
466 
467 		event->ev_arg = (void *)(((uintptr_t) event->ev_arg) - 1);
468 
469 		/*
470 		 * Create a new task and forward the message.
471 		 */
472 		newtask = NULL;
473 		isc_result = isc_task_create(T2_manager, 0, &newtask);
474 		if (isc_result != ISC_R_SUCCESS) {
475 			t_info("isc_task_create failed %d\n", isc_result);
476 			++T2_nfails;
477 			return;
478 		}
479 
480 		isc_result = isc_task_onshutdown(newtask, t2_shutdown,
481 						 (void *)task);
482 		if (isc_result != ISC_R_SUCCESS) {
483 			t_info("isc_task_onshutdown failed %d\n",
484 						isc_result);
485 			++T2_nfails;
486 			return;
487 		}
488 
489 		isc_task_send(newtask, &event);
490 	} else {
491 		/*
492 		 * Time to unwind, shutdown should perc back up.
493 		 */
494 		isc_task_destroy(&task);
495 	}
496 }
497 
498 static int
499 t_tasks2(void) {
500 	uintptr_t		ntasks;
501 	int			result;
502 	char			*p;
503 	isc_event_t		*event;
504 	unsigned int		workers;
505 	isc_result_t		isc_result;
506 
507 	T2_manager = NULL;
508 	T2_done = 0;
509 	T2_nprobs = 0;
510 	T2_nfails = 0;
511 	T2_ntasks = 0;
512 
513 	workers = 2;
514 	p = t_getenv("ISC_TASK_WORKERS");
515 	if (p != NULL)
516 		workers = atoi(p);
517 	if (workers < 1) {
518 		t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
519 		return(T_UNRESOLVED);
520 	}
521 
522 	p = t_getenv("ISC_TASKS_MIN");
523 	if (p != NULL)
524 		ntasks = atoi(p);
525 	else
526 		ntasks = T2_NTASKS;
527 	if (ntasks == 0U) {
528 		t_info("Bad config value for ISC_TASKS_MIN, %lu\n",
529 		       (unsigned long)ntasks);
530 		return(T_UNRESOLVED);
531 	}
532 
533 	t_info("Testing with %lu tasks\n", (unsigned long)ntasks);
534 
535 	isc_result = isc_mutex_init(&T2_mx);
536 	if (isc_result != ISC_R_SUCCESS) {
537 		t_info("isc_mutex_init failed %d\n", isc_result);
538 		return(T_UNRESOLVED);
539 	}
540 
541 	isc_result = isc_condition_init(&T2_cv);
542 	if (isc_result != ISC_R_SUCCESS) {
543 		t_info("isc_condition_init failed %d\n", isc_result);
544 		return(T_UNRESOLVED);
545 	}
546 
547 	isc_result = isc_mem_create(0, 0, &T2_mctx);
548 	if (isc_result != ISC_R_SUCCESS) {
549 		t_info("isc_mem_create failed %d\n", isc_result);
550 		return(T_UNRESOLVED);
551 	}
552 
553 	isc_result = isc_taskmgr_create(T2_mctx, workers, 0, &T2_manager);
554 	if (isc_result != ISC_R_SUCCESS) {
555 		t_info("isc_taskmgr_create failed %d\n", isc_result);
556 		return(T_FAIL);
557 	}
558 
559 	T2_event = isc_event_allocate(T2_mctx, (void *)1, 1, t2_callback,
560 					(void *)ntasks, sizeof(*event));
561 	if (T2_event == NULL) {
562 		t_info("isc_event_allocate failed\n");
563 		return(T_UNRESOLVED);
564 	}
565 
566 	isc_result = isc_mutex_lock(&T2_mx);
567 	if (isc_result != ISC_R_SUCCESS) {
568 		t_info("isc_mutex_lock failed %d\n", isc_result);
569 		return(T_UNRESOLVED);
570 	}
571 
572 	t2_callback(NULL, T2_event);
573 
574 	while (T2_done == 0) {
575 		isc_result = isc_condition_wait(&T2_cv, &T2_mx);
576 		if (isc_result != ISC_R_SUCCESS) {
577 			t_info("isc_condition_wait failed %d\n", isc_result);
578 			return(T_UNRESOLVED);
579 		}
580 	}
581 
582 	result = T_UNRESOLVED;
583 
584 	if ((T2_nfails == 0) && (T2_nprobs == 0))
585 		result = T_PASS;
586 	else if (T2_nfails != 0)
587 		result = T_FAIL;
588 
589 	return(result);
590 }
591 
592 static const char *a2 = "The task subsystem can create ISC_TASKS_MIN tasks";
593 
594 static void
595 t2(void) {
596 	t_assert("tasks", 2, T_REQUIRED, "%s", a2);
597 
598 	if (threaded)
599 		t_result(t_tasks2());
600 	else
601 		require_threads();
602 }
603 
604 #define	T3_NEVENTS	256
605 
606 static	int		T3_flag;
607 static	int		T3_nevents;
608 static	int		T3_nsdevents;
609 static	isc_mutex_t	T3_mx;
610 static	isc_condition_t	T3_cv;
611 static	int		T3_nfails;
612 static	int		T3_nprobs;
613 
614 static void
615 t3_sde1(isc_task_t *task, isc_event_t *event) {
616 
617 	UNUSED(task);
618 
619 	if (T3_nevents != T3_NEVENTS) {
620 		t_info("Some events were not processed\n");
621 		++T3_nprobs;
622 	}
623 	if (T3_nsdevents == 1) {
624 		++T3_nsdevents;
625 	} else {
626 		t_info("Shutdown events not processed in LIFO order\n");
627 		++T3_nfails;
628 	}
629 	isc_event_free(&event);
630 }
631 
632 static void
633 t3_sde2(isc_task_t *task, isc_event_t *event) {
634 
635 	UNUSED(task);
636 
637 	if (T3_nevents != T3_NEVENTS) {
638 		t_info("Some events were not processed\n");
639 		++T3_nprobs;
640 	}
641 	if (T3_nsdevents == 0) {
642 		++T3_nsdevents;
643 	} else {
644 		t_info("Shutdown events not processed in LIFO order\n");
645 		++T3_nfails;
646 	}
647 	isc_event_free(&event);
648 }
649 
650 static void
651 t3_event1(isc_task_t *task, isc_event_t *event) {
652 	isc_result_t	isc_result;
653 
654 	UNUSED(task);
655 
656 	isc_result = isc_mutex_lock(&T3_mx);
657 	if (isc_result != ISC_R_SUCCESS) {
658 		t_info("isc_mutex_lock failed %s\n",
659 		       isc_result_totext(isc_result));
660 		++T3_nprobs;
661 	}
662 	while (T3_flag != 1) {
663 		(void) isc_condition_wait(&T3_cv, &T3_mx);
664 	}
665 
666 	isc_result = isc_mutex_unlock(&T3_mx);
667 	if (isc_result != ISC_R_SUCCESS) {
668 		t_info("isc_mutex_unlock failed %s\n",
669 		       isc_result_totext(isc_result));
670 		++T3_nprobs;
671 	}
672 	isc_event_free(&event);
673 }
674 
675 static void
676 t3_event2(isc_task_t *task, isc_event_t *event) {
677 	UNUSED(task);
678 
679 	++T3_nevents;
680 	isc_event_free(&event);
681 }
682 
683 static int
684 t_tasks3(void) {
685 	int		cnt;
686 	int		result;
687 	char		*p;
688 	isc_mem_t	*mctx;
689 	isc_taskmgr_t	*tmgr;
690 	isc_task_t	*task;
691 	unsigned int	workers;
692 	isc_event_t	*event;
693 	isc_result_t	isc_result;
694 	isc_eventtype_t	event_type;
695 
696 	T3_flag = 0;
697 	T3_nevents = 0;
698 	T3_nsdevents = 0;
699 	T3_nfails = 0;
700 	T3_nprobs = 0;
701 
702 	event_type = 3;
703 
704 	workers = 2;
705 	p = t_getenv("ISC_TASK_WORKERS");
706 	if (p != NULL)
707 		workers = atoi(p);
708 
709 	mctx = NULL;
710 	isc_result = isc_mem_create(0, 0, &mctx);
711 	if (isc_result != ISC_R_SUCCESS) {
712 		t_info("isc_mem_create failed %s\n",
713 		       isc_result_totext(isc_result));
714 		return(T_UNRESOLVED);
715 	}
716 
717 	isc_result = isc_mutex_init(&T3_mx);
718 	if (isc_result != ISC_R_SUCCESS) {
719 		t_info("isc_mutex_init failed %s\n",
720 		       isc_result_totext(isc_result));
721 		isc_mem_destroy(&mctx);
722 		return(T_UNRESOLVED);
723 	}
724 
725 	isc_result = isc_condition_init(&T3_cv);
726 	if (isc_result != ISC_R_SUCCESS) {
727 		t_info("isc_condition_init failed %s\n",
728 		       isc_result_totext(isc_result));
729 		isc_mem_destroy(&mctx);
730 		return(T_UNRESOLVED);
731 	}
732 
733 	tmgr = NULL;
734 	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
735 	if (isc_result != ISC_R_SUCCESS) {
736 		t_info("isc_taskmgr_create failed %s\n",
737 		       isc_result_totext(isc_result));
738 		isc_mem_destroy(&mctx);
739 		return(T_UNRESOLVED);
740 	}
741 
742 	isc_result = isc_mutex_lock(&T3_mx);
743 	if (isc_result != ISC_R_SUCCESS) {
744 		t_info("isc_mutex_lock failed %s\n",
745 		       isc_result_totext(isc_result));
746 		isc_taskmgr_destroy(&tmgr);
747 		isc_mem_destroy(&mctx);
748 		return(T_UNRESOLVED);
749 	}
750 
751 	task = NULL;
752 	isc_result = isc_task_create(tmgr, 0, &task);
753 	if (isc_result != ISC_R_SUCCESS) {
754 		t_info("isc_task_create failed %s\n",
755 		       isc_result_totext(isc_result));
756 		(void) isc_mutex_unlock(&T3_mx);
757 		isc_taskmgr_destroy(&tmgr);
758 		isc_mem_destroy(&mctx);
759 		return(T_UNRESOLVED);
760 	}
761 
762 	/*
763 	 * This event causes the task to wait on T3_cv.
764 	 */
765 	event = isc_event_allocate(mctx, &senders[1], event_type, t3_event1,
766 				   NULL, sizeof(*event));
767 	if (event == NULL) {
768 		t_info("isc_event_allocate failed\n");
769 		(void) isc_mutex_unlock(&T3_mx);
770 		isc_task_destroy(&task);
771 		isc_taskmgr_destroy(&tmgr);
772 		isc_mem_destroy(&mctx);
773 		return(T_UNRESOLVED);
774 	}
775 	isc_task_send(task, &event);
776 
777 	/*
778 	 * Now we fill up the task's event queue with some events.
779 	 */
780 	for (cnt = 0; cnt < T3_NEVENTS; ++cnt) {
781 		event = isc_event_allocate(mctx, &senders[1], event_type,
782 					   t3_event2, NULL, sizeof(*event));
783 		if (event == NULL) {
784 			t_info("isc_event_allocate failed\n");
785 			(void) isc_mutex_unlock(&T3_mx);
786 			isc_task_destroy(&task);
787 			isc_taskmgr_destroy(&tmgr);
788 			isc_mem_destroy(&mctx);
789 			return(T_UNRESOLVED);
790 		}
791 		isc_task_send(task, &event);
792 	}
793 
794 	/*
795 	 * Now we register two shutdown events.
796 	 */
797 	isc_result = isc_task_onshutdown(task, t3_sde1, NULL);
798 	if (isc_result != ISC_R_SUCCESS) {
799 		t_info("isc_task_send failed %s\n",
800 				isc_result_totext(isc_result));
801 		(void) isc_mutex_unlock(&T3_mx);
802 		isc_task_destroy(&task);
803 		isc_taskmgr_destroy(&tmgr);
804 		isc_mem_destroy(&mctx);
805 		return(T_UNRESOLVED);
806 	}
807 
808 	isc_result = isc_task_onshutdown(task, t3_sde2, NULL);
809 	if (isc_result != ISC_R_SUCCESS) {
810 		t_info("isc_task_send failed %s\n",
811 				isc_result_totext(isc_result));
812 		(void) isc_mutex_unlock(&T3_mx);
813 		isc_task_destroy(&task);
814 		isc_taskmgr_destroy(&tmgr);
815 		isc_mem_destroy(&mctx);
816 		return(T_UNRESOLVED);
817 	}
818 
819 	isc_task_shutdown(task);
820 
821 	/*
822 	 * Now we free the task by signaling T3_cv.
823 	 */
824 	T3_flag = 1;
825 	isc_result = isc_condition_signal(&T3_cv);
826 	if (isc_result != ISC_R_SUCCESS) {
827 		t_info("isc_condition_signal failed %s\n",
828 				isc_result_totext(isc_result));
829 		++T3_nprobs;
830 	}
831 
832 	isc_result = isc_mutex_unlock(&T3_mx);
833 	if (isc_result != ISC_R_SUCCESS) {
834 		t_info("isc_mutex_unlock failed %s\n",
835 				isc_result_totext(isc_result));
836 		++T3_nprobs;
837 	}
838 
839 
840 	isc_task_detach(&task);
841 	isc_taskmgr_destroy(&tmgr);
842 	isc_mem_destroy(&mctx);
843 
844 	if (T3_nsdevents != 2) {
845 		t_info("T3_nsdevents == %d, expected 2\n", T3_nsdevents);
846 		++T3_nfails;
847 	}
848 
849 	result = T_UNRESOLVED;
850 
851 	if (T3_nfails != 0)
852 		result = T_FAIL;
853 	else if ((T3_nfails == 0) && (T3_nprobs == 0))
854 		result = T_PASS;
855 
856 	return(result);
857 }
858 
859 static const char *a3 =	"When isc_task_shutdown() is called, any shutdown "
860 			"events that have been requested via prior "
861 			"isc_task_onshutdown() calls are posted in "
862 			"LIFO order.";
863 static void
864 t3(void) {
865 	t_assert("tasks", 3, T_REQUIRED, "%s", a3);
866 
867 	if (threaded)
868 		t_result(t_tasks3());
869 	else
870 		require_threads();
871 }
872 
873 static isc_mutex_t	T4_mx;
874 static isc_condition_t	T4_cv;
875 static int		T4_flag;
876 static int		T4_nprobs;
877 static int		T4_nfails;
878 
879 static void
880 t4_event1(isc_task_t *task, isc_event_t *event) {
881 	isc_result_t	isc_result;
882 
883 	UNUSED(task);
884 
885 	isc_result = isc_mutex_lock(&T4_mx);
886 	if (isc_result != ISC_R_SUCCESS) {
887 		t_info("isc_mutex_lock failed %s\n",
888 		       isc_result_totext(isc_result));
889 		++T4_nprobs;
890 	}
891 	while (T4_flag != 1) {
892 		(void) isc_condition_wait(&T4_cv, &T4_mx);
893 	}
894 
895 	isc_result = isc_mutex_unlock(&T4_mx);
896 	if (isc_result != ISC_R_SUCCESS) {
897 		t_info("isc_mutex_unlock failed %s\n",
898 		       isc_result_totext(isc_result));
899 		++T4_nprobs;
900 	}
901 	isc_event_free(&event);
902 }
903 
904 static void
905 t4_sde(isc_task_t *task, isc_event_t *event) {
906 	UNUSED(task);
907 
908 	/*
909 	 * No-op.
910 	 */
911 
912 	isc_event_free(&event);
913 }
914 
915 static int
916 t_tasks4(void) {
917 	int		result;
918 	char		*p;
919 	isc_mem_t	*mctx;
920 	isc_taskmgr_t	*tmgr;
921 	isc_task_t	*task;
922 	unsigned int	workers;
923 	isc_result_t	isc_result;
924 	isc_eventtype_t	event_type;
925 	isc_event_t	*event;
926 
927 	T4_nprobs = 0;
928 	T4_nfails = 0;
929 	T4_flag = 0;
930 
931 	event_type = 4;
932 
933 	workers = 2;
934 	p = t_getenv("ISC_TASK_WORKERS");
935 	if (p != NULL)
936 		workers = atoi(p);
937 
938 	mctx = NULL;
939 	isc_result = isc_mem_create(0, 0, &mctx);
940 	if (isc_result != ISC_R_SUCCESS) {
941 		t_info("isc_mem_create failed %s\n",
942 		       isc_result_totext(isc_result));
943 		return(T_UNRESOLVED);
944 	}
945 
946 	isc_result = isc_mutex_init(&T4_mx);
947 	if (isc_result != ISC_R_SUCCESS) {
948 		t_info("isc_mutex_init failed %s\n",
949 		       isc_result_totext(isc_result));
950 		isc_mem_destroy(&mctx);
951 		return(T_UNRESOLVED);
952 	}
953 
954 	isc_result = isc_condition_init(&T4_cv);
955 	if (isc_result != ISC_R_SUCCESS) {
956 		t_info("isc_condition_init failed %s\n",
957 		       isc_result_totext(isc_result));
958 		DESTROYLOCK(&T4_mx);
959 		isc_mem_destroy(&mctx);
960 		return(T_UNRESOLVED);
961 	}
962 
963 	tmgr = NULL;
964 	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
965 	if (isc_result != ISC_R_SUCCESS) {
966 		t_info("isc_taskmgr_create failed %s\n",
967 		       isc_result_totext(isc_result));
968 		DESTROYLOCK(&T4_mx);
969 		(void) isc_condition_destroy(&T4_cv);
970 		isc_mem_destroy(&mctx);
971 		return(T_UNRESOLVED);
972 	}
973 
974 	isc_result = isc_mutex_lock(&T4_mx);
975 	if (isc_result != ISC_R_SUCCESS) {
976 		t_info("isc_mutex_lock failed %s\n",
977 		       isc_result_totext(isc_result));
978 		DESTROYLOCK(&T4_mx);
979 		(void) isc_condition_destroy(&T4_cv);
980 		isc_taskmgr_destroy(&tmgr);
981 		isc_mem_destroy(&mctx);
982 		return(T_UNRESOLVED);
983 	}
984 
985 	task = NULL;
986 	isc_result = isc_task_create(tmgr, 0, &task);
987 	if (isc_result != ISC_R_SUCCESS) {
988 		t_info("isc_task_create failed %s\n",
989 		       isc_result_totext(isc_result));
990 		DESTROYLOCK(&T4_mx);
991 		(void) isc_condition_destroy(&T4_cv);
992 		isc_taskmgr_destroy(&tmgr);
993 		isc_mem_destroy(&mctx);
994 		return(T_UNRESOLVED);
995 	}
996 
997 	/*
998 	 * This event causes the task to wait on T4_cv.
999 	 */
1000 	event = isc_event_allocate(mctx, &senders[1], event_type, t4_event1,
1001 				   NULL, sizeof(*event));
1002 	if (event == NULL) {
1003 		t_info("isc_event_allocate failed\n");
1004 		DESTROYLOCK(&T4_mx);
1005 		isc_task_destroy(&task);
1006 		(void) isc_condition_destroy(&T4_cv);
1007 		isc_taskmgr_destroy(&tmgr);
1008 		isc_mem_destroy(&mctx);
1009 		return(T_UNRESOLVED);
1010 	}
1011 	isc_task_send(task, &event);
1012 
1013 	isc_task_shutdown(task);
1014 
1015 	isc_result = isc_task_onshutdown(task, t4_sde, NULL);
1016 	if (isc_result != ISC_R_SHUTTINGDOWN) {
1017 		t_info("isc_task_onshutdown returned %s\n",
1018 		       isc_result_totext(isc_result));
1019 		++T4_nfails;
1020 	}
1021 
1022 	/*
1023 	 * Release the task.
1024 	 */
1025 	T4_flag = 1;
1026 
1027 	isc_result = isc_condition_signal(&T4_cv);
1028 	if (isc_result != ISC_R_SUCCESS) {
1029 		t_info("isc_condition_signal failed %s\n",
1030 				isc_result_totext(isc_result));
1031 		++T4_nprobs;
1032 	}
1033 
1034 	isc_result = isc_mutex_unlock(&T4_mx);
1035 	if (isc_result != ISC_R_SUCCESS) {
1036 		t_info("isc_mutex_unlock failed %s\n",
1037 				isc_result_totext(isc_result));
1038 		++T4_nprobs;
1039 	}
1040 
1041 	isc_task_detach(&task);
1042 	isc_taskmgr_destroy(&tmgr);
1043 	isc_mem_destroy(&mctx);
1044 	(void) isc_condition_destroy(&T4_cv);
1045 	DESTROYLOCK(&T4_mx);
1046 
1047 	result = T_UNRESOLVED;
1048 
1049 	if (T4_nfails != 0)
1050 		result = T_FAIL;
1051 	else if ((T4_nfails == 0) && (T4_nprobs == 0))
1052 		result = T_PASS;
1053 
1054 	return(result);
1055 }
1056 
1057 static const char *a4 =
1058 		"After isc_task_shutdown() has been called, any call to "
1059 		"isc_task_onshutdown() will return ISC_R_SHUTTINGDOWN.";
1060 
1061 static void
1062 t4(void) {
1063 	t_assert("tasks", 4, T_REQUIRED, "%s", a4);
1064 
1065 	if (threaded)
1066 		t_result(t_tasks4());
1067 	else
1068 		require_threads();
1069 }
1070 
1071 static int		T7_nprobs;
1072 static int		T7_eflag;
1073 static int		T7_sdflag;
1074 static isc_mutex_t	T7_mx;
1075 static isc_condition_t	T7_cv;
1076 
1077 static int		T7_nfails;
1078 
1079 static void
1080 t7_event1(isc_task_t *task, isc_event_t *event) {
1081 	UNUSED(task);
1082 
1083 	++T7_eflag;
1084 
1085 	isc_event_free(&event);
1086 }
1087 
1088 static void
1089 t7_sde(isc_task_t *task, isc_event_t *event) {
1090 	isc_result_t	isc_result;
1091 
1092 	UNUSED(task);
1093 
1094 	isc_result = isc_mutex_lock(&T7_mx);
1095 	if (isc_result != ISC_R_SUCCESS) {
1096 		t_info("isc_mutex_lock failed %s\n",
1097 		       isc_result_totext(isc_result));
1098 		++T7_nprobs;
1099 	}
1100 
1101 	++T7_sdflag;
1102 
1103 	isc_result = isc_condition_signal(&T7_cv);
1104 	if (isc_result != ISC_R_SUCCESS) {
1105 		t_info("isc_condition_signal failed %s\n",
1106 		       isc_result_totext(isc_result));
1107 		++T7_nprobs;
1108 	}
1109 
1110 	isc_result = isc_mutex_unlock(&T7_mx);
1111 	if (isc_result != ISC_R_SUCCESS) {
1112 		t_info("isc_mutex_unlock failed %s\n",
1113 		       isc_result_totext(isc_result));
1114 		++T7_nprobs;
1115 	}
1116 
1117 	isc_event_free(&event);
1118 }
1119 
1120 static int
1121 t_tasks7(void) {
1122 	int		result;
1123 	char		*p;
1124 	isc_mem_t	*mctx;
1125 	isc_taskmgr_t	*tmgr;
1126 	isc_task_t	*task;
1127 	unsigned int	workers;
1128 	isc_result_t	isc_result;
1129 	isc_eventtype_t	event_type;
1130 	isc_event_t	*event;
1131 	isc_time_t	now;
1132 	isc_interval_t	interval;
1133 
1134 	T7_nprobs = 0;
1135 	T7_nfails = 0;
1136 	T7_sdflag = 0;
1137 	T7_eflag = 0;
1138 
1139 	event_type = 7;
1140 
1141 	workers = 2;
1142 	p = t_getenv("ISC_TASK_WORKERS");
1143 	if (p != NULL)
1144 		workers = atoi(p);
1145 
1146 	mctx = NULL;
1147 	isc_result = isc_mem_create(0, 0, &mctx);
1148 	if (isc_result != ISC_R_SUCCESS) {
1149 		t_info("isc_mem_create failed %s\n",
1150 		       isc_result_totext(isc_result));
1151 		return(T_UNRESOLVED);
1152 	}
1153 
1154 	isc_result = isc_mutex_init(&T7_mx);
1155 	if (isc_result != ISC_R_SUCCESS) {
1156 		t_info("isc_mutex_init failed %s\n",
1157 		       isc_result_totext(isc_result));
1158 		isc_mem_destroy(&mctx);
1159 		return(T_UNRESOLVED);
1160 	}
1161 
1162 	isc_result = isc_condition_init(&T7_cv);
1163 	if (isc_result != ISC_R_SUCCESS) {
1164 		t_info("isc_condition_init failed %s\n",
1165 		       isc_result_totext(isc_result));
1166 		DESTROYLOCK(&T7_mx);
1167 		isc_mem_destroy(&mctx);
1168 		return(T_UNRESOLVED);
1169 	}
1170 
1171 	tmgr = NULL;
1172 	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
1173 	if (isc_result != ISC_R_SUCCESS) {
1174 		t_info("isc_taskmgr_create failed %s\n",
1175 		       isc_result_totext(isc_result));
1176 		DESTROYLOCK(&T7_mx);
1177 		(void) isc_condition_destroy(&T7_cv);
1178 		isc_mem_destroy(&mctx);
1179 		return(T_UNRESOLVED);
1180 	}
1181 
1182 	isc_result = isc_mutex_lock(&T7_mx);
1183 	if (isc_result != ISC_R_SUCCESS) {
1184 		t_info("isc_mutex_lock failed %s\n",
1185 		       isc_result_totext(isc_result));
1186 		DESTROYLOCK(&T7_mx);
1187 		(void) isc_condition_destroy(&T7_cv);
1188 		isc_taskmgr_destroy(&tmgr);
1189 		isc_mem_destroy(&mctx);
1190 		return(T_FAIL);
1191 	}
1192 
1193 	task = NULL;
1194 	isc_result = isc_task_create(tmgr, 0, &task);
1195 	if (isc_result != ISC_R_SUCCESS) {
1196 		t_info("isc_task_create failed %s\n",
1197 		       isc_result_totext(isc_result));
1198 		DESTROYLOCK(&T7_mx);
1199 		(void) isc_condition_destroy(&T7_cv);
1200 		isc_taskmgr_destroy(&tmgr);
1201 		isc_mem_destroy(&mctx);
1202 		return(T_FAIL);
1203 	}
1204 
1205 	isc_result = isc_task_onshutdown(task, t7_sde, NULL);
1206 	if (isc_result != ISC_R_SUCCESS) {
1207 		t_info("isc_task_onshutdown returned %s\n",
1208 		       isc_result_totext(isc_result));
1209 		DESTROYLOCK(&T7_mx);
1210 		(void) isc_condition_destroy(&T7_cv);
1211 		isc_task_destroy(&task);
1212 		isc_taskmgr_destroy(&tmgr);
1213 		isc_mem_destroy(&mctx);
1214 		return(T_UNRESOLVED);
1215 	}
1216 
1217 	event = isc_event_allocate(mctx, &senders[1], event_type, t7_event1,
1218 				   NULL, sizeof(*event));
1219 	if (event == NULL) {
1220 		t_info("isc_event_allocate failed\n");
1221 		DESTROYLOCK(&T7_mx);
1222 		(void) isc_condition_destroy(&T7_cv);
1223 		isc_task_destroy(&task);
1224 		isc_taskmgr_destroy(&tmgr);
1225 		isc_mem_destroy(&mctx);
1226 		return(T_UNRESOLVED);
1227 	}
1228 	isc_task_send(task, &event);
1229 
1230 	isc_task_shutdown(task);
1231 
1232 	isc_interval_set(&interval, 5, 0);
1233 
1234 	while (T7_sdflag == 0) {
1235 		isc_result = isc_time_nowplusinterval(&now, &interval);
1236 		if (isc_result != ISC_R_SUCCESS) {
1237 			t_info("isc_time_nowplusinterval failed %s\n",
1238 			       isc_result_totext(isc_result));
1239 			DESTROYLOCK(&T7_mx);
1240 			(void) isc_condition_destroy(&T7_cv);
1241 			isc_task_destroy(&task);
1242 			isc_taskmgr_destroy(&tmgr);
1243 			isc_mem_destroy(&mctx);
1244 			return(T_UNRESOLVED);
1245 		}
1246 
1247 		isc_result = isc_condition_waituntil(&T7_cv, &T7_mx, &now);
1248 		if (isc_result != ISC_R_SUCCESS) {
1249 			t_info("isc_condition_waituntil returned %s\n",
1250 			       isc_result_totext(isc_result));
1251 			DESTROYLOCK(&T7_mx);
1252 			(void) isc_condition_destroy(&T7_cv);
1253 			isc_task_destroy(&task);
1254 			isc_taskmgr_destroy(&tmgr);
1255 			isc_mem_destroy(&mctx);
1256 			return(T_FAIL);
1257 		}
1258 	}
1259 
1260 	isc_result = isc_mutex_unlock(&T7_mx);
1261 	if (isc_result != ISC_R_SUCCESS) {
1262 		t_info("isc_mutex_unlock failed %s\n",
1263 		       isc_result_totext(isc_result));
1264 		++T7_nprobs;
1265 	}
1266 
1267 	isc_task_detach(&task);
1268 	isc_taskmgr_destroy(&tmgr);
1269 	isc_mem_destroy(&mctx);
1270 	(void) isc_condition_destroy(&T7_cv);
1271 	DESTROYLOCK(&T7_mx);
1272 
1273 	result = T_UNRESOLVED;
1274 
1275 	if (T7_eflag == 0)
1276 		++T7_nfails;
1277 
1278 	if (T7_nfails != 0)
1279 		result = T_FAIL;
1280 	else if ((T7_nfails == 0) && (T7_nprobs == 0))
1281 		result = T_PASS;
1282 
1283 	return(result);
1284 }
1285 
1286 static const char *a7 =	"A call to isc_task_create() creates a task that can "
1287 			"receive events.";
1288 
1289 static void
1290 t7(void) {
1291 	t_assert("tasks", 7, T_REQUIRED, "%s", a7);
1292 
1293 	if (threaded)
1294 		t_result(t_tasks7());
1295 	else
1296 		require_threads();
1297 }
1298 
1299 #define	T10_SENDERCNT	3
1300 #define	T10_TYPECNT	4
1301 #define	T10_TAGCNT	5
1302 #define	T10_NEVENTS	(T10_SENDERCNT*T10_TYPECNT*T10_TAGCNT)
1303 #define	T_CONTROL	99999
1304 
1305 static int		T10_nprobs;
1306 static int		T10_nfails;
1307 static int		T10_startflag;
1308 static int		T10_shutdownflag;
1309 static int		T10_eventcnt;
1310 static isc_mutex_t	T10_mx;
1311 static isc_condition_t	T10_cv;
1312 
1313 static void		*T10_purge_sender;
1314 static isc_eventtype_t	T10_purge_type_first;
1315 static isc_eventtype_t	T10_purge_type_last;
1316 static void		*T10_purge_tag;
1317 static int		T10_testrange;
1318 
1319 static void
1320 t10_event1(isc_task_t *task, isc_event_t *event) {
1321 	isc_result_t	isc_result;
1322 
1323 	UNUSED(task);
1324 
1325 	isc_result = isc_mutex_lock(&T10_mx);
1326 	if (isc_result != ISC_R_SUCCESS) {
1327 		t_info("isc_mutex_lock failed %s\n",
1328 		       isc_result_totext(isc_result));
1329 		++T10_nprobs;
1330 	}
1331 
1332 	while (T10_startflag == 0) {
1333 		isc_result = isc_condition_wait(&T10_cv, &T10_mx);
1334 		if (isc_result != ISC_R_SUCCESS) {
1335 			t_info("isc_mutex_lock failed %s\n",
1336 			       isc_result_totext(isc_result));
1337 			++T10_nprobs;
1338 		}
1339 	}
1340 
1341 	isc_result = isc_mutex_unlock(&T10_mx);
1342 	if (isc_result != ISC_R_SUCCESS) {
1343 		t_info("isc_mutex_unlock failed %s\n",
1344 		       isc_result_totext(isc_result));
1345 		++T10_nprobs;
1346 	}
1347 
1348 	isc_event_free(&event);
1349 }
1350 
1351 static void
1352 t10_event2(isc_task_t *task, isc_event_t *event) {
1353 
1354 	int	sender_match;
1355 	int	type_match;
1356 	int	tag_match;
1357 
1358 	UNUSED(task);
1359 
1360 	sender_match = 0;
1361 	type_match = 0;
1362 	tag_match = 0;
1363 
1364 	if (T_debug) {
1365 		t_info("Event %p,%d,%p,%s\n",
1366 		       event->ev_sender,
1367 		       (int)event->ev_type,
1368 		       event->ev_tag,
1369 		       event->ev_attributes & ISC_EVENTATTR_NOPURGE ?
1370 		       "NP" : "P");
1371 	}
1372 
1373 	if ((T10_purge_sender == NULL) ||
1374 	    (T10_purge_sender == event->ev_sender)) {
1375 		sender_match = 1;
1376 	}
1377 	if (T10_testrange == 0) {
1378 		if (T10_purge_type_first == event->ev_type) {
1379 			type_match = 1;
1380 		}
1381 	} else {
1382 		if ((T10_purge_type_first <= event->ev_type) &&
1383 		    (event->ev_type <= T10_purge_type_last)) {
1384 			type_match = 1;
1385 		}
1386 	}
1387 	if ((T10_purge_tag == NULL) ||
1388 	    (T10_purge_tag == event->ev_tag)) {
1389 		tag_match = 1;
1390 	}
1391 
1392 	if (sender_match && type_match && tag_match) {
1393 		if (event->ev_attributes & ISC_EVENTATTR_NOPURGE) {
1394 			t_info("event %p,%d,%p matched but was not purgable\n",
1395 				event->ev_sender, (int)event->ev_type,
1396 			       event->ev_tag);
1397 			++T10_eventcnt;
1398 		} else {
1399 			t_info("*** event %p,%d,%p not purged\n",
1400 			       event->ev_sender, (int)event->ev_type,
1401 			       event->ev_tag);
1402 		}
1403 	} else {
1404 		++T10_eventcnt;
1405 	}
1406 	isc_event_free(&event);
1407 }
1408 
1409 
1410 static void
1411 t10_sde(isc_task_t *task, isc_event_t *event) {
1412 	isc_result_t	isc_result;
1413 
1414 	UNUSED(task);
1415 
1416 	isc_result = isc_mutex_lock(&T10_mx);
1417 	if (isc_result != ISC_R_SUCCESS) {
1418 		t_info("isc_mutex_lock failed %s\n",
1419 		       isc_result_totext(isc_result));
1420 		++T10_nprobs;
1421 	}
1422 
1423 	++T10_shutdownflag;
1424 
1425 	isc_result = isc_condition_signal(&T10_cv);
1426 	if (isc_result != ISC_R_SUCCESS) {
1427 		t_info("isc_condition_signal failed %s\n",
1428 		       isc_result_totext(isc_result));
1429 		++T10_nprobs;
1430 	}
1431 
1432 	isc_result = isc_mutex_unlock(&T10_mx);
1433 	if (isc_result != ISC_R_SUCCESS) {
1434 		t_info("isc_mutex_unlock failed %s\n",
1435 		       isc_result_totext(isc_result));
1436 		++T10_nprobs;
1437 	}
1438 
1439 	isc_event_free(&event);
1440 }
1441 
1442 static void
1443 t_taskpurge_x(int sender, int type, int tag, void *purge_sender,
1444 	      int purge_type_first, int purge_type_last, void *purge_tag,
1445 	      int exp_nevents, int *nfails, int *nprobs, int testrange)
1446 {
1447 	char		*p;
1448 	isc_mem_t	*mctx;
1449 	isc_taskmgr_t	*tmgr;
1450 	isc_task_t	*task;
1451 	unsigned int	workers;
1452 	isc_result_t	isc_result;
1453 	isc_event_t	*event;
1454 	isc_time_t	now;
1455 	isc_interval_t	interval;
1456 	int		sender_cnt;
1457 	int		type_cnt;
1458 	int		tag_cnt;
1459 	int		event_cnt;
1460 	int		cnt;
1461 	int		nevents;
1462 	isc_event_t	*eventtab[T10_NEVENTS];
1463 
1464 
1465 	T10_startflag = 0;
1466 	T10_shutdownflag = 0;
1467 	T10_eventcnt = 0;
1468 	T10_purge_sender = purge_sender;
1469 	T10_purge_type_first = (isc_eventtype_t) purge_type_first;
1470 	T10_purge_type_last = (isc_eventtype_t) purge_type_last;
1471 	T10_purge_tag = purge_tag;
1472 	T10_testrange = testrange;
1473 
1474 	workers = 2;
1475 	p = t_getenv("ISC_TASK_WORKERS");
1476 	if (p != NULL)
1477 		workers = atoi(p);
1478 
1479 	mctx = NULL;
1480 	isc_result = isc_mem_create(0, 0, &mctx);
1481 	if (isc_result != ISC_R_SUCCESS) {
1482 		t_info("isc_mem_create failed %s\n",
1483 		       isc_result_totext(isc_result));
1484 		++*nprobs;
1485 		return;
1486 	}
1487 
1488 	isc_result = isc_mutex_init(&T10_mx);
1489 	if (isc_result != ISC_R_SUCCESS) {
1490 		t_info("isc_mutex_init failed %s\n",
1491 		       isc_result_totext(isc_result));
1492 		isc_mem_destroy(&mctx);
1493 		++*nprobs;
1494 		return;
1495 	}
1496 
1497 	isc_result = isc_condition_init(&T10_cv);
1498 	if (isc_result != ISC_R_SUCCESS) {
1499 		t_info("isc_condition_init failed %s\n",
1500 		       isc_result_totext(isc_result));
1501 		isc_mem_destroy(&mctx);
1502 		DESTROYLOCK(&T10_mx);
1503 		++*nprobs;
1504 		return;
1505 	}
1506 
1507 	tmgr = NULL;
1508 	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
1509 	if (isc_result != ISC_R_SUCCESS) {
1510 		t_info("isc_taskmgr_create failed %s\n",
1511 		       isc_result_totext(isc_result));
1512 		isc_mem_destroy(&mctx);
1513 		DESTROYLOCK(&T10_mx);
1514 		(void) isc_condition_destroy(&T10_cv);
1515 		++*nprobs;
1516 		return;
1517 	}
1518 
1519 	task = NULL;
1520 	isc_result = isc_task_create(tmgr, 0, &task);
1521 	if (isc_result != ISC_R_SUCCESS) {
1522 		t_info("isc_task_create failed %s\n",
1523 		       isc_result_totext(isc_result));
1524 		isc_taskmgr_destroy(&tmgr);
1525 		isc_mem_destroy(&mctx);
1526 		DESTROYLOCK(&T10_mx);
1527 		(void) isc_condition_destroy(&T10_cv);
1528 		++*nprobs;
1529 		return;
1530 	}
1531 
1532 	isc_result = isc_task_onshutdown(task, t10_sde, NULL);
1533 	if (isc_result != ISC_R_SUCCESS) {
1534 		t_info("isc_task_onshutdown returned %s\n",
1535 		       isc_result_totext(isc_result));
1536 		isc_task_destroy(&task);
1537 		isc_taskmgr_destroy(&tmgr);
1538 		isc_mem_destroy(&mctx);
1539 		DESTROYLOCK(&T10_mx);
1540 		(void) isc_condition_destroy(&T10_cv);
1541 		++*nprobs;
1542 		return;
1543 	}
1544 
1545 	/*
1546 	 * Block the task on T10_cv.
1547 	 */
1548 	event = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)T_CONTROL,
1549 				   t10_event1, NULL, sizeof(*event));
1550 
1551 	if (event == NULL) {
1552 		t_info("isc_event_allocate failed\n");
1553 		isc_task_destroy(&task);
1554 		isc_taskmgr_destroy(&tmgr);
1555 		isc_mem_destroy(&mctx);
1556 		DESTROYLOCK(&T10_mx);
1557 		(void) isc_condition_destroy(&T10_cv);
1558 		++*nprobs;
1559 		return;
1560 	}
1561 	isc_task_send(task, &event);
1562 
1563 	/*
1564 	 * Fill the task's queue with some messages with varying
1565 	 * sender, type, tag, and purgable attribute values.
1566 	 */
1567 
1568 	event_cnt = 0;
1569 	for (sender_cnt = 0; sender_cnt < T10_SENDERCNT; ++sender_cnt) {
1570 		for (type_cnt = 0; type_cnt < T10_TYPECNT; ++type_cnt) {
1571 			for (tag_cnt = 0; tag_cnt < T10_TAGCNT; ++tag_cnt) {
1572 				eventtab[event_cnt] =
1573 					isc_event_allocate(mctx,
1574 					    &senders[sender + sender_cnt],
1575 					    (isc_eventtype_t)(type + type_cnt),
1576 					    t10_event2, NULL, sizeof(*event));
1577 
1578 				if (eventtab[event_cnt] == NULL) {
1579 					t_info("isc_event_allocate failed\n");
1580 					isc_task_destroy(&task);
1581 					isc_taskmgr_destroy(&tmgr);
1582 					isc_mem_destroy(&mctx);
1583 					DESTROYLOCK(&T10_mx);
1584 					(void) isc_condition_destroy(&T10_cv);
1585 					++*nprobs;
1586 					return;
1587 				}
1588 
1589 				eventtab[event_cnt]->ev_tag =
1590 					(void *)((uintptr_t)tag + tag_cnt);
1591 
1592 				/*
1593 				 * Make all odd message non-purgable.
1594 				 */
1595 				if ((sender_cnt % 2) && (type_cnt %2) &&
1596 				    (tag_cnt %2))
1597 					eventtab[event_cnt]->ev_attributes |=
1598 						ISC_EVENTATTR_NOPURGE;
1599 				++event_cnt;
1600 			}
1601 		}
1602 	}
1603 
1604 	for (cnt = 0; cnt < event_cnt; ++cnt)
1605 		isc_task_send(task, &eventtab[cnt]);
1606 
1607 	if (T_debug)
1608 		t_info("%d events queued\n", cnt);
1609 
1610 	if (testrange == 0) {
1611 		/*
1612 		 * We're testing isc_task_purge.
1613 		 */
1614 		nevents = isc_task_purge(task, purge_sender,
1615 					(isc_eventtype_t)purge_type_first,
1616 					purge_tag);
1617 		if (nevents != exp_nevents) {
1618 			t_info("*** isc_task_purge returned %d, expected %d\n",
1619 				nevents, exp_nevents);
1620 			++*nfails;
1621 		} else if (T_debug)
1622 			t_info("isc_task_purge returned %d\n", nevents);
1623 	} else {
1624 		/*
1625 		 * We're testing isc_task_purgerange.
1626 		 */
1627 		nevents = isc_task_purgerange(task, purge_sender,
1628 					     (isc_eventtype_t)purge_type_first,
1629 					     (isc_eventtype_t)purge_type_last,
1630 					     purge_tag);
1631 		if (nevents != exp_nevents) {
1632 			t_info("*** isc_task_purgerange returned %d, "
1633 			       "expected %d\n", nevents, exp_nevents);
1634 			++*nfails;
1635 		} else if (T_debug)
1636 			t_info("isc_task_purgerange returned %d\n", nevents);
1637 	}
1638 
1639 	isc_result = isc_mutex_lock(&T10_mx);
1640 	if (isc_result != ISC_R_SUCCESS) {
1641 		t_info("isc_mutex_lock failed %s\n",
1642 		       isc_result_totext(isc_result));
1643 		isc_task_destroy(&task);
1644 		isc_taskmgr_destroy(&tmgr);
1645 		isc_mem_destroy(&mctx);
1646 		DESTROYLOCK(&T10_mx);
1647 		(void) isc_condition_destroy(&T10_cv);
1648 		++*nprobs;
1649 		return;
1650 	}
1651 
1652 	/*
1653 	 * Unblock the task, allowing event processing.
1654 	 */
1655 	T10_startflag = 1;
1656 	isc_result = isc_condition_signal(&T10_cv);
1657 	if (isc_result != ISC_R_SUCCESS) {
1658 		t_info("isc_condition_signal failed %s\n",
1659 		       isc_result_totext(isc_result));
1660 		++*nprobs;
1661 	}
1662 
1663 	isc_task_shutdown(task);
1664 
1665 	isc_interval_set(&interval, 5, 0);
1666 
1667 	/*
1668 	 * Wait for shutdown processing to complete.
1669 	 */
1670 	while (T10_shutdownflag == 0) {
1671 		isc_result = isc_time_nowplusinterval(&now, &interval);
1672 		if (isc_result != ISC_R_SUCCESS) {
1673 			t_info("isc_time_nowplusinterval failed %s\n",
1674 			       isc_result_totext(isc_result));
1675 			isc_task_detach(&task);
1676 			isc_taskmgr_destroy(&tmgr);
1677 			isc_mem_destroy(&mctx);
1678 			DESTROYLOCK(&T10_mx);
1679 			(void) isc_condition_destroy(&T10_cv);
1680 			++*nprobs;
1681 			return;
1682 		}
1683 
1684 		isc_result = isc_condition_waituntil(&T10_cv, &T10_mx, &now);
1685 		if (isc_result != ISC_R_SUCCESS) {
1686 			t_info("isc_condition_waituntil returned %s\n",
1687 			       isc_result_totext(isc_result));
1688 			isc_task_detach(&task);
1689 			isc_taskmgr_destroy(&tmgr);
1690 			isc_mem_destroy(&mctx);
1691 			DESTROYLOCK(&T10_mx);
1692 			(void) isc_condition_destroy(&T10_cv);
1693 			++*nfails;
1694 			return;
1695 		}
1696 	}
1697 
1698 	isc_result = isc_mutex_unlock(&T10_mx);
1699 	if (isc_result != ISC_R_SUCCESS) {
1700 		t_info("isc_mutex_unlock failed %s\n",
1701 		       isc_result_totext(isc_result));
1702 		++*nprobs;
1703 	}
1704 
1705 	isc_task_detach(&task);
1706 	isc_taskmgr_destroy(&tmgr);
1707 	isc_mem_destroy(&mctx);
1708 	DESTROYLOCK(&T10_mx);
1709 	(void) isc_condition_destroy(&T10_cv);
1710 
1711 	if (T_debug)
1712 		t_info("task processed %d events\n", T10_eventcnt);
1713 
1714 	if ((T10_eventcnt + nevents) != event_cnt) {
1715 		t_info("*** processed %d, purged %d, total %d\n",
1716 		       T10_eventcnt, nevents, event_cnt);
1717 		++*nfails;
1718 	}
1719 }
1720 
1721 static int
1722 t_tasks10(void) {
1723 	int	result;
1724 
1725 	T10_nprobs = 0;
1726 	T10_nfails = 0;
1727 
1728 	/*
1729 	 * Try purging on a specific sender.
1730 	 */
1731 	t_info("testing purge on 2,4,8 expecting 1\n");
1732 	t_taskpurge_x(1, 4, 7, &senders[2], 4, 4, (void *)8, 1, &T10_nfails,
1733 		      &T10_nprobs, 0);
1734 
1735 	/*
1736 	 * Try purging on all senders.
1737 	 */
1738 	t_info("testing purge on 0,4,8 expecting 3\n");
1739 	t_taskpurge_x(1, 4, 7, NULL, 4, 4, (void *)8, 3, &T10_nfails,
1740 		      &T10_nprobs, 0);
1741 
1742 	/*
1743 	 * Try purging on all senders, specified type, all tags.
1744 	 */
1745 	t_info("testing purge on 0,4,0 expecting 15\n");
1746 	t_taskpurge_x(1, 4, 7, NULL, 4, 4, NULL, 15, &T10_nfails,
1747 		      &T10_nprobs, 0);
1748 
1749 	/*
1750 	 * Try purging on a specified tag, no such type.
1751 	 */
1752 	t_info("testing purge on 0,99,8 expecting 0\n");
1753 	t_taskpurge_x(1, 4, 7, NULL, 99, 99, (void *)8, 0, &T10_nfails,
1754 		      &T10_nprobs, 0);
1755 
1756 	/*
1757 	 * Try purging on specified sender, type, all tags.
1758 	 */
1759 	t_info("testing purge on 0,5,0 expecting 5\n");
1760 	t_taskpurge_x(1, 4, 7, &senders[3], 5, 5, NULL, 5, &T10_nfails,
1761 		      &T10_nprobs, 0);
1762 
1763 	result = T_UNRESOLVED;
1764 
1765 	if ((T10_nfails == 0) && (T10_nprobs == 0))
1766 		result = T_PASS;
1767 	else if (T10_nfails != 0)
1768 		result = T_FAIL;
1769 
1770 	return(result);
1771 }
1772 
1773 static const char *a10 =
1774 			"A call to isc_task_purge(task, sender, type, tag) "
1775 			"purges all events of type 'type' and with tag 'tag' "
1776 			"not marked as unpurgable from sender from the task's "
1777 			"queue and returns the number of events purged.";
1778 
1779 static void
1780 t10(void) {
1781 	t_assert("tasks", 10, T_REQUIRED, "%s", a10);
1782 
1783 	if (threaded)
1784 		t_result(t_tasks10());
1785 	else
1786 		require_threads();
1787 }
1788 
1789 static int		T11_nprobs;
1790 static int		T11_nfails;
1791 static int		T11_startflag;
1792 static int		T11_shutdownflag;
1793 static int		T11_eventcnt;
1794 static isc_mutex_t	T11_mx;
1795 static isc_condition_t	T11_cv;
1796 
1797 static void
1798 t11_event1(isc_task_t *task, isc_event_t *event) {
1799 	isc_result_t	isc_result;
1800 
1801 	UNUSED(task);
1802 
1803 	isc_result = isc_mutex_lock(&T11_mx);
1804 	if (isc_result != ISC_R_SUCCESS) {
1805 		t_info("isc_mutex_lock failed %s\n",
1806 		       isc_result_totext(isc_result));
1807 		++T11_nprobs;
1808 	}
1809 
1810 	while (T11_startflag == 0) {
1811 		isc_result = isc_condition_wait(&T11_cv, &T11_mx);
1812 		if (isc_result != ISC_R_SUCCESS) {
1813 			t_info("isc_mutex_lock failed %s\n",
1814 			       isc_result_totext(isc_result));
1815 			++T11_nprobs;
1816 		}
1817 	}
1818 
1819 	isc_result = isc_mutex_unlock(&T11_mx);
1820 	if (isc_result != ISC_R_SUCCESS) {
1821 		t_info("isc_mutex_unlock failed %s\n",
1822 		       isc_result_totext(isc_result));
1823 		++T11_nprobs;
1824 	}
1825 
1826 	isc_event_free(&event);
1827 }
1828 
1829 static void
1830 t11_event2(isc_task_t *task, isc_event_t *event) {
1831 	UNUSED(task);
1832 
1833 	++T11_eventcnt;
1834 	isc_event_free(&event);
1835 }
1836 
1837 
1838 static void
1839 t11_sde(isc_task_t *task, isc_event_t *event) {
1840 	isc_result_t	isc_result;
1841 
1842 	UNUSED(task);
1843 
1844 	isc_result = isc_mutex_lock(&T11_mx);
1845 	if (isc_result != ISC_R_SUCCESS) {
1846 		t_info("isc_mutex_lock failed %s\n",
1847 		       isc_result_totext(isc_result));
1848 		++T11_nprobs;
1849 	}
1850 
1851 	++T11_shutdownflag;
1852 
1853 	isc_result = isc_condition_signal(&T11_cv);
1854 	if (isc_result != ISC_R_SUCCESS) {
1855 		t_info("isc_condition_signal failed %s\n",
1856 		       isc_result_totext(isc_result));
1857 		++T11_nprobs;
1858 	}
1859 
1860 	isc_result = isc_mutex_unlock(&T11_mx);
1861 	if (isc_result != ISC_R_SUCCESS) {
1862 		t_info("isc_mutex_unlock failed %s\n",
1863 		       isc_result_totext(isc_result));
1864 		++T11_nprobs;
1865 	}
1866 
1867 	isc_event_free(&event);
1868 }
1869 
1870 static int
1871 t_tasks11(int purgable) {
1872 	char		*p;
1873 	isc_mem_t	*mctx;
1874 	isc_taskmgr_t	*tmgr;
1875 	isc_task_t	*task;
1876 	isc_boolean_t	rval;
1877 	unsigned int	workers;
1878 	isc_result_t	isc_result;
1879 	isc_event_t	*event1;
1880 	isc_event_t	*event2, *event2_clone;
1881 	isc_time_t	now;
1882 	isc_interval_t	interval;
1883 	int		result;
1884 
1885 	T11_startflag = 0;
1886 	T11_shutdownflag = 0;
1887 	T11_eventcnt = 0;
1888 
1889 	workers = 2;
1890 	p = t_getenv("ISC_TASK_WORKERS");
1891 	if (p != NULL)
1892 		workers = atoi(p);
1893 
1894 	mctx = NULL;
1895 	isc_result = isc_mem_create(0, 0, &mctx);
1896 	if (isc_result != ISC_R_SUCCESS) {
1897 		t_info("isc_mem_create failed %s\n",
1898 		       isc_result_totext(isc_result));
1899 		return(T_UNRESOLVED);
1900 	}
1901 
1902 	isc_result = isc_mutex_init(&T11_mx);
1903 	if (isc_result != ISC_R_SUCCESS) {
1904 		t_info("isc_mutex_init failed %s\n",
1905 		       isc_result_totext(isc_result));
1906 		isc_mem_destroy(&mctx);
1907 		return(T_UNRESOLVED);
1908 	}
1909 
1910 	isc_result = isc_condition_init(&T11_cv);
1911 	if (isc_result != ISC_R_SUCCESS) {
1912 		t_info("isc_condition_init failed %s\n",
1913 		       isc_result_totext(isc_result));
1914 		isc_mem_destroy(&mctx);
1915 		DESTROYLOCK(&T11_mx);
1916 		return(T_UNRESOLVED);
1917 	}
1918 
1919 	tmgr = NULL;
1920 	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
1921 	if (isc_result != ISC_R_SUCCESS) {
1922 		t_info("isc_taskmgr_create failed %s\n",
1923 		       isc_result_totext(isc_result));
1924 		isc_mem_destroy(&mctx);
1925 		DESTROYLOCK(&T11_mx);
1926 		(void) isc_condition_destroy(&T11_cv);
1927 		return(T_UNRESOLVED);
1928 	}
1929 
1930 	task = NULL;
1931 	isc_result = isc_task_create(tmgr, 0, &task);
1932 	if (isc_result != ISC_R_SUCCESS) {
1933 		t_info("isc_task_create failed %s\n",
1934 		       isc_result_totext(isc_result));
1935 		isc_taskmgr_destroy(&tmgr);
1936 		isc_mem_destroy(&mctx);
1937 		DESTROYLOCK(&T11_mx);
1938 		(void) isc_condition_destroy(&T11_cv);
1939 		return(T_UNRESOLVED);
1940 	}
1941 
1942 	isc_result = isc_task_onshutdown(task, t11_sde, NULL);
1943 	if (isc_result != ISC_R_SUCCESS) {
1944 		t_info("isc_task_onshutdown returned %s\n",
1945 		       isc_result_totext(isc_result));
1946 		isc_task_destroy(&task);
1947 		isc_taskmgr_destroy(&tmgr);
1948 		isc_mem_destroy(&mctx);
1949 		DESTROYLOCK(&T11_mx);
1950 		(void) isc_condition_destroy(&T11_cv);
1951 		return(T_UNRESOLVED);
1952 	}
1953 
1954 	/*
1955 	 * Block the task on T11_cv.
1956 	 */
1957 	event1 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
1958 				    t11_event1, NULL, sizeof(*event1));
1959 	if (event1 == NULL) {
1960 		t_info("isc_event_allocate failed\n");
1961 		isc_task_destroy(&task);
1962 		isc_taskmgr_destroy(&tmgr);
1963 		isc_mem_destroy(&mctx);
1964 		DESTROYLOCK(&T11_mx);
1965 		(void) isc_condition_destroy(&T11_cv);
1966 		return(T_UNRESOLVED);
1967 	}
1968 	isc_task_send(task, &event1);
1969 
1970 	event2 = isc_event_allocate(mctx, (void *)1, (isc_eventtype_t)1,
1971 				    t11_event2, NULL, sizeof(*event2));
1972 	if (event2 == NULL) {
1973 		t_info("isc_event_allocate failed\n");
1974 		isc_task_destroy(&task);
1975 		isc_taskmgr_destroy(&tmgr);
1976 		isc_mem_destroy(&mctx);
1977 		DESTROYLOCK(&T11_mx);
1978 		(void) isc_condition_destroy(&T11_cv);
1979 		return(T_UNRESOLVED);
1980 	}
1981 	event2_clone = event2;
1982 	if (purgable)
1983 		event2->ev_attributes &= ~ISC_EVENTATTR_NOPURGE;
1984 	else
1985 		event2->ev_attributes |= ISC_EVENTATTR_NOPURGE;
1986 
1987 	isc_task_send(task, &event2);
1988 
1989 	rval = isc_task_purgeevent(task, event2_clone);
1990 	if (rval != (purgable ? ISC_TRUE : ISC_FALSE)) {
1991 		t_info("isc_task_purgeevent returned %s, expected %s\n",
1992 		       (rval ? "ISC_TRUE" : "ISC_FALSE"),
1993 		       (purgable ? "ISC_TRUE" : "ISC_FALSE"));
1994 		++T11_nfails;
1995 	}
1996 
1997 	isc_result = isc_mutex_lock(&T11_mx);
1998 	if (isc_result != ISC_R_SUCCESS) {
1999 		t_info("isc_mutex_lock failed %s\n",
2000 		       isc_result_totext(isc_result));
2001 		++T11_nprobs;
2002 	}
2003 
2004 	/*
2005 	 * Unblock the task, allowing event processing.
2006 	 */
2007 	T11_startflag = 1;
2008 	isc_result = isc_condition_signal(&T11_cv);
2009 	if (isc_result != ISC_R_SUCCESS) {
2010 		t_info("isc_condition_signal failed %s\n",
2011 				isc_result_totext(isc_result));
2012 		++T11_nprobs;
2013 	}
2014 
2015 	isc_task_shutdown(task);
2016 
2017 	isc_interval_set(&interval, 5, 0);
2018 
2019 	/*
2020 	 * Wait for shutdown processing to complete.
2021 	 */
2022 	while (T11_shutdownflag == 0) {
2023 		isc_result = isc_time_nowplusinterval(&now, &interval);
2024 		if (isc_result != ISC_R_SUCCESS) {
2025 			t_info("isc_time_nowplusinterval failed %s\n",
2026 			       isc_result_totext(isc_result));
2027 			++T11_nprobs;
2028 		}
2029 
2030 		isc_result = isc_condition_waituntil(&T11_cv, &T11_mx, &now);
2031 		if (isc_result != ISC_R_SUCCESS) {
2032 			t_info("isc_condition_waituntil returned %s\n",
2033 			       isc_result_totext(isc_result));
2034 			++T11_nprobs;
2035 		}
2036 	}
2037 
2038 	isc_result = isc_mutex_unlock(&T11_mx);
2039 	if (isc_result != ISC_R_SUCCESS) {
2040 		t_info("isc_mutex_unlock failed %s\n",
2041 		       isc_result_totext(isc_result));
2042 		++T11_nprobs;
2043 	}
2044 
2045 	isc_task_detach(&task);
2046 	isc_taskmgr_destroy(&tmgr);
2047 	isc_mem_destroy(&mctx);
2048 	DESTROYLOCK(&T11_mx);
2049 	(void) isc_condition_destroy(&T11_cv);
2050 
2051 	if (T11_eventcnt != (purgable ? 0 : 1)) {
2052 		t_info("Event was %s purged\n",
2053 		       (purgable ? "not" : "unexpectedly"));
2054 		++T11_nfails;
2055 	}
2056 
2057 	result = T_UNRESOLVED;
2058 
2059 	if ((T11_nfails == 0) && (T11_nprobs == 0))
2060 		result = T_PASS;
2061 	else if (T11_nfails)
2062 		result = T_FAIL;
2063 
2064 	return(result);
2065 }
2066 
2067 static const char *a11 =
2068 		"When the event is marked as purgable, a call to "
2069 		"isc_task_purgeevent(task, event) purges the event 'event' "
2070 		"from the task's queue and returns ISC_TRUE.";
2071 
2072 static void
2073 t11(void) {
2074 	t_assert("tasks", 11, T_REQUIRED, "%s", a11);
2075 
2076 	if (threaded)
2077 		t_result(t_tasks11(1));
2078 	else
2079 		require_threads();
2080 }
2081 
2082 static const char *a12 =
2083 			"When the event is not marked as purgable, a call to "
2084 			"isc_task_purgeevent(task, event) does not purge the "
2085 			"event 'event' from the task's queue and returns "
2086 			"ISC_FALSE.";
2087 
2088 static int
2089 t_tasks12(void) {
2090 	return(t_tasks11(0));
2091 }
2092 
2093 static void
2094 t12(void) {
2095 	t_assert("tasks", 12, T_REQUIRED, "%s", a12);
2096 
2097 	if (threaded)
2098 		t_result(t_tasks12());
2099 	else
2100 		require_threads();
2101 }
2102 
2103 static int	T13_nfails;
2104 static int	T13_nprobs;
2105 
2106 static const char *a13 =
2107 		"A call to "
2108 		"isc_event_purgerange(task, sender, first, last, tag) "
2109 		"purges all events not marked unpurgable from "
2110 		"sender 'sender' and of type within the range 'first' "
2111 		"to 'last' inclusive from the task's event queue and "
2112 		"returns the number of tasks purged.";
2113 
2114 static int
2115 t_tasks13(void) {
2116 	int	result;
2117 
2118 	T13_nfails = 0;
2119 	T13_nprobs = 0;
2120 
2121 	/*
2122 	 * First let's try the same cases we used in t10.
2123 	 */
2124 
2125 	/*
2126 	 * Try purging on a specific sender.
2127 	 */
2128 	t_info("testing purge on 2,4,8 expecting 1\n");
2129 	t_taskpurge_x(1, 4, 7, &senders[2], 4, 4, (void *)8, 1,
2130 		      &T13_nfails, &T13_nprobs, 1);
2131 
2132 	/*
2133 	 * Try purging on all senders.
2134 	 */
2135 	t_info("testing purge on 0,4,8 expecting 3\n");
2136 	t_taskpurge_x(1, 4, 7, NULL, 4, 4, (void *)8, 3,
2137 		      &T13_nfails, &T13_nprobs, 1);
2138 
2139 	/*
2140 	 * Try purging on all senders, specified type, all tags.
2141 	 */
2142 	t_info("testing purge on 0,4,0 expecting 15\n");
2143 	t_taskpurge_x(1, 4, 7, NULL, 4, 4, NULL, 15, &T13_nfails, &T13_nprobs, 1);
2144 
2145 	/*
2146 	 * Try purging on a specified tag, no such type.
2147 	 */
2148 	t_info("testing purge on 0,99,8 expecting 0\n");
2149 	t_taskpurge_x(1, 4, 7, NULL, 99, 99, (void *)8, 0,
2150 		      &T13_nfails, &T13_nprobs, 1);
2151 
2152 	/*
2153 	 * Try purging on specified sender, type, all tags.
2154 	 */
2155 	t_info("testing purge on 3,5,0 expecting 5\n");
2156 	t_taskpurge_x(1, 4, 7, &senders[3], 5, 5, 0, 5, &T13_nfails, &T13_nprobs, 1);
2157 
2158 	/*
2159 	 * Now let's try some ranges.
2160 	 */
2161 
2162 	t_info("testing purgerange on 2,4-5,8 expecting 2\n");
2163 	t_taskpurge_x(1, 4, 7, &senders[2], 4, 5, (void *)8, 1,
2164 		      &T13_nfails, &T13_nprobs, 1);
2165 
2166 	/*
2167 	 * Try purging on all senders.
2168 	 */
2169 	t_info("testing purge on 0,4-5,8 expecting 5\n");
2170 	t_taskpurge_x(1, 4, 7, NULL, 4, 5, (void *)8, 5,
2171 		      &T13_nfails, &T13_nprobs, 1);
2172 
2173 	/*
2174 	 * Try purging on all senders, specified type, all tags.
2175 	 */
2176 	t_info("testing purge on 0,5-6,0 expecting 28\n");
2177 	t_taskpurge_x(1, 4, 7, NULL, 5, 6, NULL, 28, &T13_nfails, &T13_nprobs, 1);
2178 
2179 	/*
2180 	 * Try purging on a specified tag, no such type.
2181 	 */
2182 	t_info("testing purge on 0,99-101,8 expecting 0\n");
2183 	t_taskpurge_x(1, 4, 7, NULL, 99, 101, (void *)8, 0,
2184 		      &T13_nfails, &T13_nprobs, 1);
2185 
2186 	/*
2187 	 * Try purging on specified sender, type, all tags.
2188 	 */
2189 	t_info("testing purge on 3,5-6,0 expecting 10\n");
2190 	t_taskpurge_x(1, 4, 7, &senders[3], 5, 6, NULL, 10, &T13_nfails,
2191 		      &T13_nprobs, 1);
2192 
2193 	result = T_UNRESOLVED;
2194 
2195 	if ((T13_nfails == 0) && (T13_nprobs == 0))
2196 		result = T_PASS;
2197 	else if (T13_nfails)
2198 		result = T_FAIL;
2199 
2200 	return (result);
2201 }
2202 
2203 static void
2204 t13(void) {
2205 	t_assert("tasks", 13, T_REQUIRED, "%s", a13);
2206 
2207 	if (threaded)
2208 		t_result(t_tasks13());
2209 	else
2210 		require_threads();
2211 }
2212 
2213 #define T14_NTASKS 10
2214 #define T14_EXCLTASK 6
2215 
2216 int t14_exclusiveerror = ISC_R_SUCCESS;
2217 int t14_error = 0;
2218 int t14_done = 0;
2219 
2220 int spin(int n);
2221 
2222 int t14_active[T14_NTASKS];
2223 
2224 static void
2225 t14_callback(isc_task_t *task, isc_event_t *event) {
2226 	int taskno = *(int *)(event->ev_arg);
2227 
2228 
2229 	t_info("task enter %d\n", taskno);
2230 	if (taskno == T14_EXCLTASK) {
2231 		int	i;
2232 		t14_exclusiveerror = isc_task_beginexclusive(task);
2233 		if (t14_exclusiveerror == ISC_R_SUCCESS)
2234 			t_info("task %d got exclusive access\n", taskno);
2235 		else
2236 			t_info("task %d failed to got exclusive access: %d\n",
2237 				taskno, t14_exclusiveerror);
2238 		for (i = 0; i < T14_NTASKS; i++) {
2239 			t_info("task %d state %d\n", i , t14_active[i]);
2240 			if (t14_active[i])
2241 				t14_error++;
2242 		}
2243 		isc_task_endexclusive(task);
2244 		t14_done = 1;
2245 	} else {
2246 		t14_active[taskno]++;
2247 		(void) spin(10000000);
2248 		t14_active[taskno]--;
2249 	}
2250 	t_info("task exit %d\n", taskno);
2251 	if (t14_done) {
2252 		isc_mem_put(event->ev_destroy_arg, event->ev_arg, sizeof (int));
2253 		isc_event_free(&event);
2254 	} else {
2255 		isc_task_send(task, &event);
2256 	}
2257 }
2258 
2259 int spin(int n) {
2260 	int i;
2261 	int r = 0;
2262 	for (i = 0; i < n; i++) {
2263 		r += i;
2264 		if (r > 1000000)
2265 			r = 0;
2266 	}
2267 	return (r);
2268 }
2269 
2270 static int
2271 t_tasks14(void) {
2272 	char			*p;
2273 	isc_mem_t		*mctx;
2274 	isc_taskmgr_t		*manager;
2275 	isc_task_t		*tasks[T14_NTASKS];
2276 	unsigned int		workers;
2277 	isc_result_t		isc_result;
2278 	int 			i;
2279 
2280 	manager = NULL;
2281 	mctx = NULL;
2282 
2283 	for (i = 0; i < T14_NTASKS; i++)
2284 		tasks[i] = NULL;
2285 
2286 	workers = 4;
2287 	p = t_getenv("ISC_TASK_WORKERS");
2288 	if (p != NULL)
2289 		workers = atoi(p);
2290 	if (workers < 1) {
2291 		t_info("Bad config value for ISC_TASK_WORKERS, %d\n", workers);
2292 		return(T_UNRESOLVED);
2293 	}
2294 
2295 	isc_result = isc_mem_create(0, 0, &mctx);
2296 	if (isc_result != ISC_R_SUCCESS) {
2297 		t_info("isc_mem_create failed %d\n", isc_result);
2298 		return(T_UNRESOLVED);
2299 	}
2300 
2301 	isc_result = isc_taskmgr_create(mctx, workers, 0, &manager);
2302 	if (isc_result != ISC_R_SUCCESS) {
2303 		t_info("isc_taskmgr_create failed %d\n", isc_result);
2304 		return(T_FAIL);
2305 	}
2306 
2307 	for (i = 0; i < T14_NTASKS; i++) {
2308 		isc_event_t *event;
2309 		int *v;
2310 
2311 		isc_result = isc_task_create(manager, 0, &tasks[i]);
2312 		if (isc_result != ISC_R_SUCCESS) {
2313 			t_info("isc_task_create failed %d\n", isc_result);
2314 			return(T_FAIL);
2315 		}
2316 
2317 		v = isc_mem_get(mctx, sizeof *v);
2318 		if (v == NULL) {
2319 			isc_task_detach(&tasks[i]);
2320 			t_info("isc_mem_get failed\n");
2321 			return(T_FAIL);
2322 		}
2323 		*v = i;
2324 
2325 		event = isc_event_allocate(mctx, NULL, 1, t14_callback,
2326 					   v, sizeof(*event));
2327 		if (event == NULL) {
2328 			isc_mem_put(mctx, v, sizeof *v);
2329 			t_info("isc_event_allocate failed\n");
2330 			return(T_UNRESOLVED);
2331 		}
2332 		isc_task_send(tasks[i], &event);
2333 	}
2334 
2335 	for (i = 0; i < T14_NTASKS; i++) {
2336 		isc_task_detach(&tasks[i]);
2337 	}
2338 
2339 	isc_taskmgr_destroy(&manager);
2340 
2341 	if (t14_exclusiveerror != ISC_R_SUCCESS || t14_error) {
2342 		if (t14_exclusiveerror != ISC_R_SUCCESS)
2343 			t_info("isc_task_beginexclusive() failed\n");
2344 		if (t14_error)
2345 			t_info("mutual access occurred\n");
2346 		return(T_FAIL);
2347 	}
2348 
2349 	isc_mem_destroy(&mctx);
2350 	return(T_PASS);
2351 }
2352 
2353 static void
2354 t14(void) {
2355 	int	result;
2356 
2357 	t_assert("tasks", 14, T_REQUIRED, "%s",
2358 		 "isc_task_beginexclusive() gets exclusive access");
2359 	result = t_tasks14();
2360 	t_result(result);
2361 }
2362 
2363 testspec_t	T_testlist[] = {
2364 	{	(PFV) t1,	"basic task subsystem"	},
2365 	{	(PFV) t2,	"maxtasks"		},
2366 	{	(PFV) t3,	"isc_task_shutdown"	},
2367 	{	(PFV) t4,	"isc_task_shutdown"	},
2368 	{	(PFV) t7,	"isc_task_create"	},
2369 	{	(PFV) t10,	"isc_task_purge"	},
2370 	{	(PFV) t11,	"isc_task_purgeevent"	},
2371 	{	(PFV) t12,	"isc_task_purgeevent"	},
2372 	{	(PFV) t13,	"isc_task_purgerange"	},
2373 	{	(PFV) t14,	"isc_task_beginexclusive" },
2374 	{	(PFV) 0,	NULL			}
2375 };
2376 
2377 #ifdef WIN32
2378 int
2379 main(int argc, char **argv) {
2380 	t_settests(T_testlist);
2381 	return (t_main(argc, argv));
2382 }
2383 #endif
2384