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