]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/ntp/lib/isc/task.c
o Fix invalid TCP checksums with pf(4). [EN-16:02.pf]
[FreeBSD/releng/9.3.git] / contrib / ntp / lib / isc / task.c
1 /*
2  * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1998-2003  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 /*! \file
21  * \author Principal Author: Bob Halley
22  */
23
24 /*
25  * XXXRTH  Need to document the states a task can be in, and the rules
26  * for changing states.
27  */
28
29 #include <config.h>
30
31 #include <isc/condition.h>
32 #include <isc/event.h>
33 #include <isc/magic.h>
34 #include <isc/mem.h>
35 #include <isc/msgs.h>
36 #include <isc/platform.h>
37 #include <isc/string.h>
38 #include <isc/task.h>
39 #include <isc/thread.h>
40 #include <isc/util.h>
41 #include <isc/xml.h>
42
43 #ifdef OPENSSL_LEAKS
44 #include <openssl/err.h>
45 #endif
46
47 /*%
48  * For BIND9 internal applications:
49  * when built with threads we use multiple worker threads shared by the whole
50  * application.
51  * when built without threads we share a single global task manager and use
52  * an integrated event loop for socket, timer, and other generic task events.
53  * For generic library:
54  * we don't use either of them: an application can have multiple task managers
55  * whether or not it's threaded, and if the application is threaded each thread
56  * is expected to have a separate manager; no "worker threads" are shared by
57  * the application threads.
58  */
59 #ifdef BIND9
60 #ifdef ISC_PLATFORM_USETHREADS
61 #define USE_WORKER_THREADS
62 #else
63 #define USE_SHARED_MANAGER
64 #endif  /* ISC_PLATFORM_USETHREADS */
65 #endif  /* BIND9 */
66
67 #include "task_p.h"
68
69 #ifdef ISC_TASK_TRACE
70 #define XTRACE(m)               fprintf(stderr, "task %p thread %lu: %s\n", \
71                                        task, isc_thread_self(), (m))
72 #define XTTRACE(t, m)           fprintf(stderr, "task %p thread %lu: %s\n", \
73                                        (t), isc_thread_self(), (m))
74 #define XTHREADTRACE(m)         fprintf(stderr, "thread %lu: %s\n", \
75                                        isc_thread_self(), (m))
76 #else
77 #define XTRACE(m)
78 #define XTTRACE(t, m)
79 #define XTHREADTRACE(m)
80 #endif
81
82 /***
83  *** Types.
84  ***/
85
86 typedef enum {
87         task_state_idle, task_state_ready, task_state_running,
88         task_state_done
89 } task_state_t;
90
91 #if defined(HAVE_LIBXML2) && defined(BIND9)
92 static const char *statenames[] = {
93         "idle", "ready", "running", "done",
94 };
95 #endif
96
97 #define TASK_MAGIC                      ISC_MAGIC('T', 'A', 'S', 'K')
98 #define VALID_TASK(t)                   ISC_MAGIC_VALID(t, TASK_MAGIC)
99
100 typedef struct isc__task isc__task_t;
101 typedef struct isc__taskmgr isc__taskmgr_t;
102
103 struct isc__task {
104         /* Not locked. */
105         isc_task_t                      common;
106         isc__taskmgr_t *                manager;
107         isc_mutex_t                     lock;
108         /* Locked by task lock. */
109         task_state_t                    state;
110         unsigned int                    references;
111         isc_eventlist_t                 events;
112         isc_eventlist_t                 on_shutdown;
113         unsigned int                    quantum;
114         unsigned int                    flags;
115         isc_stdtime_t                   now;
116         char                            name[16];
117         void *                          tag;
118         /* Locked by task manager lock. */
119         LINK(isc__task_t)               link;
120         LINK(isc__task_t)               ready_link;
121         LINK(isc__task_t)               ready_priority_link;
122 };
123
124 #define TASK_F_SHUTTINGDOWN             0x01
125 #define TASK_F_PRIVILEGED               0x02
126
127 #define TASK_SHUTTINGDOWN(t)            (((t)->flags & TASK_F_SHUTTINGDOWN) \
128                                          != 0)
129
130 #define TASK_MANAGER_MAGIC              ISC_MAGIC('T', 'S', 'K', 'M')
131 #define VALID_MANAGER(m)                ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
132
133 typedef ISC_LIST(isc__task_t)   isc__tasklist_t;
134
135 struct isc__taskmgr {
136         /* Not locked. */
137         isc_taskmgr_t                   common;
138         isc_mem_t *                     mctx;
139         isc_mutex_t                     lock;
140 #ifdef ISC_PLATFORM_USETHREADS
141         unsigned int                    workers;
142         isc_thread_t *                  threads;
143 #endif /* ISC_PLATFORM_USETHREADS */
144         /* Locked by task manager lock. */
145         unsigned int                    default_quantum;
146         LIST(isc__task_t)               tasks;
147         isc__tasklist_t                 ready_tasks;
148         isc__tasklist_t                 ready_priority_tasks;
149         isc_taskmgrmode_t               mode;
150 #ifdef ISC_PLATFORM_USETHREADS
151         isc_condition_t                 work_available;
152         isc_condition_t                 exclusive_granted;
153         isc_condition_t                 paused;
154 #endif /* ISC_PLATFORM_USETHREADS */
155         unsigned int                    tasks_running;
156         isc_boolean_t                   pause_requested;
157         isc_boolean_t                   exclusive_requested;
158         isc_boolean_t                   exiting;
159 #ifdef USE_SHARED_MANAGER
160         unsigned int                    refs;
161 #endif /* ISC_PLATFORM_USETHREADS */
162 };
163
164 #define DEFAULT_TASKMGR_QUANTUM         10
165 #define DEFAULT_DEFAULT_QUANTUM         5
166 #define FINISHED(m)                     ((m)->exiting && EMPTY((m)->tasks))
167
168 #ifdef USE_SHARED_MANAGER
169 static isc__taskmgr_t *taskmgr = NULL;
170 #endif /* USE_SHARED_MANAGER */
171
172 /*%
173  * The following can be either static or public, depending on build environment.
174  */
175
176 #ifdef BIND9
177 #define ISC_TASKFUNC_SCOPE
178 #else
179 #define ISC_TASKFUNC_SCOPE static
180 #endif
181
182 ISC_TASKFUNC_SCOPE isc_result_t
183 isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
184                  isc_task_t **taskp);
185 ISC_TASKFUNC_SCOPE void
186 isc__task_attach(isc_task_t *source0, isc_task_t **targetp);
187 ISC_TASKFUNC_SCOPE void
188 isc__task_detach(isc_task_t **taskp);
189 ISC_TASKFUNC_SCOPE void
190 isc__task_send(isc_task_t *task0, isc_event_t **eventp);
191 ISC_TASKFUNC_SCOPE void
192 isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
193 ISC_TASKFUNC_SCOPE unsigned int
194 isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
195                      isc_eventtype_t last, void *tag);
196 ISC_TASKFUNC_SCOPE unsigned int
197 isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
198                 void *tag);
199 ISC_TASKFUNC_SCOPE isc_boolean_t
200 isc__task_purgeevent(isc_task_t *task0, isc_event_t *event);
201 ISC_TASKFUNC_SCOPE unsigned int
202 isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
203                       isc_eventtype_t last, void *tag,
204                       isc_eventlist_t *events);
205 ISC_TASKFUNC_SCOPE unsigned int
206 isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
207                  void *tag, isc_eventlist_t *events);
208 ISC_TASKFUNC_SCOPE isc_result_t
209 isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
210                      const void *arg);
211 ISC_TASKFUNC_SCOPE void
212 isc__task_shutdown(isc_task_t *task0);
213 ISC_TASKFUNC_SCOPE void
214 isc__task_destroy(isc_task_t **taskp);
215 ISC_TASKFUNC_SCOPE void
216 isc__task_setname(isc_task_t *task0, const char *name, void *tag);
217 ISC_TASKFUNC_SCOPE const char *
218 isc__task_getname(isc_task_t *task0);
219 ISC_TASKFUNC_SCOPE void *
220 isc__task_gettag(isc_task_t *task0);
221 ISC_TASKFUNC_SCOPE void
222 isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t);
223 ISC_TASKFUNC_SCOPE isc_result_t
224 isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
225                     unsigned int default_quantum, isc_taskmgr_t **managerp);
226 ISC_TASKFUNC_SCOPE void
227 isc__taskmgr_destroy(isc_taskmgr_t **managerp);
228 ISC_TASKFUNC_SCOPE isc_result_t
229 isc__task_beginexclusive(isc_task_t *task);
230 ISC_TASKFUNC_SCOPE void
231 isc__task_endexclusive(isc_task_t *task0);
232 ISC_TASKFUNC_SCOPE void
233 isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv);
234 ISC_TASKFUNC_SCOPE isc_boolean_t
235 isc__task_privilege(isc_task_t *task0);
236 ISC_TASKFUNC_SCOPE void
237 isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode);
238 ISC_TASKFUNC_SCOPE isc_taskmgrmode_t
239 isc__taskmgr_mode(isc_taskmgr_t *manager0);
240
241 static inline isc_boolean_t
242 empty_readyq(isc__taskmgr_t *manager);
243
244 static inline isc__task_t *
245 pop_readyq(isc__taskmgr_t *manager);
246
247 static inline void
248 push_readyq(isc__taskmgr_t *manager, isc__task_t *task);
249
250 static struct isc__taskmethods {
251         isc_taskmethods_t methods;
252
253         /*%
254          * The following are defined just for avoiding unused static functions.
255          */
256 #ifndef BIND9
257         void *purgeevent, *unsendrange, *getname, *gettag, *getcurrenttime;
258 #endif
259 } taskmethods = {
260         {
261                 isc__task_attach,
262                 isc__task_detach,
263                 isc__task_destroy,
264                 isc__task_send,
265                 isc__task_sendanddetach,
266                 isc__task_unsend,
267                 isc__task_onshutdown,
268                 isc__task_shutdown,
269                 isc__task_setname,
270                 isc__task_purge,
271                 isc__task_purgerange,
272                 isc__task_beginexclusive,
273                 isc__task_endexclusive,
274                 isc__task_setprivilege,
275                 isc__task_privilege
276         }
277 #ifndef BIND9
278         ,
279         (void *)isc__task_purgeevent, (void *)isc__task_unsendrange,
280         (void *)isc__task_getname, (void *)isc__task_gettag,
281         (void *)isc__task_getcurrenttime
282 #endif
283 };
284
285 static isc_taskmgrmethods_t taskmgrmethods = {
286         isc__taskmgr_destroy,
287         isc__taskmgr_setmode,
288         isc__taskmgr_mode,
289         isc__task_create
290 };
291
292 /***
293  *** Tasks.
294  ***/
295
296 static void
297 task_finished(isc__task_t *task) {
298         isc__taskmgr_t *manager = task->manager;
299
300         REQUIRE(EMPTY(task->events));
301         REQUIRE(EMPTY(task->on_shutdown));
302         REQUIRE(task->references == 0);
303         REQUIRE(task->state == task_state_done);
304
305         XTRACE("task_finished");
306
307         LOCK(&manager->lock);
308         UNLINK(manager->tasks, task, link);
309 #ifdef USE_WORKER_THREADS
310         if (FINISHED(manager)) {
311                 /*
312                  * All tasks have completed and the
313                  * task manager is exiting.  Wake up
314                  * any idle worker threads so they
315                  * can exit.
316                  */
317                 BROADCAST(&manager->work_available);
318         }
319 #endif /* USE_WORKER_THREADS */
320         UNLOCK(&manager->lock);
321
322         DESTROYLOCK(&task->lock);
323         task->common.impmagic = 0;
324         task->common.magic = 0;
325         isc_mem_put(manager->mctx, task, sizeof(*task));
326 }
327
328 ISC_TASKFUNC_SCOPE isc_result_t
329 isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
330                  isc_task_t **taskp)
331 {
332         isc__taskmgr_t *manager = (void*)manager0;
333         isc__task_t *task;
334         isc_boolean_t exiting;
335         isc_result_t result;
336
337         REQUIRE(VALID_MANAGER(manager));
338         REQUIRE(taskp != NULL && *taskp == NULL);
339
340         task = isc_mem_get(manager->mctx, sizeof(*task));
341         if (task == NULL)
342                 return (ISC_R_NOMEMORY);
343         XTRACE("isc_task_create");
344         result = isc_mutex_init(&task->lock);
345         if (result != ISC_R_SUCCESS) {
346                 isc_mem_put(manager->mctx, task, sizeof(*task));
347                 return (result);
348         }
349         LOCK(&manager->lock);
350         LOCK(&task->lock);      /* helps coverity analysis noise ratio */
351         task->manager = manager;
352         task->state = task_state_idle;
353         task->references = 1;
354         INIT_LIST(task->events);
355         INIT_LIST(task->on_shutdown);
356         task->quantum = quantum;
357         task->flags = 0;
358         task->now = 0;
359         memset(task->name, 0, sizeof(task->name));
360         task->tag = NULL;
361         INIT_LINK(task, link);
362         INIT_LINK(task, ready_link);
363         INIT_LINK(task, ready_priority_link);
364         UNLOCK(&task->lock);
365         UNLOCK(&manager->lock);
366
367         exiting = ISC_FALSE;
368         LOCK(&manager->lock);
369         if (!manager->exiting) {
370                 if (task->quantum == 0)
371                         task->quantum = manager->default_quantum;
372                 APPEND(manager->tasks, task, link);
373         } else
374                 exiting = ISC_TRUE;
375         UNLOCK(&manager->lock);
376
377         if (exiting) {
378                 DESTROYLOCK(&task->lock);
379                 isc_mem_put(manager->mctx, task, sizeof(*task));
380                 return (ISC_R_SHUTTINGDOWN);
381         }
382
383         task->common.methods = (isc_taskmethods_t *)&taskmethods;
384         task->common.magic = ISCAPI_TASK_MAGIC;
385         task->common.impmagic = TASK_MAGIC;
386         *taskp = (isc_task_t *)task;
387
388         return (ISC_R_SUCCESS);
389 }
390
391 ISC_TASKFUNC_SCOPE void
392 isc__task_attach(isc_task_t *source0, isc_task_t **targetp) {
393         isc__task_t *source = (isc__task_t *)source0;
394
395         /*
396          * Attach *targetp to source.
397          */
398
399         REQUIRE(VALID_TASK(source));
400         REQUIRE(targetp != NULL && *targetp == NULL);
401
402         XTTRACE(source, "isc_task_attach");
403
404         LOCK(&source->lock);
405         source->references++;
406         UNLOCK(&source->lock);
407
408         *targetp = (isc_task_t *)source;
409 }
410
411 static inline isc_boolean_t
412 task_shutdown(isc__task_t *task) {
413         isc_boolean_t was_idle = ISC_FALSE;
414         isc_event_t *event, *prev;
415
416         /*
417          * Caller must be holding the task's lock.
418          */
419
420         XTRACE("task_shutdown");
421
422         if (! TASK_SHUTTINGDOWN(task)) {
423                 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
424                                       ISC_MSG_SHUTTINGDOWN, "shutting down"));
425                 task->flags |= TASK_F_SHUTTINGDOWN;
426                 if (task->state == task_state_idle) {
427                         INSIST(EMPTY(task->events));
428                         task->state = task_state_ready;
429                         was_idle = ISC_TRUE;
430                 }
431                 INSIST(task->state == task_state_ready ||
432                        task->state == task_state_running);
433
434                 /*
435                  * Note that we post shutdown events LIFO.
436                  */
437                 for (event = TAIL(task->on_shutdown);
438                      event != NULL;
439                      event = prev) {
440                         prev = PREV(event, ev_link);
441                         DEQUEUE(task->on_shutdown, event, ev_link);
442                         ENQUEUE(task->events, event, ev_link);
443                 }
444         }
445
446         return (was_idle);
447 }
448
449 /*
450  * Moves a task onto the appropriate run queue.
451  *
452  * Caller must NOT hold manager lock.
453  */
454 static inline void
455 task_ready(isc__task_t *task) {
456         isc__taskmgr_t *manager = task->manager;
457 #ifdef USE_WORKER_THREADS
458         isc_boolean_t has_privilege = isc__task_privilege((isc_task_t *) task);
459 #endif /* USE_WORKER_THREADS */
460
461         REQUIRE(VALID_MANAGER(manager));
462         REQUIRE(task->state == task_state_ready);
463
464         XTRACE("task_ready");
465
466         LOCK(&manager->lock);
467         push_readyq(manager, task);
468 #ifdef USE_WORKER_THREADS
469         if (manager->mode == isc_taskmgrmode_normal || has_privilege)
470                 SIGNAL(&manager->work_available);
471 #endif /* USE_WORKER_THREADS */
472         UNLOCK(&manager->lock);
473 }
474
475 static inline isc_boolean_t
476 task_detach(isc__task_t *task) {
477
478         /*
479          * Caller must be holding the task lock.
480          */
481
482         REQUIRE(task->references > 0);
483
484         XTRACE("detach");
485
486         task->references--;
487         if (task->references == 0 && task->state == task_state_idle) {
488                 INSIST(EMPTY(task->events));
489                 /*
490                  * There are no references to this task, and no
491                  * pending events.  We could try to optimize and
492                  * either initiate shutdown or clean up the task,
493                  * depending on its state, but it's easier to just
494                  * make the task ready and allow run() or the event
495                  * loop to deal with shutting down and termination.
496                  */
497                 task->state = task_state_ready;
498                 return (ISC_TRUE);
499         }
500
501         return (ISC_FALSE);
502 }
503
504 ISC_TASKFUNC_SCOPE void
505 isc__task_detach(isc_task_t **taskp) {
506         isc__task_t *task;
507         isc_boolean_t was_idle;
508
509         /*
510          * Detach *taskp from its task.
511          */
512
513         REQUIRE(taskp != NULL);
514         task = (isc__task_t *)*taskp;
515         REQUIRE(VALID_TASK(task));
516
517         XTRACE("isc_task_detach");
518
519         LOCK(&task->lock);
520         was_idle = task_detach(task);
521         UNLOCK(&task->lock);
522
523         if (was_idle)
524                 task_ready(task);
525
526         *taskp = NULL;
527 }
528
529 static inline isc_boolean_t
530 task_send(isc__task_t *task, isc_event_t **eventp) {
531         isc_boolean_t was_idle = ISC_FALSE;
532         isc_event_t *event;
533
534         /*
535          * Caller must be holding the task lock.
536          */
537
538         REQUIRE(eventp != NULL);
539         event = *eventp;
540         REQUIRE(event != NULL);
541         REQUIRE(event->ev_type > 0);
542         REQUIRE(task->state != task_state_done);
543
544         XTRACE("task_send");
545
546         if (task->state == task_state_idle) {
547                 was_idle = ISC_TRUE;
548                 INSIST(EMPTY(task->events));
549                 task->state = task_state_ready;
550         }
551         INSIST(task->state == task_state_ready ||
552                task->state == task_state_running);
553         ENQUEUE(task->events, event, ev_link);
554         *eventp = NULL;
555
556         return (was_idle);
557 }
558
559 ISC_TASKFUNC_SCOPE void
560 isc__task_send(isc_task_t *task0, isc_event_t **eventp) {
561         isc__task_t *task = (isc__task_t *)task0;
562         isc_boolean_t was_idle;
563
564         /*
565          * Send '*event' to 'task'.
566          */
567
568         REQUIRE(VALID_TASK(task));
569
570         XTRACE("isc_task_send");
571
572         /*
573          * We're trying hard to hold locks for as short a time as possible.
574          * We're also trying to hold as few locks as possible.  This is why
575          * some processing is deferred until after the lock is released.
576          */
577         LOCK(&task->lock);
578         was_idle = task_send(task, eventp);
579         UNLOCK(&task->lock);
580
581         if (was_idle) {
582                 /*
583                  * We need to add this task to the ready queue.
584                  *
585                  * We've waited until now to do it because making a task
586                  * ready requires locking the manager.  If we tried to do
587                  * this while holding the task lock, we could deadlock.
588                  *
589                  * We've changed the state to ready, so no one else will
590                  * be trying to add this task to the ready queue.  The
591                  * only way to leave the ready state is by executing the
592                  * task.  It thus doesn't matter if events are added,
593                  * removed, or a shutdown is started in the interval
594                  * between the time we released the task lock, and the time
595                  * we add the task to the ready queue.
596                  */
597                 task_ready(task);
598         }
599 }
600
601 ISC_TASKFUNC_SCOPE void
602 isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
603         isc_boolean_t idle1, idle2;
604         isc__task_t *task;
605
606         /*
607          * Send '*event' to '*taskp' and then detach '*taskp' from its
608          * task.
609          */
610
611         REQUIRE(taskp != NULL);
612         task = (isc__task_t *)*taskp;
613         REQUIRE(VALID_TASK(task));
614
615         XTRACE("isc_task_sendanddetach");
616
617         LOCK(&task->lock);
618         idle1 = task_send(task, eventp);
619         idle2 = task_detach(task);
620         UNLOCK(&task->lock);
621
622         /*
623          * If idle1, then idle2 shouldn't be true as well since we're holding
624          * the task lock, and thus the task cannot switch from ready back to
625          * idle.
626          */
627         INSIST(!(idle1 && idle2));
628
629         if (idle1 || idle2)
630                 task_ready(task);
631
632         *taskp = NULL;
633 }
634
635 #define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
636
637 static unsigned int
638 dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first,
639                isc_eventtype_t last, void *tag,
640                isc_eventlist_t *events, isc_boolean_t purging)
641 {
642         isc_event_t *event, *next_event;
643         unsigned int count = 0;
644
645         REQUIRE(VALID_TASK(task));
646         REQUIRE(last >= first);
647
648         XTRACE("dequeue_events");
649
650         /*
651          * Events matching 'sender', whose type is >= first and <= last, and
652          * whose tag is 'tag' will be dequeued.  If 'purging', matching events
653          * which are marked as unpurgable will not be dequeued.
654          *
655          * sender == NULL means "any sender", and tag == NULL means "any tag".
656          */
657
658         LOCK(&task->lock);
659
660         for (event = HEAD(task->events); event != NULL; event = next_event) {
661                 next_event = NEXT(event, ev_link);
662                 if (event->ev_type >= first && event->ev_type <= last &&
663                     (sender == NULL || event->ev_sender == sender) &&
664                     (tag == NULL || event->ev_tag == tag) &&
665                     (!purging || PURGE_OK(event))) {
666                         DEQUEUE(task->events, event, ev_link);
667                         ENQUEUE(*events, event, ev_link);
668                         count++;
669                 }
670         }
671
672         UNLOCK(&task->lock);
673
674         return (count);
675 }
676
677 ISC_TASKFUNC_SCOPE unsigned int
678 isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
679                      isc_eventtype_t last, void *tag)
680 {
681         isc__task_t *task = (isc__task_t *)task0;
682         unsigned int count;
683         isc_eventlist_t events;
684         isc_event_t *event, *next_event;
685
686         /*
687          * Purge events from a task's event queue.
688          */
689
690         XTRACE("isc_task_purgerange");
691
692         ISC_LIST_INIT(events);
693
694         count = dequeue_events(task, sender, first, last, tag, &events,
695                                ISC_TRUE);
696
697         for (event = HEAD(events); event != NULL; event = next_event) {
698                 next_event = NEXT(event, ev_link);
699                 isc_event_free(&event);
700         }
701
702         /*
703          * Note that purging never changes the state of the task.
704          */
705
706         return (count);
707 }
708
709 ISC_TASKFUNC_SCOPE unsigned int
710 isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
711                 void *tag)
712 {
713         /*
714          * Purge events from a task's event queue.
715          */
716
717         XTRACE("isc_task_purge");
718
719         return (isc__task_purgerange(task, sender, type, type, tag));
720 }
721
722 ISC_TASKFUNC_SCOPE isc_boolean_t
723 isc__task_purgeevent(isc_task_t *task0, isc_event_t *event) {
724         isc__task_t *task = (isc__task_t *)task0;
725         isc_event_t *curr_event, *next_event;
726
727         /*
728          * Purge 'event' from a task's event queue.
729          *
730          * XXXRTH:  WARNING:  This method may be removed before beta.
731          */
732
733         REQUIRE(VALID_TASK(task));
734
735         /*
736          * If 'event' is on the task's event queue, it will be purged,
737          * unless it is marked as unpurgeable.  'event' does not have to be
738          * on the task's event queue; in fact, it can even be an invalid
739          * pointer.  Purging only occurs if the event is actually on the task's
740          * event queue.
741          *
742          * Purging never changes the state of the task.
743          */
744
745         LOCK(&task->lock);
746         for (curr_event = HEAD(task->events);
747              curr_event != NULL;
748              curr_event = next_event) {
749                 next_event = NEXT(curr_event, ev_link);
750                 if (curr_event == event && PURGE_OK(event)) {
751                         DEQUEUE(task->events, curr_event, ev_link);
752                         break;
753                 }
754         }
755         UNLOCK(&task->lock);
756
757         if (curr_event == NULL)
758                 return (ISC_FALSE);
759
760         isc_event_free(&curr_event);
761
762         return (ISC_TRUE);
763 }
764
765 ISC_TASKFUNC_SCOPE unsigned int
766 isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
767                       isc_eventtype_t last, void *tag,
768                       isc_eventlist_t *events)
769 {
770         /*
771          * Remove events from a task's event queue.
772          */
773
774         XTRACE("isc_task_unsendrange");
775
776         return (dequeue_events((isc__task_t *)task, sender, first,
777                                last, tag, events, ISC_FALSE));
778 }
779
780 ISC_TASKFUNC_SCOPE unsigned int
781 isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
782                  void *tag, isc_eventlist_t *events)
783 {
784         /*
785          * Remove events from a task's event queue.
786          */
787
788         XTRACE("isc_task_unsend");
789
790         return (dequeue_events((isc__task_t *)task, sender, type,
791                                type, tag, events, ISC_FALSE));
792 }
793
794 ISC_TASKFUNC_SCOPE isc_result_t
795 isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
796                      const void *arg)
797 {
798         isc__task_t *task = (isc__task_t *)task0;
799         isc_boolean_t disallowed = ISC_FALSE;
800         isc_result_t result = ISC_R_SUCCESS;
801         isc_event_t *event;
802
803         /*
804          * Send a shutdown event with action 'action' and argument 'arg' when
805          * 'task' is shutdown.
806          */
807
808         REQUIRE(VALID_TASK(task));
809         REQUIRE(action != NULL);
810
811         event = isc_event_allocate(task->manager->mctx,
812                                    NULL,
813                                    ISC_TASKEVENT_SHUTDOWN,
814                                    action,
815                                    arg,
816                                    sizeof(*event));
817         if (event == NULL)
818                 return (ISC_R_NOMEMORY);
819
820         LOCK(&task->lock);
821         if (TASK_SHUTTINGDOWN(task)) {
822                 disallowed = ISC_TRUE;
823                 result = ISC_R_SHUTTINGDOWN;
824         } else
825                 ENQUEUE(task->on_shutdown, event, ev_link);
826         UNLOCK(&task->lock);
827
828         if (disallowed)
829                 isc_mem_put(task->manager->mctx, event, sizeof(*event));
830
831         return (result);
832 }
833
834 ISC_TASKFUNC_SCOPE void
835 isc__task_shutdown(isc_task_t *task0) {
836         isc__task_t *task = (isc__task_t *)task0;
837         isc_boolean_t was_idle;
838
839         /*
840          * Shutdown 'task'.
841          */
842
843         REQUIRE(VALID_TASK(task));
844
845         LOCK(&task->lock);
846         was_idle = task_shutdown(task);
847         UNLOCK(&task->lock);
848
849         if (was_idle)
850                 task_ready(task);
851 }
852
853 ISC_TASKFUNC_SCOPE void
854 isc__task_destroy(isc_task_t **taskp) {
855
856         /*
857          * Destroy '*taskp'.
858          */
859
860         REQUIRE(taskp != NULL);
861
862         isc_task_shutdown(*taskp);
863         isc_task_detach(taskp);
864 }
865
866 ISC_TASKFUNC_SCOPE void
867 isc__task_setname(isc_task_t *task0, const char *name, void *tag) {
868         isc__task_t *task = (isc__task_t *)task0;
869
870         /*
871          * Name 'task'.
872          */
873
874         REQUIRE(VALID_TASK(task));
875
876         LOCK(&task->lock);
877         memset(task->name, 0, sizeof(task->name));
878         strncpy(task->name, name, sizeof(task->name) - 1);
879         task->tag = tag;
880         UNLOCK(&task->lock);
881 }
882
883 ISC_TASKFUNC_SCOPE const char *
884 isc__task_getname(isc_task_t *task0) {
885         isc__task_t *task = (isc__task_t *)task0;
886
887         REQUIRE(VALID_TASK(task));
888
889         return (task->name);
890 }
891
892 ISC_TASKFUNC_SCOPE void *
893 isc__task_gettag(isc_task_t *task0) {
894         isc__task_t *task = (isc__task_t *)task0;
895
896         REQUIRE(VALID_TASK(task));
897
898         return (task->tag);
899 }
900
901 ISC_TASKFUNC_SCOPE void
902 isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) {
903         isc__task_t *task = (isc__task_t *)task0;
904
905         REQUIRE(VALID_TASK(task));
906         REQUIRE(t != NULL);
907
908         LOCK(&task->lock);
909         *t = task->now;
910         UNLOCK(&task->lock);
911 }
912
913 /***
914  *** Task Manager.
915  ***/
916
917 /*
918  * Return ISC_TRUE if the current ready list for the manager, which is
919  * either ready_tasks or the ready_priority_tasks, depending on whether
920  * the manager is currently in normal or privileged execution mode.
921  *
922  * Caller must hold the task manager lock.
923  */
924 static inline isc_boolean_t
925 empty_readyq(isc__taskmgr_t *manager) {
926         isc__tasklist_t queue;
927
928         if (manager->mode == isc_taskmgrmode_normal)
929                 queue = manager->ready_tasks;
930         else
931                 queue = manager->ready_priority_tasks;
932
933         return (ISC_TF(EMPTY(queue)));
934 }
935
936 /*
937  * Dequeue and return a pointer to the first task on the current ready
938  * list for the manager.
939  * If the task is privileged, dequeue it from the other ready list
940  * as well.
941  *
942  * Caller must hold the task manager lock.
943  */
944 static inline isc__task_t *
945 pop_readyq(isc__taskmgr_t *manager) {
946         isc__task_t *task;
947
948         if (manager->mode == isc_taskmgrmode_normal)
949                 task = HEAD(manager->ready_tasks);
950         else
951                 task = HEAD(manager->ready_priority_tasks);
952
953         if (task != NULL) {
954                 DEQUEUE(manager->ready_tasks, task, ready_link);
955                 if (ISC_LINK_LINKED(task, ready_priority_link))
956                         DEQUEUE(manager->ready_priority_tasks, task,
957                                 ready_priority_link);
958         }
959
960         return (task);
961 }
962
963 /*
964  * Push 'task' onto the ready_tasks queue.  If 'task' has the privilege
965  * flag set, then also push it onto the ready_priority_tasks queue.
966  *
967  * Caller must hold the task manager lock.
968  */
969 static inline void
970 push_readyq(isc__taskmgr_t *manager, isc__task_t *task) {
971         ENQUEUE(manager->ready_tasks, task, ready_link);
972         if ((task->flags & TASK_F_PRIVILEGED) != 0)
973                 ENQUEUE(manager->ready_priority_tasks, task,
974                         ready_priority_link);
975 }
976
977 static void
978 dispatch(isc__taskmgr_t *manager) {
979         isc__task_t *task;
980 #ifndef USE_WORKER_THREADS
981         unsigned int total_dispatch_count = 0;
982         isc__tasklist_t new_ready_tasks;
983         isc__tasklist_t new_priority_tasks;
984 #endif /* USE_WORKER_THREADS */
985
986         REQUIRE(VALID_MANAGER(manager));
987
988         /*
989          * Again we're trying to hold the lock for as short a time as possible
990          * and to do as little locking and unlocking as possible.
991          *
992          * In both while loops, the appropriate lock must be held before the
993          * while body starts.  Code which acquired the lock at the top of
994          * the loop would be more readable, but would result in a lot of
995          * extra locking.  Compare:
996          *
997          * Straightforward:
998          *
999          *      LOCK();
1000          *      ...
1001          *      UNLOCK();
1002          *      while (expression) {
1003          *              LOCK();
1004          *              ...
1005          *              UNLOCK();
1006          *
1007          *              Unlocked part here...
1008          *
1009          *              LOCK();
1010          *              ...
1011          *              UNLOCK();
1012          *      }
1013          *
1014          * Note how if the loop continues we unlock and then immediately lock.
1015          * For N iterations of the loop, this code does 2N+1 locks and 2N+1
1016          * unlocks.  Also note that the lock is not held when the while
1017          * condition is tested, which may or may not be important, depending
1018          * on the expression.
1019          *
1020          * As written:
1021          *
1022          *      LOCK();
1023          *      while (expression) {
1024          *              ...
1025          *              UNLOCK();
1026          *
1027          *              Unlocked part here...
1028          *
1029          *              LOCK();
1030          *              ...
1031          *      }
1032          *      UNLOCK();
1033          *
1034          * For N iterations of the loop, this code does N+1 locks and N+1
1035          * unlocks.  The while expression is always protected by the lock.
1036          */
1037
1038 #ifndef USE_WORKER_THREADS
1039         ISC_LIST_INIT(new_ready_tasks);
1040         ISC_LIST_INIT(new_priority_tasks);
1041 #endif
1042         LOCK(&manager->lock);
1043
1044         while (!FINISHED(manager)) {
1045 #ifdef USE_WORKER_THREADS
1046                 /*
1047                  * For reasons similar to those given in the comment in
1048                  * isc_task_send() above, it is safe for us to dequeue
1049                  * the task while only holding the manager lock, and then
1050                  * change the task to running state while only holding the
1051                  * task lock.
1052                  *
1053                  * If a pause has been requested, don't do any work
1054                  * until it's been released.
1055                  */
1056                 while ((empty_readyq(manager) || manager->pause_requested ||
1057                         manager->exclusive_requested) && !FINISHED(manager))
1058                 {
1059                         XTHREADTRACE(isc_msgcat_get(isc_msgcat,
1060                                                     ISC_MSGSET_GENERAL,
1061                                                     ISC_MSG_WAIT, "wait"));
1062                         WAIT(&manager->work_available, &manager->lock);
1063                         XTHREADTRACE(isc_msgcat_get(isc_msgcat,
1064                                                     ISC_MSGSET_TASK,
1065                                                     ISC_MSG_AWAKE, "awake"));
1066                 }
1067 #else /* USE_WORKER_THREADS */
1068                 if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
1069                     empty_readyq(manager))
1070                         break;
1071 #endif /* USE_WORKER_THREADS */
1072                 XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
1073                                             ISC_MSG_WORKING, "working"));
1074
1075                 task = pop_readyq(manager);
1076                 if (task != NULL) {
1077                         unsigned int dispatch_count = 0;
1078                         isc_boolean_t done = ISC_FALSE;
1079                         isc_boolean_t requeue = ISC_FALSE;
1080                         isc_boolean_t finished = ISC_FALSE;
1081                         isc_event_t *event;
1082
1083                         INSIST(VALID_TASK(task));
1084
1085                         /*
1086                          * Note we only unlock the manager lock if we actually
1087                          * have a task to do.  We must reacquire the manager
1088                          * lock before exiting the 'if (task != NULL)' block.
1089                          */
1090                         manager->tasks_running++;
1091                         UNLOCK(&manager->lock);
1092
1093                         LOCK(&task->lock);
1094                         INSIST(task->state == task_state_ready);
1095                         task->state = task_state_running;
1096                         XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1097                                               ISC_MSG_RUNNING, "running"));
1098                         isc_stdtime_get(&task->now);
1099                         do {
1100                                 if (!EMPTY(task->events)) {
1101                                         event = HEAD(task->events);
1102                                         DEQUEUE(task->events, event, ev_link);
1103
1104                                         /*
1105                                          * Execute the event action.
1106                                          */
1107                                         XTRACE(isc_msgcat_get(isc_msgcat,
1108                                                             ISC_MSGSET_TASK,
1109                                                             ISC_MSG_EXECUTE,
1110                                                             "execute action"));
1111                                         if (event->ev_action != NULL) {
1112                                                 UNLOCK(&task->lock);
1113                                                 (event->ev_action)(
1114                                                         (isc_task_t *)task,
1115                                                         event);
1116                                                 LOCK(&task->lock);
1117                                         }
1118                                         dispatch_count++;
1119 #ifndef USE_WORKER_THREADS
1120                                         total_dispatch_count++;
1121 #endif /* USE_WORKER_THREADS */
1122                                 }
1123
1124                                 if (task->references == 0 &&
1125                                     EMPTY(task->events) &&
1126                                     !TASK_SHUTTINGDOWN(task)) {
1127                                         isc_boolean_t was_idle;
1128
1129                                         /*
1130                                          * There are no references and no
1131                                          * pending events for this task,
1132                                          * which means it will not become
1133                                          * runnable again via an external
1134                                          * action (such as sending an event
1135                                          * or detaching).
1136                                          *
1137                                          * We initiate shutdown to prevent
1138                                          * it from becoming a zombie.
1139                                          *
1140                                          * We do this here instead of in
1141                                          * the "if EMPTY(task->events)" block
1142                                          * below because:
1143                                          *
1144                                          *      If we post no shutdown events,
1145                                          *      we want the task to finish.
1146                                          *
1147                                          *      If we did post shutdown events,
1148                                          *      will still want the task's
1149                                          *      quantum to be applied.
1150                                          */
1151                                         was_idle = task_shutdown(task);
1152                                         INSIST(!was_idle);
1153                                 }
1154
1155                                 if (EMPTY(task->events)) {
1156                                         /*
1157                                          * Nothing else to do for this task
1158                                          * right now.
1159                                          */
1160                                         XTRACE(isc_msgcat_get(isc_msgcat,
1161                                                               ISC_MSGSET_TASK,
1162                                                               ISC_MSG_EMPTY,
1163                                                               "empty"));
1164                                         if (task->references == 0 &&
1165                                             TASK_SHUTTINGDOWN(task)) {
1166                                                 /*
1167                                                  * The task is done.
1168                                                  */
1169                                                 XTRACE(isc_msgcat_get(
1170                                                                isc_msgcat,
1171                                                                ISC_MSGSET_TASK,
1172                                                                ISC_MSG_DONE,
1173                                                                "done"));
1174                                                 finished = ISC_TRUE;
1175                                                 task->state = task_state_done;
1176                                         } else
1177                                                 task->state = task_state_idle;
1178                                         done = ISC_TRUE;
1179                                 } else if (dispatch_count >= task->quantum) {
1180                                         /*
1181                                          * Our quantum has expired, but
1182                                          * there is more work to be done.
1183                                          * We'll requeue it to the ready
1184                                          * queue later.
1185                                          *
1186                                          * We don't check quantum until
1187                                          * dispatching at least one event,
1188                                          * so the minimum quantum is one.
1189                                          */
1190                                         XTRACE(isc_msgcat_get(isc_msgcat,
1191                                                               ISC_MSGSET_TASK,
1192                                                               ISC_MSG_QUANTUM,
1193                                                               "quantum"));
1194                                         task->state = task_state_ready;
1195                                         requeue = ISC_TRUE;
1196                                         done = ISC_TRUE;
1197                                 }
1198                         } while (!done);
1199                         UNLOCK(&task->lock);
1200
1201                         if (finished)
1202                                 task_finished(task);
1203
1204                         LOCK(&manager->lock);
1205                         manager->tasks_running--;
1206 #ifdef USE_WORKER_THREADS
1207                         if (manager->exclusive_requested &&
1208                             manager->tasks_running == 1) {
1209                                 SIGNAL(&manager->exclusive_granted);
1210                         } else if (manager->pause_requested &&
1211                                    manager->tasks_running == 0) {
1212                                 SIGNAL(&manager->paused);
1213                         }
1214 #endif /* USE_WORKER_THREADS */
1215                         if (requeue) {
1216                                 /*
1217                                  * We know we're awake, so we don't have
1218                                  * to wakeup any sleeping threads if the
1219                                  * ready queue is empty before we requeue.
1220                                  *
1221                                  * A possible optimization if the queue is
1222                                  * empty is to 'goto' the 'if (task != NULL)'
1223                                  * block, avoiding the ENQUEUE of the task
1224                                  * and the subsequent immediate DEQUEUE
1225                                  * (since it is the only executable task).
1226                                  * We don't do this because then we'd be
1227                                  * skipping the exit_requested check.  The
1228                                  * cost of ENQUEUE is low anyway, especially
1229                                  * when you consider that we'd have to do
1230                                  * an extra EMPTY check to see if we could
1231                                  * do the optimization.  If the ready queue
1232                                  * were usually nonempty, the 'optimization'
1233                                  * might even hurt rather than help.
1234                                  */
1235 #ifdef USE_WORKER_THREADS
1236                                 push_readyq(manager, task);
1237 #else
1238                                 ENQUEUE(new_ready_tasks, task, ready_link);
1239                                 if ((task->flags & TASK_F_PRIVILEGED) != 0)
1240                                         ENQUEUE(new_priority_tasks, task,
1241                                                 ready_priority_link);
1242 #endif
1243                         }
1244                 }
1245
1246 #ifdef USE_WORKER_THREADS
1247                 /*
1248                  * If we are in privileged execution mode and there are no
1249                  * tasks remaining on the current ready queue, then
1250                  * we're stuck.  Automatically drop privileges at that
1251                  * point and continue with the regular ready queue.
1252                  */
1253                 if (manager->tasks_running == 0 && empty_readyq(manager)) {
1254                         manager->mode = isc_taskmgrmode_normal;
1255                         if (!empty_readyq(manager))
1256                                 BROADCAST(&manager->work_available);
1257                 }
1258 #endif
1259         }
1260
1261 #ifndef USE_WORKER_THREADS
1262         ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link);
1263         ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks,
1264                             ready_priority_link);
1265         if (empty_readyq(manager))
1266                 manager->mode = isc_taskmgrmode_normal;
1267 #endif
1268
1269         UNLOCK(&manager->lock);
1270 }
1271
1272 #ifdef USE_WORKER_THREADS
1273 static isc_threadresult_t
1274 #ifdef _WIN32
1275 WINAPI
1276 #endif
1277 run(void *uap) {
1278         isc__taskmgr_t *manager = uap;
1279
1280         XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1281                                     ISC_MSG_STARTING, "starting"));
1282
1283         dispatch(manager);
1284
1285         XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1286                                     ISC_MSG_EXITING, "exiting"));
1287
1288 #ifdef OPENSSL_LEAKS
1289         ERR_remove_state(0);
1290 #endif
1291
1292         return ((isc_threadresult_t)0);
1293 }
1294 #endif /* USE_WORKER_THREADS */
1295
1296 static void
1297 manager_free(isc__taskmgr_t *manager) {
1298         isc_mem_t *mctx;
1299
1300         LOCK(&manager->lock);
1301 #ifdef USE_WORKER_THREADS
1302         (void)isc_condition_destroy(&manager->exclusive_granted);
1303         (void)isc_condition_destroy(&manager->work_available);
1304         (void)isc_condition_destroy(&manager->paused);
1305         isc_mem_free(manager->mctx, manager->threads);
1306 #endif /* USE_WORKER_THREADS */
1307         manager->common.impmagic = 0;
1308         manager->common.magic = 0;
1309         mctx = manager->mctx;
1310         UNLOCK(&manager->lock);
1311         DESTROYLOCK(&manager->lock);
1312         isc_mem_put(mctx, manager, sizeof(*manager));
1313         isc_mem_detach(&mctx);
1314
1315 #ifdef USE_SHARED_MANAGER
1316         taskmgr = NULL;
1317 #endif  /* USE_SHARED_MANAGER */
1318 }
1319
1320 ISC_TASKFUNC_SCOPE isc_result_t
1321 isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
1322                     unsigned int default_quantum, isc_taskmgr_t **managerp)
1323 {
1324         isc_result_t result;
1325         unsigned int i, started = 0;
1326         isc__taskmgr_t *manager;
1327
1328         /*
1329          * Create a new task manager.
1330          */
1331
1332         REQUIRE(workers > 0);
1333         REQUIRE(managerp != NULL && *managerp == NULL);
1334
1335 #ifndef USE_WORKER_THREADS
1336         UNUSED(i);
1337         UNUSED(started);
1338 #endif
1339
1340 #ifdef USE_SHARED_MANAGER
1341         if (taskmgr != NULL) {
1342                 if (taskmgr->refs == 0)
1343                         return (ISC_R_SHUTTINGDOWN);
1344                 taskmgr->refs++;
1345                 *managerp = (isc_taskmgr_t *)taskmgr;
1346                 return (ISC_R_SUCCESS);
1347         }
1348 #endif /* USE_SHARED_MANAGER */
1349
1350         manager = isc_mem_get(mctx, sizeof(*manager));
1351         if (manager == NULL)
1352                 return (ISC_R_NOMEMORY);
1353         manager->common.methods = &taskmgrmethods;
1354         manager->common.impmagic = TASK_MANAGER_MAGIC;
1355         manager->common.magic = ISCAPI_TASKMGR_MAGIC;
1356         manager->mode = isc_taskmgrmode_normal;
1357         manager->mctx = NULL;
1358         result = isc_mutex_init(&manager->lock);
1359         if (result != ISC_R_SUCCESS)
1360                 goto cleanup_mgr;
1361         LOCK(&manager->lock);
1362
1363 #ifdef USE_WORKER_THREADS
1364         manager->workers = 0;
1365         manager->threads = isc_mem_allocate(mctx,
1366                                             workers * sizeof(isc_thread_t));
1367         if (manager->threads == NULL) {
1368                 result = ISC_R_NOMEMORY;
1369                 goto cleanup_lock;
1370         }
1371         if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
1372                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1373                                  "isc_condition_init() %s",
1374                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1375                                                 ISC_MSG_FAILED, "failed"));
1376                 result = ISC_R_UNEXPECTED;
1377                 goto cleanup_threads;
1378         }
1379         if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
1380                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1381                                  "isc_condition_init() %s",
1382                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1383                                                 ISC_MSG_FAILED, "failed"));
1384                 result = ISC_R_UNEXPECTED;
1385                 goto cleanup_workavailable;
1386         }
1387         if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS) {
1388                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1389                                  "isc_condition_init() %s",
1390                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
1391                                                 ISC_MSG_FAILED, "failed"));
1392                 result = ISC_R_UNEXPECTED;
1393                 goto cleanup_exclusivegranted;
1394         }
1395 #endif /* USE_WORKER_THREADS */
1396         if (default_quantum == 0)
1397                 default_quantum = DEFAULT_DEFAULT_QUANTUM;
1398         manager->default_quantum = default_quantum;
1399         INIT_LIST(manager->tasks);
1400         INIT_LIST(manager->ready_tasks);
1401         INIT_LIST(manager->ready_priority_tasks);
1402         manager->tasks_running = 0;
1403         manager->exclusive_requested = ISC_FALSE;
1404         manager->pause_requested = ISC_FALSE;
1405         manager->exiting = ISC_FALSE;
1406
1407         isc_mem_attach(mctx, &manager->mctx);
1408
1409 #ifdef USE_WORKER_THREADS
1410         /*
1411          * Start workers.
1412          */
1413         for (i = 0; i < workers; i++) {
1414                 if (isc_thread_create(run, manager,
1415                                       &manager->threads[manager->workers]) ==
1416                     ISC_R_SUCCESS) {
1417                         manager->workers++;
1418                         started++;
1419                 }
1420         }
1421         UNLOCK(&manager->lock);
1422
1423         if (started == 0) {
1424                 manager_free(manager);
1425                 return (ISC_R_NOTHREADS);
1426         }
1427         isc_thread_setconcurrency(workers);
1428 #endif /* USE_WORKER_THREADS */
1429 #ifdef USE_SHARED_MANAGER
1430         manager->refs = 1;
1431         UNLOCK(&manager->lock);
1432         taskmgr = manager;
1433 #endif /* USE_SHARED_MANAGER */
1434
1435         *managerp = (isc_taskmgr_t *)manager;
1436
1437         return (ISC_R_SUCCESS);
1438
1439 #ifdef USE_WORKER_THREADS
1440  cleanup_exclusivegranted:
1441         (void)isc_condition_destroy(&manager->exclusive_granted);
1442  cleanup_workavailable:
1443         (void)isc_condition_destroy(&manager->work_available);
1444  cleanup_threads:
1445         isc_mem_free(mctx, manager->threads);
1446  cleanup_lock:
1447         UNLOCK(&manager->lock);
1448         DESTROYLOCK(&manager->lock);
1449 #endif
1450  cleanup_mgr:
1451         isc_mem_put(mctx, manager, sizeof(*manager));
1452         return (result);
1453 }
1454
1455 ISC_TASKFUNC_SCOPE void
1456 isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
1457         isc__taskmgr_t *manager;
1458         isc__task_t *task;
1459         unsigned int i;
1460
1461         /*
1462          * Destroy '*managerp'.
1463          */
1464
1465         REQUIRE(managerp != NULL);
1466         manager = (void*)(*managerp);
1467         REQUIRE(VALID_MANAGER(manager));
1468
1469 #ifndef USE_WORKER_THREADS
1470         UNUSED(i);
1471 #endif /* USE_WORKER_THREADS */
1472
1473 #ifdef USE_SHARED_MANAGER
1474         manager->refs--;
1475         if (manager->refs > 0) {
1476                 *managerp = NULL;
1477                 return;
1478         }
1479 #endif
1480
1481         XTHREADTRACE("isc_taskmgr_destroy");
1482         /*
1483          * Only one non-worker thread may ever call this routine.
1484          * If a worker thread wants to initiate shutdown of the
1485          * task manager, it should ask some non-worker thread to call
1486          * isc_taskmgr_destroy(), e.g. by signalling a condition variable
1487          * that the startup thread is sleeping on.
1488          */
1489
1490         /*
1491          * Unlike elsewhere, we're going to hold this lock a long time.
1492          * We need to do so, because otherwise the list of tasks could
1493          * change while we were traversing it.
1494          *
1495          * This is also the only function where we will hold both the
1496          * task manager lock and a task lock at the same time.
1497          */
1498
1499         LOCK(&manager->lock);
1500
1501         /*
1502          * Make sure we only get called once.
1503          */
1504         INSIST(!manager->exiting);
1505         manager->exiting = ISC_TRUE;
1506
1507         /*
1508          * If privileged mode was on, turn it off.
1509          */
1510         manager->mode = isc_taskmgrmode_normal;
1511
1512         /*
1513          * Post shutdown event(s) to every task (if they haven't already been
1514          * posted).
1515          */
1516         for (task = HEAD(manager->tasks);
1517              task != NULL;
1518              task = NEXT(task, link)) {
1519                 LOCK(&task->lock);
1520                 if (task_shutdown(task))
1521                         push_readyq(manager, task);
1522                 UNLOCK(&task->lock);
1523         }
1524 #ifdef USE_WORKER_THREADS
1525         /*
1526          * Wake up any sleeping workers.  This ensures we get work done if
1527          * there's work left to do, and if there are already no tasks left
1528          * it will cause the workers to see manager->exiting.
1529          */
1530         BROADCAST(&manager->work_available);
1531         UNLOCK(&manager->lock);
1532
1533         /*
1534          * Wait for all the worker threads to exit.
1535          */
1536         for (i = 0; i < manager->workers; i++)
1537                 (void)isc_thread_join(manager->threads[i], NULL);
1538 #else /* USE_WORKER_THREADS */
1539         /*
1540          * Dispatch the shutdown events.
1541          */
1542         UNLOCK(&manager->lock);
1543         while (isc__taskmgr_ready((isc_taskmgr_t *)manager))
1544                 (void)isc__taskmgr_dispatch((isc_taskmgr_t *)manager);
1545 #ifdef BIND9
1546         if (!ISC_LIST_EMPTY(manager->tasks))
1547                 isc_mem_printallactive(stderr);
1548 #endif
1549         INSIST(ISC_LIST_EMPTY(manager->tasks));
1550 #ifdef USE_SHARED_MANAGER
1551         taskmgr = NULL;
1552 #endif
1553 #endif /* USE_WORKER_THREADS */
1554
1555         manager_free(manager);
1556
1557         *managerp = NULL;
1558 }
1559
1560 ISC_TASKFUNC_SCOPE void
1561 isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode) {
1562         isc__taskmgr_t *manager = (void*)manager0;
1563
1564         LOCK(&manager->lock);
1565         manager->mode = mode;
1566         UNLOCK(&manager->lock);
1567 }
1568
1569 ISC_TASKFUNC_SCOPE isc_taskmgrmode_t
1570 isc__taskmgr_mode(isc_taskmgr_t *manager0) {
1571         isc__taskmgr_t *manager = (void*)manager0;
1572         isc_taskmgrmode_t mode;
1573         LOCK(&manager->lock);
1574         mode = manager->mode;
1575         UNLOCK(&manager->lock);
1576         return (mode);
1577 }
1578
1579 #ifndef USE_WORKER_THREADS
1580 isc_boolean_t
1581 isc__taskmgr_ready(isc_taskmgr_t *manager0) {
1582         isc__taskmgr_t *manager = (void*)manager0;
1583         isc_boolean_t is_ready;
1584
1585 #ifdef USE_SHARED_MANAGER
1586         if (manager == NULL)
1587                 manager = taskmgr;
1588 #endif
1589         if (manager == NULL)
1590                 return (ISC_FALSE);
1591
1592         LOCK(&manager->lock);
1593         is_ready = !empty_readyq(manager);
1594         UNLOCK(&manager->lock);
1595
1596         return (is_ready);
1597 }
1598
1599 isc_result_t
1600 isc__taskmgr_dispatch(isc_taskmgr_t *manager0) {
1601         isc__taskmgr_t *manager = (void*)manager0;
1602
1603 #ifdef USE_SHARED_MANAGER
1604         if (manager == NULL)
1605                 manager = taskmgr;
1606 #endif
1607         if (manager == NULL)
1608                 return (ISC_R_NOTFOUND);
1609
1610         dispatch(manager);
1611
1612         return (ISC_R_SUCCESS);
1613 }
1614
1615 #else
1616 ISC_TASKFUNC_SCOPE void
1617 isc__taskmgr_pause(isc_taskmgr_t *manager0) {
1618         isc__taskmgr_t *manager = (void*)manager0;
1619         LOCK(&manager->lock);
1620         while (manager->tasks_running > 0) {
1621                 WAIT(&manager->paused, &manager->lock);
1622         }
1623         manager->pause_requested = ISC_TRUE;
1624         UNLOCK(&manager->lock);
1625 }
1626
1627 ISC_TASKFUNC_SCOPE void
1628 isc__taskmgr_resume(isc_taskmgr_t *manager0) {
1629         isc__taskmgr_t *manager = (void*)manager0;
1630
1631         LOCK(&manager->lock);
1632         if (manager->pause_requested) {
1633                 manager->pause_requested = ISC_FALSE;
1634                 BROADCAST(&manager->work_available);
1635         }
1636         UNLOCK(&manager->lock);
1637 }
1638 #endif /* USE_WORKER_THREADS */
1639
1640 ISC_TASKFUNC_SCOPE isc_result_t
1641 isc__task_beginexclusive(isc_task_t *task0) {
1642 #ifdef USE_WORKER_THREADS
1643         isc__task_t *task = (isc__task_t *)task0;
1644         isc__taskmgr_t *manager = task->manager;
1645         REQUIRE(task->state == task_state_running);
1646         LOCK(&manager->lock);
1647         if (manager->exclusive_requested) {
1648                 UNLOCK(&manager->lock);
1649                 return (ISC_R_LOCKBUSY);
1650         }
1651         manager->exclusive_requested = ISC_TRUE;
1652         while (manager->tasks_running > 1) {
1653                 WAIT(&manager->exclusive_granted, &manager->lock);
1654         }
1655         UNLOCK(&manager->lock);
1656 #else
1657         UNUSED(task0);
1658 #endif
1659         return (ISC_R_SUCCESS);
1660 }
1661
1662 ISC_TASKFUNC_SCOPE void
1663 isc__task_endexclusive(isc_task_t *task0) {
1664 #ifdef USE_WORKER_THREADS
1665         isc__task_t *task = (isc__task_t *)task0;
1666         isc__taskmgr_t *manager = task->manager;
1667
1668         REQUIRE(task->state == task_state_running);
1669         LOCK(&manager->lock);
1670         REQUIRE(manager->exclusive_requested);
1671         manager->exclusive_requested = ISC_FALSE;
1672         BROADCAST(&manager->work_available);
1673         UNLOCK(&manager->lock);
1674 #else
1675         UNUSED(task0);
1676 #endif
1677 }
1678
1679 ISC_TASKFUNC_SCOPE void
1680 isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv) {
1681         isc__task_t *task = (isc__task_t *)task0;
1682         isc__taskmgr_t *manager = task->manager;
1683         isc_boolean_t oldpriv;
1684
1685         LOCK(&task->lock);
1686         oldpriv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
1687         if (priv)
1688                 task->flags |= TASK_F_PRIVILEGED;
1689         else
1690                 task->flags &= ~TASK_F_PRIVILEGED;
1691         UNLOCK(&task->lock);
1692
1693         if (priv == oldpriv)
1694                 return;
1695
1696         LOCK(&manager->lock);
1697         if (priv && ISC_LINK_LINKED(task, ready_link))
1698                 ENQUEUE(manager->ready_priority_tasks, task,
1699                         ready_priority_link);
1700         else if (!priv && ISC_LINK_LINKED(task, ready_priority_link))
1701                 DEQUEUE(manager->ready_priority_tasks, task,
1702                         ready_priority_link);
1703         UNLOCK(&manager->lock);
1704 }
1705
1706 ISC_TASKFUNC_SCOPE isc_boolean_t
1707 isc__task_privilege(isc_task_t *task0) {
1708         isc__task_t *task = (isc__task_t *)task0;
1709         isc_boolean_t priv;
1710
1711         LOCK(&task->lock);
1712         priv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
1713         UNLOCK(&task->lock);
1714         return (priv);
1715 }
1716
1717 #ifdef USE_SOCKETIMPREGISTER
1718 isc_result_t
1719 isc__task_register() {
1720         return (isc_task_register(isc__taskmgr_create));
1721 }
1722 #endif
1723
1724 isc_boolean_t
1725 isc_task_exiting(isc_task_t *t) {
1726         isc__task_t *task = (isc__task_t *)t;
1727
1728         REQUIRE(VALID_TASK(task));
1729         return (TASK_SHUTTINGDOWN(task));
1730 }
1731
1732
1733 #if defined(HAVE_LIBXML2) && defined(BIND9)
1734 void
1735 isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
1736         isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
1737         isc__task_t *task;
1738
1739         LOCK(&mgr->lock);
1740
1741         /*
1742          * Write out the thread-model, and some details about each depending
1743          * on which type is enabled.
1744          */
1745         xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model");
1746 #ifdef ISC_PLATFORM_USETHREADS
1747         xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
1748         xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded");
1749         xmlTextWriterEndElement(writer); /* type */
1750
1751         xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads");
1752         xmlTextWriterWriteFormatString(writer, "%d", mgr->workers);
1753         xmlTextWriterEndElement(writer); /* worker-threads */
1754 #else /* ISC_PLATFORM_USETHREADS */
1755         xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
1756         xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded");
1757         xmlTextWriterEndElement(writer); /* type */
1758
1759         xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
1760         xmlTextWriterWriteFormatString(writer, "%d", mgr->refs);
1761         xmlTextWriterEndElement(writer); /* references */
1762 #endif /* ISC_PLATFORM_USETHREADS */
1763
1764         xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum");
1765         xmlTextWriterWriteFormatString(writer, "%d", mgr->default_quantum);
1766         xmlTextWriterEndElement(writer); /* default-quantum */
1767
1768         xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running");
1769         xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running);
1770         xmlTextWriterEndElement(writer); /* tasks-running */
1771
1772         xmlTextWriterEndElement(writer); /* thread-model */
1773
1774         xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks");
1775         task = ISC_LIST_HEAD(mgr->tasks);
1776         while (task != NULL) {
1777                 LOCK(&task->lock);
1778                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "task");
1779
1780                 if (task->name[0] != 0) {
1781                         xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
1782                         xmlTextWriterWriteFormatString(writer, "%s",
1783                                                        task->name);
1784                         xmlTextWriterEndElement(writer); /* name */
1785                 }
1786
1787                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
1788                 xmlTextWriterWriteFormatString(writer, "%d", task->references);
1789                 xmlTextWriterEndElement(writer); /* references */
1790
1791                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
1792                 xmlTextWriterWriteFormatString(writer, "%p", task);
1793                 xmlTextWriterEndElement(writer); /* id */
1794
1795                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "state");
1796                 xmlTextWriterWriteFormatString(writer, "%s",
1797                                                statenames[task->state]);
1798                 xmlTextWriterEndElement(writer); /* state */
1799
1800                 xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum");
1801                 xmlTextWriterWriteFormatString(writer, "%d", task->quantum);
1802                 xmlTextWriterEndElement(writer); /* quantum */
1803
1804                 xmlTextWriterEndElement(writer);
1805
1806                 UNLOCK(&task->lock);
1807                 task = ISC_LIST_NEXT(task, link);
1808         }
1809         xmlTextWriterEndElement(writer); /* tasks */
1810
1811         UNLOCK(&mgr->lock);
1812 }
1813 #endif /* HAVE_LIBXML2 && BIND9 */