task.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1998-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file
00021  * \author Principal Author: Bob Halley
00022  */
00023 
00024 /*
00025  * XXXRTH  Need to document the states a task can be in, and the rules
00026  * for changing states.
00027  */
00028 
00029 #include <config.h>
00030 
00031 #include <isc/app.h>
00032 #include <isc/condition.h>
00033 #include <isc/event.h>
00034 #include <isc/json.h>
00035 #include <isc/magic.h>
00036 #include <isc/mem.h>
00037 #include <isc/msgs.h>
00038 #include <isc/once.h>
00039 #include <isc/platform.h>
00040 #include <isc/string.h>
00041 #include <isc/task.h>
00042 #include <isc/thread.h>
00043 #include <isc/util.h>
00044 #include <isc/xml.h>
00045 
00046 #ifdef OPENSSL_LEAKS
00047 #include <openssl/err.h>
00048 #endif
00049 
00050 /*%
00051  * For BIND9 internal applications:
00052  * when built with threads we use multiple worker threads shared by the whole
00053  * application.
00054  * when built without threads we share a single global task manager and use
00055  * an integrated event loop for socket, timer, and other generic task events.
00056  * For generic library:
00057  * we don't use either of them: an application can have multiple task managers
00058  * whether or not it's threaded, and if the application is threaded each thread
00059  * is expected to have a separate manager; no "worker threads" are shared by
00060  * the application threads.
00061  */
00062 #ifdef ISC_PLATFORM_USETHREADS
00063 #define USE_WORKER_THREADS
00064 #else
00065 #define USE_SHARED_MANAGER
00066 #endif  /* ISC_PLATFORM_USETHREADS */
00067 
00068 #include "task_p.h"
00069 
00070 #ifdef ISC_TASK_TRACE
00071 #define XTRACE(m)               fprintf(stderr, "task %p thread %lu: %s\n", \
00072                                        task, isc_thread_self(), (m))
00073 #define XTTRACE(t, m)           fprintf(stderr, "task %p thread %lu: %s\n", \
00074                                        (t), isc_thread_self(), (m))
00075 #define XTHREADTRACE(m)         fprintf(stderr, "thread %lu: %s\n", \
00076                                        isc_thread_self(), (m))
00077 #else
00078 #define XTRACE(m)
00079 #define XTTRACE(t, m)
00080 #define XTHREADTRACE(m)
00081 #endif
00082 
00083 /***
00084  *** Types.
00085  ***/
00086 
00087 typedef enum {
00088         task_state_idle, task_state_ready, task_state_running,
00089         task_state_done
00090 } task_state_t;
00091 
00092 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
00093 static const char *statenames[] = {
00094         "idle", "ready", "running", "done",
00095 };
00096 #endif
00097 
00098 #define TASK_MAGIC                      ISC_MAGIC('T', 'A', 'S', 'K')
00099 #define VALID_TASK(t)                   ISC_MAGIC_VALID(t, TASK_MAGIC)
00100 
00101 typedef struct isc__task isc__task_t;
00102 typedef struct isc__taskmgr isc__taskmgr_t;
00103 
00104 struct isc__task {
00105         /* Not locked. */
00106         isc_task_t                      common;
00107         isc__taskmgr_t *                manager;
00108         isc_mutex_t                     lock;
00109         /* Locked by task lock. */
00110         task_state_t                    state;
00111         unsigned int                    references;
00112         isc_eventlist_t                 events;
00113         isc_eventlist_t                 on_shutdown;
00114         unsigned int                    nevents;
00115         unsigned int                    quantum;
00116         unsigned int                    flags;
00117         isc_stdtime_t                   now;
00118         char                            name[16];
00119         void *                          tag;
00120         /* Locked by task manager lock. */
00121         LINK(isc__task_t)               link;
00122         LINK(isc__task_t)               ready_link;
00123         LINK(isc__task_t)               ready_priority_link;
00124 };
00125 
00126 #define TASK_F_SHUTTINGDOWN             0x01
00127 #define TASK_F_PRIVILEGED               0x02
00128 
00129 #define TASK_SHUTTINGDOWN(t)            (((t)->flags & TASK_F_SHUTTINGDOWN) \
00130                                          != 0)
00131 
00132 #define TASK_MANAGER_MAGIC              ISC_MAGIC('T', 'S', 'K', 'M')
00133 #define VALID_MANAGER(m)                ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
00134 
00135 typedef ISC_LIST(isc__task_t)   isc__tasklist_t;
00136 
00137 struct isc__taskmgr {
00138         /* Not locked. */
00139         isc_taskmgr_t                   common;
00140         isc_mem_t *                     mctx;
00141         isc_mutex_t                     lock;
00142 #ifdef ISC_PLATFORM_USETHREADS
00143         unsigned int                    workers;
00144         isc_thread_t *                  threads;
00145 #endif /* ISC_PLATFORM_USETHREADS */
00146         /* Locked by task manager lock. */
00147         unsigned int                    default_quantum;
00148         LIST(isc__task_t)               tasks;
00149         isc__tasklist_t                 ready_tasks;
00150         isc__tasklist_t                 ready_priority_tasks;
00151         isc_taskmgrmode_t               mode;
00152 #ifdef ISC_PLATFORM_USETHREADS
00153         isc_condition_t                 work_available;
00154         isc_condition_t                 exclusive_granted;
00155         isc_condition_t                 paused;
00156 #endif /* ISC_PLATFORM_USETHREADS */
00157         unsigned int                    tasks_running;
00158         unsigned int                    tasks_ready;
00159         isc_boolean_t                   pause_requested;
00160         isc_boolean_t                   exclusive_requested;
00161         isc_boolean_t                   exiting;
00162 
00163         /*
00164          * Multiple threads can read/write 'excl' at the same time, so we need
00165          * to protect the access.  We can't use 'lock' since isc_task_detach()
00166          * will try to acquire it.
00167          */
00168         isc_mutex_t                     excl_lock;
00169         isc__task_t                     *excl;
00170 #ifdef USE_SHARED_MANAGER
00171         unsigned int                    refs;
00172 #endif /* ISC_PLATFORM_USETHREADS */
00173 };
00174 
00175 #define DEFAULT_TASKMGR_QUANTUM         10
00176 #define DEFAULT_DEFAULT_QUANTUM         5
00177 #define FINISHED(m)                     ((m)->exiting && EMPTY((m)->tasks))
00178 
00179 #ifdef USE_SHARED_MANAGER
00180 static isc__taskmgr_t *taskmgr = NULL;
00181 #endif /* USE_SHARED_MANAGER */
00182 
00183 /*%
00184  * The following are intended for internal use (indicated by "isc__"
00185  * prefix) but are not declared as static, allowing direct access from
00186  * unit tests etc.
00187  */
00188 
00189 isc_result_t
00190 isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
00191                  isc_task_t **taskp);
00192 void
00193 isc__task_attach(isc_task_t *source0, isc_task_t **targetp);
00194 void
00195 isc__task_detach(isc_task_t **taskp);
00196 void
00197 isc__task_send(isc_task_t *task0, isc_event_t **eventp);
00198 void
00199 isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
00200 unsigned int
00201 isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
00202                      isc_eventtype_t last, void *tag);
00203 unsigned int
00204 isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
00205                 void *tag);
00206 isc_boolean_t
00207 isc_task_purgeevent(isc_task_t *task0, isc_event_t *event);
00208 unsigned int
00209 isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
00210                       isc_eventtype_t last, void *tag,
00211                       isc_eventlist_t *events);
00212 unsigned int
00213 isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
00214                  void *tag, isc_eventlist_t *events);
00215 isc_result_t
00216 isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
00217                      void *arg);
00218 void
00219 isc__task_shutdown(isc_task_t *task0);
00220 void
00221 isc__task_destroy(isc_task_t **taskp);
00222 void
00223 isc__task_setname(isc_task_t *task0, const char *name, void *tag);
00224 const char *
00225 isc__task_getname(isc_task_t *task0);
00226 void *
00227 isc__task_gettag(isc_task_t *task0);
00228 void
00229 isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t);
00230 isc_result_t
00231 isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
00232                     unsigned int default_quantum, isc_taskmgr_t **managerp);
00233 void
00234 isc__taskmgr_destroy(isc_taskmgr_t **managerp);
00235 void
00236 isc_taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0);
00237 isc_result_t
00238 isc_taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp);
00239 isc_result_t
00240 isc__task_beginexclusive(isc_task_t *task);
00241 void
00242 isc__task_endexclusive(isc_task_t *task0);
00243 void
00244 isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv);
00245 isc_boolean_t
00246 isc__task_privilege(isc_task_t *task0);
00247 void
00248 isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode);
00249 isc_taskmgrmode_t
00250 isc__taskmgr_mode(isc_taskmgr_t *manager0);
00251 
00252 static inline isc_boolean_t
00253 empty_readyq(isc__taskmgr_t *manager);
00254 
00255 static inline isc__task_t *
00256 pop_readyq(isc__taskmgr_t *manager);
00257 
00258 static inline void
00259 push_readyq(isc__taskmgr_t *manager, isc__task_t *task);
00260 
00261 static struct isc__taskmethods {
00262         isc_taskmethods_t methods;
00263 
00264         /*%
00265          * The following are defined just for avoiding unused static functions.
00266          */
00267         void *purgeevent, *unsendrange, *getname, *gettag, *getcurrenttime;
00268 } taskmethods = {
00269         {
00270                 isc__task_attach,
00271                 isc__task_detach,
00272                 isc__task_destroy,
00273                 isc__task_send,
00274                 isc__task_sendanddetach,
00275                 isc__task_unsend,
00276                 isc__task_onshutdown,
00277                 isc__task_shutdown,
00278                 isc__task_setname,
00279                 isc__task_purge,
00280                 isc__task_purgerange,
00281                 isc__task_beginexclusive,
00282                 isc__task_endexclusive,
00283                 isc__task_setprivilege,
00284                 isc__task_privilege
00285         },
00286         (void *)isc_task_purgeevent,
00287         (void *)isc__task_unsendrange,
00288         (void *)isc__task_getname,
00289         (void *)isc__task_gettag,
00290         (void *)isc__task_getcurrenttime
00291 };
00292 
00293 static isc_taskmgrmethods_t taskmgrmethods = {
00294         isc__taskmgr_destroy,
00295         isc__taskmgr_setmode,
00296         isc__taskmgr_mode,
00297         isc__task_create,
00298         isc_taskmgr_setexcltask,
00299         isc_taskmgr_excltask
00300 };
00301 
00302 /***
00303  *** Tasks.
00304  ***/
00305 
00306 static void
00307 task_finished(isc__task_t *task) {
00308         isc__taskmgr_t *manager = task->manager;
00309 
00310         REQUIRE(EMPTY(task->events));
00311         REQUIRE(task->nevents == 0);
00312         REQUIRE(EMPTY(task->on_shutdown));
00313         REQUIRE(task->references == 0);
00314         REQUIRE(task->state == task_state_done);
00315 
00316         XTRACE("task_finished");
00317 
00318         LOCK(&manager->lock);
00319         UNLINK(manager->tasks, task, link);
00320 #ifdef USE_WORKER_THREADS
00321         if (FINISHED(manager)) {
00322                 /*
00323                  * All tasks have completed and the
00324                  * task manager is exiting.  Wake up
00325                  * any idle worker threads so they
00326                  * can exit.
00327                  */
00328                 BROADCAST(&manager->work_available);
00329         }
00330 #endif /* USE_WORKER_THREADS */
00331         UNLOCK(&manager->lock);
00332 
00333         DESTROYLOCK(&task->lock);
00334         task->common.impmagic = 0;
00335         task->common.magic = 0;
00336         isc_mem_put(manager->mctx, task, sizeof(*task));
00337 }
00338 
00339 isc_result_t
00340 isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
00341                  isc_task_t **taskp)
00342 {
00343         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
00344         isc__task_t *task;
00345         isc_boolean_t exiting;
00346         isc_result_t result;
00347 
00348         REQUIRE(VALID_MANAGER(manager));
00349         REQUIRE(taskp != NULL && *taskp == NULL);
00350 
00351         task = isc_mem_get(manager->mctx, sizeof(*task));
00352         if (task == NULL)
00353                 return (ISC_R_NOMEMORY);
00354         XTRACE("isc_task_create");
00355         task->manager = manager;
00356         result = isc_mutex_init(&task->lock);
00357         if (result != ISC_R_SUCCESS) {
00358                 isc_mem_put(manager->mctx, task, sizeof(*task));
00359                 return (result);
00360         }
00361         task->state = task_state_idle;
00362         task->references = 1;
00363         INIT_LIST(task->events);
00364         INIT_LIST(task->on_shutdown);
00365         task->nevents = 0;
00366         task->quantum = quantum;
00367         task->flags = 0;
00368         task->now = 0;
00369         memset(task->name, 0, sizeof(task->name));
00370         task->tag = NULL;
00371         INIT_LINK(task, link);
00372         INIT_LINK(task, ready_link);
00373         INIT_LINK(task, ready_priority_link);
00374 
00375         exiting = ISC_FALSE;
00376         LOCK(&manager->lock);
00377         if (!manager->exiting) {
00378                 if (task->quantum == 0)
00379                         task->quantum = manager->default_quantum;
00380                 APPEND(manager->tasks, task, link);
00381         } else
00382                 exiting = ISC_TRUE;
00383         UNLOCK(&manager->lock);
00384 
00385         if (exiting) {
00386                 DESTROYLOCK(&task->lock);
00387                 isc_mem_put(manager->mctx, task, sizeof(*task));
00388                 return (ISC_R_SHUTTINGDOWN);
00389         }
00390 
00391         task->common.methods = (isc_taskmethods_t *)&taskmethods;
00392         task->common.magic = ISCAPI_TASK_MAGIC;
00393         task->common.impmagic = TASK_MAGIC;
00394         *taskp = (isc_task_t *)task;
00395 
00396         return (ISC_R_SUCCESS);
00397 }
00398 
00399 void
00400 isc__task_attach(isc_task_t *source0, isc_task_t **targetp) {
00401         isc__task_t *source = (isc__task_t *)source0;
00402 
00403         /*
00404          * Attach *targetp to source.
00405          */
00406 
00407         REQUIRE(VALID_TASK(source));
00408         REQUIRE(targetp != NULL && *targetp == NULL);
00409 
00410         XTTRACE(source, "isc_task_attach");
00411 
00412         LOCK(&source->lock);
00413         source->references++;
00414         UNLOCK(&source->lock);
00415 
00416         *targetp = (isc_task_t *)source;
00417 }
00418 
00419 static inline isc_boolean_t
00420 task_shutdown(isc__task_t *task) {
00421         isc_boolean_t was_idle = ISC_FALSE;
00422         isc_event_t *event, *prev;
00423 
00424         /*
00425          * Caller must be holding the task's lock.
00426          */
00427 
00428         XTRACE("task_shutdown");
00429 
00430         if (! TASK_SHUTTINGDOWN(task)) {
00431                 XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
00432                                       ISC_MSG_SHUTTINGDOWN, "shutting down"));
00433                 task->flags |= TASK_F_SHUTTINGDOWN;
00434                 if (task->state == task_state_idle) {
00435                         INSIST(EMPTY(task->events));
00436                         task->state = task_state_ready;
00437                         was_idle = ISC_TRUE;
00438                 }
00439                 INSIST(task->state == task_state_ready ||
00440                        task->state == task_state_running);
00441 
00442                 /*
00443                  * Note that we post shutdown events LIFO.
00444                  */
00445                 for (event = TAIL(task->on_shutdown);
00446                      event != NULL;
00447                      event = prev) {
00448                         prev = PREV(event, ev_link);
00449                         DEQUEUE(task->on_shutdown, event, ev_link);
00450                         ENQUEUE(task->events, event, ev_link);
00451                         task->nevents++;
00452                 }
00453         }
00454 
00455         return (was_idle);
00456 }
00457 
00458 /*
00459  * Moves a task onto the appropriate run queue.
00460  *
00461  * Caller must NOT hold manager lock.
00462  */
00463 static inline void
00464 task_ready(isc__task_t *task) {
00465         isc__taskmgr_t *manager = task->manager;
00466 #ifdef USE_WORKER_THREADS
00467         isc_boolean_t has_privilege = isc__task_privilege((isc_task_t *) task);
00468 #endif /* USE_WORKER_THREADS */
00469 
00470         REQUIRE(VALID_MANAGER(manager));
00471         REQUIRE(task->state == task_state_ready);
00472 
00473         XTRACE("task_ready");
00474 
00475         LOCK(&manager->lock);
00476         push_readyq(manager, task);
00477 #ifdef USE_WORKER_THREADS
00478         if (manager->mode == isc_taskmgrmode_normal || has_privilege)
00479                 SIGNAL(&manager->work_available);
00480 #endif /* USE_WORKER_THREADS */
00481         UNLOCK(&manager->lock);
00482 }
00483 
00484 static inline isc_boolean_t
00485 task_detach(isc__task_t *task) {
00486 
00487         /*
00488          * Caller must be holding the task lock.
00489          */
00490 
00491         REQUIRE(task->references > 0);
00492 
00493         XTRACE("detach");
00494 
00495         task->references--;
00496         if (task->references == 0 && task->state == task_state_idle) {
00497                 INSIST(EMPTY(task->events));
00498                 /*
00499                  * There are no references to this task, and no
00500                  * pending events.  We could try to optimize and
00501                  * either initiate shutdown or clean up the task,
00502                  * depending on its state, but it's easier to just
00503                  * make the task ready and allow run() or the event
00504                  * loop to deal with shutting down and termination.
00505                  */
00506                 task->state = task_state_ready;
00507                 return (ISC_TRUE);
00508         }
00509 
00510         return (ISC_FALSE);
00511 }
00512 
00513 void
00514 isc__task_detach(isc_task_t **taskp) {
00515         isc__task_t *task;
00516         isc_boolean_t was_idle;
00517 
00518         /*
00519          * Detach *taskp from its task.
00520          */
00521 
00522         REQUIRE(taskp != NULL);
00523         task = (isc__task_t *)*taskp;
00524         REQUIRE(VALID_TASK(task));
00525 
00526         XTRACE("isc_task_detach");
00527 
00528         LOCK(&task->lock);
00529         was_idle = task_detach(task);
00530         UNLOCK(&task->lock);
00531 
00532         if (was_idle)
00533                 task_ready(task);
00534 
00535         *taskp = NULL;
00536 }
00537 
00538 static inline isc_boolean_t
00539 task_send(isc__task_t *task, isc_event_t **eventp) {
00540         isc_boolean_t was_idle = ISC_FALSE;
00541         isc_event_t *event;
00542 
00543         /*
00544          * Caller must be holding the task lock.
00545          */
00546 
00547         REQUIRE(eventp != NULL);
00548         event = *eventp;
00549         REQUIRE(event != NULL);
00550         REQUIRE(event->ev_type > 0);
00551         REQUIRE(task->state != task_state_done);
00552 
00553         XTRACE("task_send");
00554 
00555         if (task->state == task_state_idle) {
00556                 was_idle = ISC_TRUE;
00557                 INSIST(EMPTY(task->events));
00558                 task->state = task_state_ready;
00559         }
00560         INSIST(task->state == task_state_ready ||
00561                task->state == task_state_running);
00562         ENQUEUE(task->events, event, ev_link);
00563         task->nevents++;
00564         *eventp = NULL;
00565 
00566         return (was_idle);
00567 }
00568 
00569 void
00570 isc__task_send(isc_task_t *task0, isc_event_t **eventp) {
00571         isc__task_t *task = (isc__task_t *)task0;
00572         isc_boolean_t was_idle;
00573 
00574         /*
00575          * Send '*event' to 'task'.
00576          */
00577 
00578         REQUIRE(VALID_TASK(task));
00579 
00580         XTRACE("isc_task_send");
00581 
00582         /*
00583          * We're trying hard to hold locks for as short a time as possible.
00584          * We're also trying to hold as few locks as possible.  This is why
00585          * some processing is deferred until after the lock is released.
00586          */
00587         LOCK(&task->lock);
00588         was_idle = task_send(task, eventp);
00589         UNLOCK(&task->lock);
00590 
00591         if (was_idle) {
00592                 /*
00593                  * We need to add this task to the ready queue.
00594                  *
00595                  * We've waited until now to do it because making a task
00596                  * ready requires locking the manager.  If we tried to do
00597                  * this while holding the task lock, we could deadlock.
00598                  *
00599                  * We've changed the state to ready, so no one else will
00600                  * be trying to add this task to the ready queue.  The
00601                  * only way to leave the ready state is by executing the
00602                  * task.  It thus doesn't matter if events are added,
00603                  * removed, or a shutdown is started in the interval
00604                  * between the time we released the task lock, and the time
00605                  * we add the task to the ready queue.
00606                  */
00607                 task_ready(task);
00608         }
00609 }
00610 
00611 void
00612 isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
00613         isc_boolean_t idle1, idle2;
00614         isc__task_t *task;
00615 
00616         /*
00617          * Send '*event' to '*taskp' and then detach '*taskp' from its
00618          * task.
00619          */
00620 
00621         REQUIRE(taskp != NULL);
00622         task = (isc__task_t *)*taskp;
00623         REQUIRE(VALID_TASK(task));
00624 
00625         XTRACE("isc_task_sendanddetach");
00626 
00627         LOCK(&task->lock);
00628         idle1 = task_send(task, eventp);
00629         idle2 = task_detach(task);
00630         UNLOCK(&task->lock);
00631 
00632         /*
00633          * If idle1, then idle2 shouldn't be true as well since we're holding
00634          * the task lock, and thus the task cannot switch from ready back to
00635          * idle.
00636          */
00637         INSIST(!(idle1 && idle2));
00638 
00639         if (idle1 || idle2)
00640                 task_ready(task);
00641 
00642         *taskp = NULL;
00643 }
00644 
00645 #define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
00646 
00647 static unsigned int
00648 dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first,
00649                isc_eventtype_t last, void *tag,
00650                isc_eventlist_t *events, isc_boolean_t purging)
00651 {
00652         isc_event_t *event, *next_event;
00653         unsigned int count = 0;
00654 
00655         REQUIRE(VALID_TASK(task));
00656         REQUIRE(last >= first);
00657 
00658         XTRACE("dequeue_events");
00659 
00660         /*
00661          * Events matching 'sender', whose type is >= first and <= last, and
00662          * whose tag is 'tag' will be dequeued.  If 'purging', matching events
00663          * which are marked as unpurgable will not be dequeued.
00664          *
00665          * sender == NULL means "any sender", and tag == NULL means "any tag".
00666          */
00667 
00668         LOCK(&task->lock);
00669 
00670         for (event = HEAD(task->events); event != NULL; event = next_event) {
00671                 next_event = NEXT(event, ev_link);
00672                 if (event->ev_type >= first && event->ev_type <= last &&
00673                     (sender == NULL || event->ev_sender == sender) &&
00674                     (tag == NULL || event->ev_tag == tag) &&
00675                     (!purging || PURGE_OK(event))) {
00676                         DEQUEUE(task->events, event, ev_link);
00677                         task->nevents--;
00678                         ENQUEUE(*events, event, ev_link);
00679                         count++;
00680                 }
00681         }
00682 
00683         UNLOCK(&task->lock);
00684 
00685         return (count);
00686 }
00687 
00688 unsigned int
00689 isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first,
00690                      isc_eventtype_t last, void *tag)
00691 {
00692         isc__task_t *task = (isc__task_t *)task0;
00693         unsigned int count;
00694         isc_eventlist_t events;
00695         isc_event_t *event, *next_event;
00696 
00697         /*
00698          * Purge events from a task's event queue.
00699          */
00700 
00701         XTRACE("isc_task_purgerange");
00702 
00703         ISC_LIST_INIT(events);
00704 
00705         count = dequeue_events(task, sender, first, last, tag, &events,
00706                                ISC_TRUE);
00707 
00708         for (event = HEAD(events); event != NULL; event = next_event) {
00709                 next_event = NEXT(event, ev_link);
00710                 isc_event_free(&event);
00711         }
00712 
00713         /*
00714          * Note that purging never changes the state of the task.
00715          */
00716 
00717         return (count);
00718 }
00719 
00720 unsigned int
00721 isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
00722                 void *tag)
00723 {
00724         /*
00725          * Purge events from a task's event queue.
00726          */
00727 
00728         XTRACE("isc_task_purge");
00729 
00730         return (isc__task_purgerange(task, sender, type, type, tag));
00731 }
00732 
00733 isc_boolean_t
00734 isc_task_purgeevent(isc_task_t *task0, isc_event_t *event) {
00735         isc__task_t *task = (isc__task_t *)task0;
00736         isc_event_t *curr_event, *next_event;
00737 
00738         /*
00739          * Purge 'event' from a task's event queue.
00740          *
00741          * XXXRTH:  WARNING:  This method may be removed before beta.
00742          */
00743 
00744         REQUIRE(VALID_TASK(task));
00745 
00746         /*
00747          * If 'event' is on the task's event queue, it will be purged,
00748          * unless it is marked as unpurgeable.  'event' does not have to be
00749          * on the task's event queue; in fact, it can even be an invalid
00750          * pointer.  Purging only occurs if the event is actually on the task's
00751          * event queue.
00752          *
00753          * Purging never changes the state of the task.
00754          */
00755 
00756         LOCK(&task->lock);
00757         for (curr_event = HEAD(task->events);
00758              curr_event != NULL;
00759              curr_event = next_event) {
00760                 next_event = NEXT(curr_event, ev_link);
00761                 if (curr_event == event && PURGE_OK(event)) {
00762                         DEQUEUE(task->events, curr_event, ev_link);
00763                         task->nevents--;
00764                         break;
00765                 }
00766         }
00767         UNLOCK(&task->lock);
00768 
00769         if (curr_event == NULL)
00770                 return (ISC_FALSE);
00771 
00772         isc_event_free(&curr_event);
00773 
00774         return (ISC_TRUE);
00775 }
00776 
00777 unsigned int
00778 isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
00779                       isc_eventtype_t last, void *tag,
00780                       isc_eventlist_t *events)
00781 {
00782         /*
00783          * Remove events from a task's event queue.
00784          */
00785 
00786         XTRACE("isc_task_unsendrange");
00787 
00788         return (dequeue_events((isc__task_t *)task, sender, first,
00789                                last, tag, events, ISC_FALSE));
00790 }
00791 
00792 unsigned int
00793 isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
00794                  void *tag, isc_eventlist_t *events)
00795 {
00796         /*
00797          * Remove events from a task's event queue.
00798          */
00799 
00800         XTRACE("isc_task_unsend");
00801 
00802         return (dequeue_events((isc__task_t *)task, sender, type,
00803                                type, tag, events, ISC_FALSE));
00804 }
00805 
00806 isc_result_t
00807 isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action,
00808                      void *arg)
00809 {
00810         isc__task_t *task = (isc__task_t *)task0;
00811         isc_boolean_t disallowed = ISC_FALSE;
00812         isc_result_t result = ISC_R_SUCCESS;
00813         isc_event_t *event;
00814 
00815         /*
00816          * Send a shutdown event with action 'action' and argument 'arg' when
00817          * 'task' is shutdown.
00818          */
00819 
00820         REQUIRE(VALID_TASK(task));
00821         REQUIRE(action != NULL);
00822 
00823         event = isc_event_allocate(task->manager->mctx,
00824                                    NULL,
00825                                    ISC_TASKEVENT_SHUTDOWN,
00826                                    action,
00827                                    arg,
00828                                    sizeof(*event));
00829         if (event == NULL)
00830                 return (ISC_R_NOMEMORY);
00831 
00832         LOCK(&task->lock);
00833         if (TASK_SHUTTINGDOWN(task)) {
00834                 disallowed = ISC_TRUE;
00835                 result = ISC_R_SHUTTINGDOWN;
00836         } else
00837                 ENQUEUE(task->on_shutdown, event, ev_link);
00838         UNLOCK(&task->lock);
00839 
00840         if (disallowed)
00841                 isc_mem_put(task->manager->mctx, event, sizeof(*event));
00842 
00843         return (result);
00844 }
00845 
00846 void
00847 isc__task_shutdown(isc_task_t *task0) {
00848         isc__task_t *task = (isc__task_t *)task0;
00849         isc_boolean_t was_idle;
00850 
00851         /*
00852          * Shutdown 'task'.
00853          */
00854 
00855         REQUIRE(VALID_TASK(task));
00856 
00857         LOCK(&task->lock);
00858         was_idle = task_shutdown(task);
00859         UNLOCK(&task->lock);
00860 
00861         if (was_idle)
00862                 task_ready(task);
00863 }
00864 
00865 void
00866 isc__task_destroy(isc_task_t **taskp) {
00867 
00868         /*
00869          * Destroy '*taskp'.
00870          */
00871 
00872         REQUIRE(taskp != NULL);
00873 
00874         isc_task_shutdown(*taskp);
00875         isc_task_detach(taskp);
00876 }
00877 
00878 void
00879 isc__task_setname(isc_task_t *task0, const char *name, void *tag) {
00880         isc__task_t *task = (isc__task_t *)task0;
00881 
00882         /*
00883          * Name 'task'.
00884          */
00885 
00886         REQUIRE(VALID_TASK(task));
00887 
00888         LOCK(&task->lock);
00889         memset(task->name, 0, sizeof(task->name));
00890         strncpy(task->name, name, sizeof(task->name) - 1);
00891         task->tag = tag;
00892         UNLOCK(&task->lock);
00893 }
00894 
00895 const char *
00896 isc__task_getname(isc_task_t *task0) {
00897         isc__task_t *task = (isc__task_t *)task0;
00898 
00899         REQUIRE(VALID_TASK(task));
00900 
00901         return (task->name);
00902 }
00903 
00904 void *
00905 isc__task_gettag(isc_task_t *task0) {
00906         isc__task_t *task = (isc__task_t *)task0;
00907 
00908         REQUIRE(VALID_TASK(task));
00909 
00910         return (task->tag);
00911 }
00912 
00913 void
00914 isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) {
00915         isc__task_t *task = (isc__task_t *)task0;
00916 
00917         REQUIRE(VALID_TASK(task));
00918         REQUIRE(t != NULL);
00919 
00920         LOCK(&task->lock);
00921         *t = task->now;
00922         UNLOCK(&task->lock);
00923 }
00924 
00925 /***
00926  *** Task Manager.
00927  ***/
00928 
00929 /*
00930  * Return ISC_TRUE if the current ready list for the manager, which is
00931  * either ready_tasks or the ready_priority_tasks, depending on whether
00932  * the manager is currently in normal or privileged execution mode.
00933  *
00934  * Caller must hold the task manager lock.
00935  */
00936 static inline isc_boolean_t
00937 empty_readyq(isc__taskmgr_t *manager) {
00938         isc__tasklist_t queue;
00939 
00940         if (manager->mode == isc_taskmgrmode_normal)
00941                 queue = manager->ready_tasks;
00942         else
00943                 queue = manager->ready_priority_tasks;
00944 
00945         return (ISC_TF(EMPTY(queue)));
00946 }
00947 
00948 /*
00949  * Dequeue and return a pointer to the first task on the current ready
00950  * list for the manager.
00951  * If the task is privileged, dequeue it from the other ready list
00952  * as well.
00953  *
00954  * Caller must hold the task manager lock.
00955  */
00956 static inline isc__task_t *
00957 pop_readyq(isc__taskmgr_t *manager) {
00958         isc__task_t *task;
00959 
00960         if (manager->mode == isc_taskmgrmode_normal)
00961                 task = HEAD(manager->ready_tasks);
00962         else
00963                 task = HEAD(manager->ready_priority_tasks);
00964 
00965         if (task != NULL) {
00966                 DEQUEUE(manager->ready_tasks, task, ready_link);
00967                 if (ISC_LINK_LINKED(task, ready_priority_link))
00968                         DEQUEUE(manager->ready_priority_tasks, task,
00969                                 ready_priority_link);
00970         }
00971 
00972         return (task);
00973 }
00974 
00975 /*
00976  * Push 'task' onto the ready_tasks queue.  If 'task' has the privilege
00977  * flag set, then also push it onto the ready_priority_tasks queue.
00978  *
00979  * Caller must hold the task manager lock.
00980  */
00981 static inline void
00982 push_readyq(isc__taskmgr_t *manager, isc__task_t *task) {
00983         ENQUEUE(manager->ready_tasks, task, ready_link);
00984         if ((task->flags & TASK_F_PRIVILEGED) != 0)
00985                 ENQUEUE(manager->ready_priority_tasks, task,
00986                         ready_priority_link);
00987         manager->tasks_ready++;
00988 }
00989 
00990 static void
00991 dispatch(isc__taskmgr_t *manager) {
00992         isc__task_t *task;
00993 #ifndef USE_WORKER_THREADS
00994         unsigned int total_dispatch_count = 0;
00995         isc__tasklist_t new_ready_tasks;
00996         isc__tasklist_t new_priority_tasks;
00997         unsigned int tasks_ready = 0;
00998 #endif /* USE_WORKER_THREADS */
00999 
01000         REQUIRE(VALID_MANAGER(manager));
01001 
01002         /*
01003          * Again we're trying to hold the lock for as short a time as possible
01004          * and to do as little locking and unlocking as possible.
01005          *
01006          * In both while loops, the appropriate lock must be held before the
01007          * while body starts.  Code which acquired the lock at the top of
01008          * the loop would be more readable, but would result in a lot of
01009          * extra locking.  Compare:
01010          *
01011          * Straightforward:
01012          *
01013          *      LOCK();
01014          *      ...
01015          *      UNLOCK();
01016          *      while (expression) {
01017          *              LOCK();
01018          *              ...
01019          *              UNLOCK();
01020          *
01021          *              Unlocked part here...
01022          *
01023          *              LOCK();
01024          *              ...
01025          *              UNLOCK();
01026          *      }
01027          *
01028          * Note how if the loop continues we unlock and then immediately lock.
01029          * For N iterations of the loop, this code does 2N+1 locks and 2N+1
01030          * unlocks.  Also note that the lock is not held when the while
01031          * condition is tested, which may or may not be important, depending
01032          * on the expression.
01033          *
01034          * As written:
01035          *
01036          *      LOCK();
01037          *      while (expression) {
01038          *              ...
01039          *              UNLOCK();
01040          *
01041          *              Unlocked part here...
01042          *
01043          *              LOCK();
01044          *              ...
01045          *      }
01046          *      UNLOCK();
01047          *
01048          * For N iterations of the loop, this code does N+1 locks and N+1
01049          * unlocks.  The while expression is always protected by the lock.
01050          */
01051 
01052 #ifndef USE_WORKER_THREADS
01053         ISC_LIST_INIT(new_ready_tasks);
01054         ISC_LIST_INIT(new_priority_tasks);
01055 #endif
01056         LOCK(&manager->lock);
01057 
01058         while (!FINISHED(manager)) {
01059 #ifdef USE_WORKER_THREADS
01060                 /*
01061                  * For reasons similar to those given in the comment in
01062                  * isc_task_send() above, it is safe for us to dequeue
01063                  * the task while only holding the manager lock, and then
01064                  * change the task to running state while only holding the
01065                  * task lock.
01066                  *
01067                  * If a pause has been requested, don't do any work
01068                  * until it's been released.
01069                  */
01070                 while ((empty_readyq(manager) || manager->pause_requested ||
01071                         manager->exclusive_requested) && !FINISHED(manager))
01072                 {
01073                         XTHREADTRACE(isc_msgcat_get(isc_msgcat,
01074                                                     ISC_MSGSET_GENERAL,
01075                                                     ISC_MSG_WAIT, "wait"));
01076                         WAIT(&manager->work_available, &manager->lock);
01077                         XTHREADTRACE(isc_msgcat_get(isc_msgcat,
01078                                                     ISC_MSGSET_TASK,
01079                                                     ISC_MSG_AWAKE, "awake"));
01080                 }
01081 #else /* USE_WORKER_THREADS */
01082                 if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
01083                     empty_readyq(manager))
01084                         break;
01085 #endif /* USE_WORKER_THREADS */
01086                 XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
01087                                             ISC_MSG_WORKING, "working"));
01088 
01089                 task = pop_readyq(manager);
01090                 if (task != NULL) {
01091                         unsigned int dispatch_count = 0;
01092                         isc_boolean_t done = ISC_FALSE;
01093                         isc_boolean_t requeue = ISC_FALSE;
01094                         isc_boolean_t finished = ISC_FALSE;
01095                         isc_event_t *event;
01096 
01097                         INSIST(VALID_TASK(task));
01098 
01099                         /*
01100                          * Note we only unlock the manager lock if we actually
01101                          * have a task to do.  We must reacquire the manager
01102                          * lock before exiting the 'if (task != NULL)' block.
01103                          */
01104                         manager->tasks_ready--;
01105                         manager->tasks_running++;
01106                         UNLOCK(&manager->lock);
01107 
01108                         LOCK(&task->lock);
01109                         INSIST(task->state == task_state_ready);
01110                         task->state = task_state_running;
01111                         XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01112                                               ISC_MSG_RUNNING, "running"));
01113                         isc_stdtime_get(&task->now);
01114                         do {
01115                                 if (!EMPTY(task->events)) {
01116                                         event = HEAD(task->events);
01117                                         DEQUEUE(task->events, event, ev_link);
01118                                         task->nevents--;
01119 
01120                                         /*
01121                                          * Execute the event action.
01122                                          */
01123                                         XTRACE(isc_msgcat_get(isc_msgcat,
01124                                                             ISC_MSGSET_TASK,
01125                                                             ISC_MSG_EXECUTE,
01126                                                             "execute action"));
01127                                         if (event->ev_action != NULL) {
01128                                                 UNLOCK(&task->lock);
01129                                                 (event->ev_action)(
01130                                                         (isc_task_t *)task,
01131                                                         event);
01132                                                 LOCK(&task->lock);
01133                                         }
01134                                         dispatch_count++;
01135 #ifndef USE_WORKER_THREADS
01136                                         total_dispatch_count++;
01137 #endif /* USE_WORKER_THREADS */
01138                                 }
01139 
01140                                 if (task->references == 0 &&
01141                                     EMPTY(task->events) &&
01142                                     !TASK_SHUTTINGDOWN(task)) {
01143                                         isc_boolean_t was_idle;
01144 
01145                                         /*
01146                                          * There are no references and no
01147                                          * pending events for this task,
01148                                          * which means it will not become
01149                                          * runnable again via an external
01150                                          * action (such as sending an event
01151                                          * or detaching).
01152                                          *
01153                                          * We initiate shutdown to prevent
01154                                          * it from becoming a zombie.
01155                                          *
01156                                          * We do this here instead of in
01157                                          * the "if EMPTY(task->events)" block
01158                                          * below because:
01159                                          *
01160                                          *      If we post no shutdown events,
01161                                          *      we want the task to finish.
01162                                          *
01163                                          *      If we did post shutdown events,
01164                                          *      will still want the task's
01165                                          *      quantum to be applied.
01166                                          */
01167                                         was_idle = task_shutdown(task);
01168                                         INSIST(!was_idle);
01169                                 }
01170 
01171                                 if (EMPTY(task->events)) {
01172                                         /*
01173                                          * Nothing else to do for this task
01174                                          * right now.
01175                                          */
01176                                         XTRACE(isc_msgcat_get(isc_msgcat,
01177                                                               ISC_MSGSET_TASK,
01178                                                               ISC_MSG_EMPTY,
01179                                                               "empty"));
01180                                         if (task->references == 0 &&
01181                                             TASK_SHUTTINGDOWN(task)) {
01182                                                 /*
01183                                                  * The task is done.
01184                                                  */
01185                                                 XTRACE(isc_msgcat_get(
01186                                                                isc_msgcat,
01187                                                                ISC_MSGSET_TASK,
01188                                                                ISC_MSG_DONE,
01189                                                                "done"));
01190                                                 finished = ISC_TRUE;
01191                                                 task->state = task_state_done;
01192                                         } else
01193                                                 task->state = task_state_idle;
01194                                         done = ISC_TRUE;
01195                                 } else if (dispatch_count >= task->quantum) {
01196                                         /*
01197                                          * Our quantum has expired, but
01198                                          * there is more work to be done.
01199                                          * We'll requeue it to the ready
01200                                          * queue later.
01201                                          *
01202                                          * We don't check quantum until
01203                                          * dispatching at least one event,
01204                                          * so the minimum quantum is one.
01205                                          */
01206                                         XTRACE(isc_msgcat_get(isc_msgcat,
01207                                                               ISC_MSGSET_TASK,
01208                                                               ISC_MSG_QUANTUM,
01209                                                               "quantum"));
01210                                         task->state = task_state_ready;
01211                                         requeue = ISC_TRUE;
01212                                         done = ISC_TRUE;
01213                                 }
01214                         } while (!done);
01215                         UNLOCK(&task->lock);
01216 
01217                         if (finished)
01218                                 task_finished(task);
01219 
01220                         LOCK(&manager->lock);
01221                         manager->tasks_running--;
01222 #ifdef USE_WORKER_THREADS
01223                         if (manager->exclusive_requested &&
01224                             manager->tasks_running == 1) {
01225                                 SIGNAL(&manager->exclusive_granted);
01226                         } else if (manager->pause_requested &&
01227                                    manager->tasks_running == 0) {
01228                                 SIGNAL(&manager->paused);
01229                         }
01230 #endif /* USE_WORKER_THREADS */
01231                         if (requeue) {
01232                                 /*
01233                                  * We know we're awake, so we don't have
01234                                  * to wakeup any sleeping threads if the
01235                                  * ready queue is empty before we requeue.
01236                                  *
01237                                  * A possible optimization if the queue is
01238                                  * empty is to 'goto' the 'if (task != NULL)'
01239                                  * block, avoiding the ENQUEUE of the task
01240                                  * and the subsequent immediate DEQUEUE
01241                                  * (since it is the only executable task).
01242                                  * We don't do this because then we'd be
01243                                  * skipping the exit_requested check.  The
01244                                  * cost of ENQUEUE is low anyway, especially
01245                                  * when you consider that we'd have to do
01246                                  * an extra EMPTY check to see if we could
01247                                  * do the optimization.  If the ready queue
01248                                  * were usually nonempty, the 'optimization'
01249                                  * might even hurt rather than help.
01250                                  */
01251 #ifdef USE_WORKER_THREADS
01252                                 push_readyq(manager, task);
01253 #else
01254                                 ENQUEUE(new_ready_tasks, task, ready_link);
01255                                 if ((task->flags & TASK_F_PRIVILEGED) != 0)
01256                                         ENQUEUE(new_priority_tasks, task,
01257                                                 ready_priority_link);
01258                                 tasks_ready++;
01259 #endif
01260                         }
01261                 }
01262 
01263 #ifdef USE_WORKER_THREADS
01264                 /*
01265                  * If we are in privileged execution mode and there are no
01266                  * tasks remaining on the current ready queue, then
01267                  * we're stuck.  Automatically drop privileges at that
01268                  * point and continue with the regular ready queue.
01269                  */
01270                 if (manager->tasks_running == 0 && empty_readyq(manager)) {
01271                         manager->mode = isc_taskmgrmode_normal;
01272                         if (!empty_readyq(manager))
01273                                 BROADCAST(&manager->work_available);
01274                 }
01275 #endif
01276         }
01277 
01278 #ifndef USE_WORKER_THREADS
01279         ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link);
01280         ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks,
01281                             ready_priority_link);
01282         manager->tasks_ready += tasks_ready;
01283         if (empty_readyq(manager))
01284                 manager->mode = isc_taskmgrmode_normal;
01285 #endif
01286 
01287         UNLOCK(&manager->lock);
01288 }
01289 
01290 #ifdef USE_WORKER_THREADS
01291 static isc_threadresult_t
01292 #ifdef _WIN32
01293 WINAPI
01294 #endif
01295 run(void *uap) {
01296         isc__taskmgr_t *manager = uap;
01297 
01298         XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01299                                     ISC_MSG_STARTING, "starting"));
01300 
01301         dispatch(manager);
01302 
01303         XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01304                                     ISC_MSG_EXITING, "exiting"));
01305 
01306 #ifdef OPENSSL_LEAKS
01307         ERR_remove_state(0);
01308 #endif
01309 
01310         return ((isc_threadresult_t)0);
01311 }
01312 #endif /* USE_WORKER_THREADS */
01313 
01314 static void
01315 manager_free(isc__taskmgr_t *manager) {
01316         isc_mem_t *mctx;
01317 
01318 #ifdef USE_WORKER_THREADS
01319         (void)isc_condition_destroy(&manager->exclusive_granted);
01320         (void)isc_condition_destroy(&manager->work_available);
01321         (void)isc_condition_destroy(&manager->paused);
01322         isc_mem_free(manager->mctx, manager->threads);
01323 #endif /* USE_WORKER_THREADS */
01324         DESTROYLOCK(&manager->lock);
01325         DESTROYLOCK(&manager->excl_lock);
01326         manager->common.impmagic = 0;
01327         manager->common.magic = 0;
01328         mctx = manager->mctx;
01329         isc_mem_put(mctx, manager, sizeof(*manager));
01330         isc_mem_detach(&mctx);
01331 
01332 #ifdef USE_SHARED_MANAGER
01333         taskmgr = NULL;
01334 #endif  /* USE_SHARED_MANAGER */
01335 }
01336 
01337 isc_result_t
01338 isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
01339                     unsigned int default_quantum, isc_taskmgr_t **managerp)
01340 {
01341         isc_result_t result;
01342         unsigned int i, started = 0;
01343         isc__taskmgr_t *manager;
01344 
01345         /*
01346          * Create a new task manager.
01347          */
01348 
01349         REQUIRE(workers > 0);
01350         REQUIRE(managerp != NULL && *managerp == NULL);
01351 
01352 #ifndef USE_WORKER_THREADS
01353         UNUSED(i);
01354         UNUSED(started);
01355 #endif
01356 
01357 #ifdef USE_SHARED_MANAGER
01358         if (taskmgr != NULL) {
01359                 if (taskmgr->refs == 0)
01360                         return (ISC_R_SHUTTINGDOWN);
01361                 taskmgr->refs++;
01362                 *managerp = (isc_taskmgr_t *)taskmgr;
01363                 return (ISC_R_SUCCESS);
01364         }
01365 #endif /* USE_SHARED_MANAGER */
01366 
01367         manager = isc_mem_get(mctx, sizeof(*manager));
01368         if (manager == NULL)
01369                 return (ISC_R_NOMEMORY);
01370         manager->common.methods = &taskmgrmethods;
01371         manager->common.impmagic = TASK_MANAGER_MAGIC;
01372         manager->common.magic = ISCAPI_TASKMGR_MAGIC;
01373         manager->mode = isc_taskmgrmode_normal;
01374         manager->mctx = NULL;
01375         result = isc_mutex_init(&manager->lock);
01376         if (result != ISC_R_SUCCESS)
01377                 goto cleanup_mgr;
01378         result = isc_mutex_init(&manager->excl_lock);
01379         if (result != ISC_R_SUCCESS) {
01380                 DESTROYLOCK(&manager->lock);
01381                 goto cleanup_mgr;
01382         }
01383 
01384 #ifdef USE_WORKER_THREADS
01385         manager->workers = 0;
01386         manager->threads = isc_mem_allocate(mctx,
01387                                             workers * sizeof(isc_thread_t));
01388         if (manager->threads == NULL) {
01389                 result = ISC_R_NOMEMORY;
01390                 goto cleanup_lock;
01391         }
01392         if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
01393                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01394                                  "isc_condition_init() %s",
01395                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01396                                                 ISC_MSG_FAILED, "failed"));
01397                 result = ISC_R_UNEXPECTED;
01398                 goto cleanup_threads;
01399         }
01400         if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
01401                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01402                                  "isc_condition_init() %s",
01403                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01404                                                 ISC_MSG_FAILED, "failed"));
01405                 result = ISC_R_UNEXPECTED;
01406                 goto cleanup_workavailable;
01407         }
01408         if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS) {
01409                 UNEXPECTED_ERROR(__FILE__, __LINE__,
01410                                  "isc_condition_init() %s",
01411                                  isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
01412                                                 ISC_MSG_FAILED, "failed"));
01413                 result = ISC_R_UNEXPECTED;
01414                 goto cleanup_exclusivegranted;
01415         }
01416 #endif /* USE_WORKER_THREADS */
01417         if (default_quantum == 0)
01418                 default_quantum = DEFAULT_DEFAULT_QUANTUM;
01419         manager->default_quantum = default_quantum;
01420         INIT_LIST(manager->tasks);
01421         INIT_LIST(manager->ready_tasks);
01422         INIT_LIST(manager->ready_priority_tasks);
01423         manager->tasks_running = 0;
01424         manager->tasks_ready = 0;
01425         manager->exclusive_requested = ISC_FALSE;
01426         manager->pause_requested = ISC_FALSE;
01427         manager->exiting = ISC_FALSE;
01428         manager->excl = NULL;
01429 
01430         isc_mem_attach(mctx, &manager->mctx);
01431 
01432 #ifdef USE_WORKER_THREADS
01433         LOCK(&manager->lock);
01434         /*
01435          * Start workers.
01436          */
01437         for (i = 0; i < workers; i++) {
01438                 if (isc_thread_create(run, manager,
01439                                       &manager->threads[manager->workers]) ==
01440                     ISC_R_SUCCESS) {
01441                         manager->workers++;
01442                         started++;
01443                 }
01444         }
01445         UNLOCK(&manager->lock);
01446 
01447         if (started == 0) {
01448                 manager_free(manager);
01449                 return (ISC_R_NOTHREADS);
01450         }
01451         isc_thread_setconcurrency(workers);
01452 #endif /* USE_WORKER_THREADS */
01453 #ifdef USE_SHARED_MANAGER
01454         manager->refs = 1;
01455         taskmgr = manager;
01456 #endif /* USE_SHARED_MANAGER */
01457 
01458         *managerp = (isc_taskmgr_t *)manager;
01459 
01460         return (ISC_R_SUCCESS);
01461 
01462 #ifdef USE_WORKER_THREADS
01463  cleanup_exclusivegranted:
01464         (void)isc_condition_destroy(&manager->exclusive_granted);
01465  cleanup_workavailable:
01466         (void)isc_condition_destroy(&manager->work_available);
01467  cleanup_threads:
01468         isc_mem_free(mctx, manager->threads);
01469  cleanup_lock:
01470         DESTROYLOCK(&manager->lock);
01471 #endif
01472  cleanup_mgr:
01473         isc_mem_put(mctx, manager, sizeof(*manager));
01474         return (result);
01475 }
01476 
01477 void
01478 isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
01479         isc__taskmgr_t *manager;
01480         isc__task_t *task;
01481         unsigned int i;
01482 
01483         /*
01484          * Destroy '*managerp'.
01485          */
01486 
01487         REQUIRE(managerp != NULL);
01488         manager = (isc__taskmgr_t *)*managerp;
01489         REQUIRE(VALID_MANAGER(manager));
01490 
01491 #ifndef USE_WORKER_THREADS
01492         UNUSED(i);
01493 #endif /* USE_WORKER_THREADS */
01494 
01495 #ifdef USE_SHARED_MANAGER
01496         manager->refs--;
01497         if (manager->refs > 0) {
01498                 *managerp = NULL;
01499                 return;
01500         }
01501 #endif
01502 
01503         XTHREADTRACE("isc_taskmgr_destroy");
01504         /*
01505          * Only one non-worker thread may ever call this routine.
01506          * If a worker thread wants to initiate shutdown of the
01507          * task manager, it should ask some non-worker thread to call
01508          * isc_taskmgr_destroy(), e.g. by signalling a condition variable
01509          * that the startup thread is sleeping on.
01510          */
01511 
01512         /*
01513          * Detach the exclusive task before acquiring the manager lock
01514          */
01515         LOCK(&manager->excl_lock);
01516         if (manager->excl != NULL)
01517                 isc__task_detach((isc_task_t **) &manager->excl);
01518         UNLOCK(&manager->excl_lock);
01519 
01520         /*
01521          * Unlike elsewhere, we're going to hold this lock a long time.
01522          * We need to do so, because otherwise the list of tasks could
01523          * change while we were traversing it.
01524          *
01525          * This is also the only function where we will hold both the
01526          * task manager lock and a task lock at the same time.
01527          */
01528 
01529         LOCK(&manager->lock);
01530 
01531         /*
01532          * Make sure we only get called once.
01533          */
01534         INSIST(!manager->exiting);
01535         manager->exiting = ISC_TRUE;
01536 
01537         /*
01538          * If privileged mode was on, turn it off.
01539          */
01540         manager->mode = isc_taskmgrmode_normal;
01541 
01542         /*
01543          * Post shutdown event(s) to every task (if they haven't already been
01544          * posted).
01545          */
01546         for (task = HEAD(manager->tasks);
01547              task != NULL;
01548              task = NEXT(task, link)) {
01549                 LOCK(&task->lock);
01550                 if (task_shutdown(task))
01551                         push_readyq(manager, task);
01552                 UNLOCK(&task->lock);
01553         }
01554 #ifdef USE_WORKER_THREADS
01555         /*
01556          * Wake up any sleeping workers.  This ensures we get work done if
01557          * there's work left to do, and if there are already no tasks left
01558          * it will cause the workers to see manager->exiting.
01559          */
01560         BROADCAST(&manager->work_available);
01561         UNLOCK(&manager->lock);
01562 
01563         /*
01564          * Wait for all the worker threads to exit.
01565          */
01566         for (i = 0; i < manager->workers; i++)
01567                 (void)isc_thread_join(manager->threads[i], NULL);
01568 #else /* USE_WORKER_THREADS */
01569         /*
01570          * Dispatch the shutdown events.
01571          */
01572         UNLOCK(&manager->lock);
01573         while (isc__taskmgr_ready((isc_taskmgr_t *)manager))
01574                 (void)isc__taskmgr_dispatch((isc_taskmgr_t *)manager);
01575         if (!ISC_LIST_EMPTY(manager->tasks))
01576                 isc_mem_printallactive(stderr);
01577         INSIST(ISC_LIST_EMPTY(manager->tasks));
01578 #ifdef USE_SHARED_MANAGER
01579         taskmgr = NULL;
01580 #endif
01581 #endif /* USE_WORKER_THREADS */
01582 
01583         manager_free(manager);
01584 
01585         *managerp = NULL;
01586 }
01587 
01588 void
01589 isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode) {
01590         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01591 
01592         LOCK(&manager->lock);
01593         manager->mode = mode;
01594         UNLOCK(&manager->lock);
01595 }
01596 
01597 isc_taskmgrmode_t
01598 isc__taskmgr_mode(isc_taskmgr_t *manager0) {
01599         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01600         isc_taskmgrmode_t mode;
01601         LOCK(&manager->lock);
01602         mode = manager->mode;
01603         UNLOCK(&manager->lock);
01604         return (mode);
01605 }
01606 
01607 #ifndef USE_WORKER_THREADS
01608 isc_boolean_t
01609 isc__taskmgr_ready(isc_taskmgr_t *manager0) {
01610         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01611         isc_boolean_t is_ready;
01612 
01613 #ifdef USE_SHARED_MANAGER
01614         if (manager == NULL)
01615                 manager = taskmgr;
01616 #endif
01617         if (manager == NULL)
01618                 return (ISC_FALSE);
01619 
01620         LOCK(&manager->lock);
01621         is_ready = !empty_readyq(manager);
01622         UNLOCK(&manager->lock);
01623 
01624         return (is_ready);
01625 }
01626 
01627 isc_result_t
01628 isc__taskmgr_dispatch(isc_taskmgr_t *manager0) {
01629         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01630 
01631 #ifdef USE_SHARED_MANAGER
01632         if (manager == NULL)
01633                 manager = taskmgr;
01634 #endif
01635         if (manager == NULL)
01636                 return (ISC_R_NOTFOUND);
01637 
01638         dispatch(manager);
01639 
01640         return (ISC_R_SUCCESS);
01641 }
01642 
01643 #else
01644 void
01645 isc__taskmgr_pause(isc_taskmgr_t *manager0) {
01646         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01647         LOCK(&manager->lock);
01648         while (manager->tasks_running > 0) {
01649                 WAIT(&manager->paused, &manager->lock);
01650         }
01651         manager->pause_requested = ISC_TRUE;
01652         UNLOCK(&manager->lock);
01653 }
01654 
01655 void
01656 isc__taskmgr_resume(isc_taskmgr_t *manager0) {
01657         isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
01658 
01659         LOCK(&manager->lock);
01660         if (manager->pause_requested) {
01661                 manager->pause_requested = ISC_FALSE;
01662                 BROADCAST(&manager->work_available);
01663         }
01664         UNLOCK(&manager->lock);
01665 }
01666 #endif /* USE_WORKER_THREADS */
01667 
01668 void
01669 isc_taskmgr_setexcltask(isc_taskmgr_t *mgr0, isc_task_t *task0) {
01670         isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0;
01671         isc__task_t *task = (isc__task_t *) task0;
01672 
01673         REQUIRE(VALID_MANAGER(mgr));
01674         REQUIRE(VALID_TASK(task));
01675         LOCK(&mgr->excl_lock);
01676         if (mgr->excl != NULL)
01677                 isc__task_detach((isc_task_t **) &mgr->excl);
01678         isc__task_attach(task0, (isc_task_t **) &mgr->excl);
01679         UNLOCK(&mgr->excl_lock);
01680 }
01681 
01682 isc_result_t
01683 isc_taskmgr_excltask(isc_taskmgr_t *mgr0, isc_task_t **taskp) {
01684         isc__taskmgr_t *mgr = (isc__taskmgr_t *) mgr0;
01685         isc_result_t result = ISC_R_SUCCESS;
01686 
01687         REQUIRE(VALID_MANAGER(mgr));
01688         REQUIRE(taskp != NULL && *taskp == NULL);
01689 
01690         LOCK(&mgr->excl_lock);
01691         if (mgr->excl != NULL)
01692                 isc__task_attach((isc_task_t *) mgr->excl, taskp);
01693         else
01694                 result = ISC_R_NOTFOUND;
01695         UNLOCK(&mgr->excl_lock);
01696 
01697         return (result);
01698 }
01699 
01700 isc_result_t
01701 isc__task_beginexclusive(isc_task_t *task0) {
01702 #ifdef USE_WORKER_THREADS
01703         isc__task_t *task = (isc__task_t *)task0;
01704         isc__taskmgr_t *manager = task->manager;
01705 
01706         REQUIRE(task->state == task_state_running);
01707         /* XXX: Require task == manager->excl? */
01708 
01709         LOCK(&manager->lock);
01710         if (manager->exclusive_requested) {
01711                 UNLOCK(&manager->lock);
01712                 return (ISC_R_LOCKBUSY);
01713         }
01714         manager->exclusive_requested = ISC_TRUE;
01715         while (manager->tasks_running > 1) {
01716                 WAIT(&manager->exclusive_granted, &manager->lock);
01717         }
01718         UNLOCK(&manager->lock);
01719 #else
01720         UNUSED(task0);
01721 #endif
01722         return (ISC_R_SUCCESS);
01723 }
01724 
01725 void
01726 isc__task_endexclusive(isc_task_t *task0) {
01727 #ifdef USE_WORKER_THREADS
01728         isc__task_t *task = (isc__task_t *)task0;
01729         isc__taskmgr_t *manager = task->manager;
01730 
01731         REQUIRE(task->state == task_state_running);
01732         LOCK(&manager->lock);
01733         REQUIRE(manager->exclusive_requested);
01734         manager->exclusive_requested = ISC_FALSE;
01735         BROADCAST(&manager->work_available);
01736         UNLOCK(&manager->lock);
01737 #else
01738         UNUSED(task0);
01739 #endif
01740 }
01741 
01742 void
01743 isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv) {
01744         isc__task_t *task = (isc__task_t *)task0;
01745         isc__taskmgr_t *manager = task->manager;
01746         isc_boolean_t oldpriv;
01747 
01748         LOCK(&task->lock);
01749         oldpriv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
01750         if (priv)
01751                 task->flags |= TASK_F_PRIVILEGED;
01752         else
01753                 task->flags &= ~TASK_F_PRIVILEGED;
01754         UNLOCK(&task->lock);
01755 
01756         if (priv == oldpriv)
01757                 return;
01758 
01759         LOCK(&manager->lock);
01760         if (priv && ISC_LINK_LINKED(task, ready_link))
01761                 ENQUEUE(manager->ready_priority_tasks, task,
01762                         ready_priority_link);
01763         else if (!priv && ISC_LINK_LINKED(task, ready_priority_link))
01764                 DEQUEUE(manager->ready_priority_tasks, task,
01765                         ready_priority_link);
01766         UNLOCK(&manager->lock);
01767 }
01768 
01769 isc_boolean_t
01770 isc__task_privilege(isc_task_t *task0) {
01771         isc__task_t *task = (isc__task_t *)task0;
01772         isc_boolean_t priv;
01773 
01774         LOCK(&task->lock);
01775         priv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
01776         UNLOCK(&task->lock);
01777         return (priv);
01778 }
01779 
01780 isc_result_t
01781 isc__task_register(void) {
01782         return (isc_task_register(isc__taskmgr_create));
01783 }
01784 
01785 isc_boolean_t
01786 isc_task_exiting(isc_task_t *t) {
01787         isc__task_t *task = (isc__task_t *)t;
01788 
01789         REQUIRE(VALID_TASK(task));
01790         return (TASK_SHUTTINGDOWN(task));
01791 }
01792 
01793 
01794 #ifdef HAVE_LIBXML2
01795 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
01796 int
01797 isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
01798         isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
01799         isc__task_t *task = NULL;
01800         int xmlrc;
01801 
01802         LOCK(&mgr->lock);
01803 
01804         /*
01805          * Write out the thread-model, and some details about each depending
01806          * on which type is enabled.
01807          */
01808         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model"));
01809 #ifdef ISC_PLATFORM_USETHREADS
01810         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
01811         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded"));
01812         TRY0(xmlTextWriterEndElement(writer)); /* type */
01813 
01814         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads"));
01815         TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->workers));
01816         TRY0(xmlTextWriterEndElement(writer)); /* worker-threads */
01817 #else /* ISC_PLATFORM_USETHREADS */
01818         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
01819         TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded"));
01820         TRY0(xmlTextWriterEndElement(writer)); /* type */
01821 
01822         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
01823         TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
01824         TRY0(xmlTextWriterEndElement(writer)); /* references */
01825 #endif /* ISC_PLATFORM_USETHREADS */
01826 
01827         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum"));
01828         TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01829                                             mgr->default_quantum));
01830         TRY0(xmlTextWriterEndElement(writer)); /* default-quantum */
01831 
01832         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running"));
01833         TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running));
01834         TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */
01835 
01836         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"));
01837         TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_ready));
01838         TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */
01839 
01840         TRY0(xmlTextWriterEndElement(writer)); /* thread-model */
01841 
01842         TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks"));
01843         task = ISC_LIST_HEAD(mgr->tasks);
01844         while (task != NULL) {
01845                 LOCK(&task->lock);
01846                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "task"));
01847 
01848                 if (task->name[0] != 0) {
01849                         TRY0(xmlTextWriterStartElement(writer,
01850                                                        ISC_XMLCHAR "name"));
01851                         TRY0(xmlTextWriterWriteFormatString(writer, "%s",
01852                                                        task->name));
01853                         TRY0(xmlTextWriterEndElement(writer)); /* name */
01854                 }
01855 
01856                 TRY0(xmlTextWriterStartElement(writer,
01857                                                ISC_XMLCHAR "references"));
01858                 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01859                                                     task->references));
01860                 TRY0(xmlTextWriterEndElement(writer)); /* references */
01861 
01862                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
01863                 TRY0(xmlTextWriterWriteFormatString(writer, "%p", task));
01864                 TRY0(xmlTextWriterEndElement(writer)); /* id */
01865 
01866                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "state"));
01867                 TRY0(xmlTextWriterWriteFormatString(writer, "%s",
01868                                                statenames[task->state]));
01869                 TRY0(xmlTextWriterEndElement(writer)); /* state */
01870 
01871                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum"));
01872                 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01873                                                     task->quantum));
01874                 TRY0(xmlTextWriterEndElement(writer)); /* quantum */
01875 
01876                 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "events"));
01877                 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01878                                                     task->nevents));
01879                 TRY0(xmlTextWriterEndElement(writer)); /* events */
01880 
01881                 TRY0(xmlTextWriterEndElement(writer));
01882 
01883                 UNLOCK(&task->lock);
01884                 task = ISC_LIST_NEXT(task, link);
01885         }
01886         TRY0(xmlTextWriterEndElement(writer)); /* tasks */
01887 
01888  error:
01889         if (task != NULL)
01890                 UNLOCK(&task->lock);
01891         UNLOCK(&mgr->lock);
01892 
01893         return (xmlrc);
01894 }
01895 #endif /* HAVE_LIBXML2 */
01896 
01897 #ifdef HAVE_JSON
01898 #define CHECKMEM(m) do { \
01899         if (m == NULL) { \
01900                 result = ISC_R_NOMEMORY;\
01901                 goto error;\
01902         } \
01903 } while(0)
01904 
01905 isc_result_t
01906 isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
01907         isc_result_t result = ISC_R_SUCCESS;
01908         isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
01909         isc__task_t *task = NULL;
01910         json_object *obj = NULL, *array = NULL, *taskobj = NULL;
01911 
01912         LOCK(&mgr->lock);
01913 
01914         /*
01915          * Write out the thread-model, and some details about each depending
01916          * on which type is enabled.
01917          */
01918 #ifdef ISC_PLATFORM_USETHREADS
01919         obj = json_object_new_string("threaded");
01920         CHECKMEM(obj);
01921         json_object_object_add(tasks, "thread-model", obj);
01922 
01923         obj = json_object_new_int(mgr->workers);
01924         CHECKMEM(obj);
01925         json_object_object_add(tasks, "worker-threads", obj);
01926 #else /* ISC_PLATFORM_USETHREADS */
01927         obj = json_object_new_string("non-threaded");
01928         CHECKMEM(obj);
01929         json_object_object_add(tasks, "thread-model", obj);
01930 
01931         obj = json_object_new_int(mgr->refs);
01932         CHECKMEM(obj);
01933         json_object_object_add(tasks, "references", obj);
01934 #endif /* ISC_PLATFORM_USETHREADS */
01935 
01936         obj = json_object_new_int(mgr->default_quantum);
01937         CHECKMEM(obj);
01938         json_object_object_add(tasks, "default-quantum", obj);
01939 
01940         obj = json_object_new_int(mgr->tasks_running);
01941         CHECKMEM(obj);
01942         json_object_object_add(tasks, "tasks-running", obj);
01943 
01944         obj = json_object_new_int(mgr->tasks_ready);
01945         CHECKMEM(obj);
01946         json_object_object_add(tasks, "tasks-ready", obj);
01947 
01948         array = json_object_new_array();
01949         CHECKMEM(array);
01950 
01951         for (task = ISC_LIST_HEAD(mgr->tasks);
01952              task != NULL;
01953              task = ISC_LIST_NEXT(task, link))
01954         {
01955                 char buf[255];
01956 
01957                 LOCK(&task->lock);
01958 
01959                 taskobj = json_object_new_object();
01960                 CHECKMEM(taskobj);
01961                 json_object_array_add(array, taskobj);
01962 
01963                 sprintf(buf, "%p", task);
01964                 obj = json_object_new_string(buf);
01965                 CHECKMEM(obj);
01966                 json_object_object_add(taskobj, "id", obj);
01967 
01968                 if (task->name[0] != 0) {
01969                         obj = json_object_new_string(task->name);
01970                         CHECKMEM(obj);
01971                         json_object_object_add(taskobj, "name", obj);
01972                 }
01973 
01974                 obj = json_object_new_int(task->references);
01975                 CHECKMEM(obj);
01976                 json_object_object_add(taskobj, "references", obj);
01977 
01978                 obj = json_object_new_string(statenames[task->state]);
01979                 CHECKMEM(obj);
01980                 json_object_object_add(taskobj, "state", obj);
01981 
01982                 obj = json_object_new_int(task->quantum);
01983                 CHECKMEM(obj);
01984                 json_object_object_add(taskobj, "quantum", obj);
01985 
01986                 obj = json_object_new_int(task->nevents);
01987                 CHECKMEM(obj);
01988                 json_object_object_add(taskobj, "events", obj);
01989 
01990                 UNLOCK(&task->lock);
01991         }
01992 
01993         json_object_object_add(tasks, "tasks", array);
01994         array = NULL;
01995         result = ISC_R_SUCCESS;
01996 
01997  error:
01998         if (array != NULL)
01999                 json_object_put(array);
02000 
02001         if (task != NULL)
02002                 UNLOCK(&task->lock);
02003         UNLOCK(&mgr->lock);
02004 
02005         return (result);
02006 }
02007 #endif
02008 
02009 
02010 static isc_mutex_t createlock;
02011 static isc_once_t once = ISC_ONCE_INIT;
02012 static isc_taskmgrcreatefunc_t taskmgr_createfunc = NULL;
02013 
02014 static void
02015 initialize(void) {
02016         RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
02017 }
02018 
02019 isc_result_t
02020 isc_task_register(isc_taskmgrcreatefunc_t createfunc) {
02021         isc_result_t result = ISC_R_SUCCESS;
02022 
02023         RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
02024 
02025         LOCK(&createlock);
02026         if (taskmgr_createfunc == NULL)
02027                 taskmgr_createfunc = createfunc;
02028         else
02029                 result = ISC_R_EXISTS;
02030         UNLOCK(&createlock);
02031 
02032         return (result);
02033 }
02034 
02035 isc_result_t
02036 isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
02037                         unsigned int workers, unsigned int default_quantum,
02038                         isc_taskmgr_t **managerp)
02039 {
02040         isc_result_t result;
02041 
02042         LOCK(&createlock);
02043 
02044         REQUIRE(taskmgr_createfunc != NULL);
02045         result = (*taskmgr_createfunc)(mctx, workers, default_quantum,
02046                                        managerp);
02047 
02048         UNLOCK(&createlock);
02049 
02050         if (result == ISC_R_SUCCESS)
02051                 isc_appctx_settaskmgr(actx, *managerp);
02052 
02053         return (result);
02054 }
02055 
02056 isc_result_t
02057 isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
02058                    unsigned int default_quantum, isc_taskmgr_t **managerp)
02059 {
02060         isc_result_t result;
02061 
02062         if (isc_bind9)
02063                 return (isc__taskmgr_create(mctx, workers,
02064                                             default_quantum, managerp));
02065         LOCK(&createlock);
02066 
02067         REQUIRE(taskmgr_createfunc != NULL);
02068         result = (*taskmgr_createfunc)(mctx, workers, default_quantum,
02069                                        managerp);
02070 
02071         UNLOCK(&createlock);
02072 
02073         return (result);
02074 }
02075 
02076 void
02077 isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
02078         REQUIRE(managerp != NULL && ISCAPI_TASKMGR_VALID(*managerp));
02079 
02080         if (isc_bind9)
02081                 isc__taskmgr_destroy(managerp);
02082         else
02083                 (*managerp)->methods->destroy(managerp);
02084 
02085         ENSURE(*managerp == NULL);
02086 }
02087 
02088 void
02089 isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode) {
02090         REQUIRE(ISCAPI_TASKMGR_VALID(manager));
02091 
02092         if (isc_bind9)
02093                 isc__taskmgr_setmode(manager, mode);
02094         else
02095                 manager->methods->setmode(manager, mode);
02096 }
02097 
02098 isc_taskmgrmode_t
02099 isc_taskmgr_mode(isc_taskmgr_t *manager) {
02100         REQUIRE(ISCAPI_TASKMGR_VALID(manager));
02101 
02102         if (isc_bind9)
02103                 return (isc__taskmgr_mode(manager));
02104 
02105         return (manager->methods->mode(manager));
02106 }
02107 
02108 isc_result_t
02109 isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
02110                 isc_task_t **taskp)
02111 {
02112         REQUIRE(ISCAPI_TASKMGR_VALID(manager));
02113         REQUIRE(taskp != NULL && *taskp == NULL);
02114 
02115         if (isc_bind9)
02116                 return (isc__task_create(manager, quantum, taskp));
02117 
02118         return (manager->methods->taskcreate(manager, quantum, taskp));
02119 }
02120 
02121 void
02122 isc_task_attach(isc_task_t *source, isc_task_t **targetp) {
02123         REQUIRE(ISCAPI_TASK_VALID(source));
02124         REQUIRE(targetp != NULL && *targetp == NULL);
02125 
02126         if (isc_bind9)
02127                 isc__task_attach(source, targetp);
02128         else
02129                 source->methods->attach(source, targetp);
02130 
02131         ENSURE(*targetp == source);
02132 }
02133 
02134 void
02135 isc_task_detach(isc_task_t **taskp) {
02136         REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp));
02137 
02138         if (isc_bind9)
02139                 isc__task_detach(taskp);
02140         else
02141                 (*taskp)->methods->detach(taskp);
02142 
02143         ENSURE(*taskp == NULL);
02144 }
02145 
02146 void
02147 isc_task_send(isc_task_t *task, isc_event_t **eventp) {
02148         REQUIRE(ISCAPI_TASK_VALID(task));
02149         REQUIRE(eventp != NULL && *eventp != NULL);
02150 
02151         if (isc_bind9)
02152                 isc__task_send(task, eventp);
02153         else {
02154                 task->methods->send(task, eventp);
02155                 ENSURE(*eventp == NULL);
02156         }
02157 }
02158 
02159 void
02160 isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
02161         REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp));
02162         REQUIRE(eventp != NULL && *eventp != NULL);
02163 
02164         if (isc_bind9)
02165                 isc__task_sendanddetach(taskp, eventp);
02166         else {
02167                 (*taskp)->methods->sendanddetach(taskp, eventp);
02168                 ENSURE(*eventp == NULL);
02169         }
02170 
02171         ENSURE(*taskp == NULL);
02172 }
02173 
02174 unsigned int
02175 isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
02176                 void *tag, isc_eventlist_t *events)
02177 {
02178         REQUIRE(ISCAPI_TASK_VALID(task));
02179 
02180         if (isc_bind9)
02181                 return (isc__task_unsend(task, sender, type, tag, events));
02182 
02183         return (task->methods->unsend(task, sender, type, tag, events));
02184 }
02185 
02186 isc_result_t
02187 isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg)
02188 {
02189         REQUIRE(ISCAPI_TASK_VALID(task));
02190 
02191         if (isc_bind9)
02192                 return (isc__task_onshutdown(task, action, arg));
02193 
02194         return (task->methods->onshutdown(task, action, arg));
02195 }
02196 
02197 void
02198 isc_task_shutdown(isc_task_t *task) {
02199         REQUIRE(ISCAPI_TASK_VALID(task));
02200 
02201         if (isc_bind9)
02202                 isc__task_shutdown(task);
02203         else
02204                 task->methods->shutdown(task);
02205 }
02206 
02207 void
02208 isc_task_destroy(isc_task_t **taskp) {
02209         if (!isc_bind9)
02210                 return;
02211 
02212         isc__task_destroy(taskp);
02213 }
02214 
02215 void
02216 isc_task_setname(isc_task_t *task, const char *name, void *tag) {
02217         REQUIRE(ISCAPI_TASK_VALID(task));
02218 
02219         if (isc_bind9)
02220                 isc__task_setname(task, name, tag);
02221         else
02222                 task->methods->setname(task, name, tag);
02223 }
02224 
02225 unsigned int
02226 isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag)
02227 {
02228         REQUIRE(ISCAPI_TASK_VALID(task));
02229 
02230         if (isc_bind9)
02231                 return (isc__task_purge(task, sender, type, tag));
02232 
02233         return (task->methods->purgeevents(task, sender, type, tag));
02234 }
02235 
02236 isc_result_t
02237 isc_task_beginexclusive(isc_task_t *task) {
02238         REQUIRE(ISCAPI_TASK_VALID(task));
02239 
02240         if (isc_bind9)
02241                 return (isc__task_beginexclusive(task));
02242 
02243         return (task->methods->beginexclusive(task));
02244 }
02245 
02246 void
02247 isc_task_endexclusive(isc_task_t *task) {
02248         REQUIRE(ISCAPI_TASK_VALID(task));
02249 
02250         if (isc_bind9)
02251                 isc__task_endexclusive(task);
02252         else
02253                 task->methods->endexclusive(task);
02254 }
02255 
02256 void
02257 isc_task_setprivilege(isc_task_t *task, isc_boolean_t priv) {
02258         REQUIRE(ISCAPI_TASK_VALID(task));
02259 
02260         if (isc_bind9)
02261                 isc__task_setprivilege(task, priv);
02262         else
02263                 task->methods->setprivilege(task, priv);
02264 }
02265 
02266 isc_boolean_t
02267 isc_task_privilege(isc_task_t *task) {
02268         REQUIRE(ISCAPI_TASK_VALID(task));
02269 
02270         if (isc_bind9)
02271                 return (isc__task_privilege(task));
02272 
02273         return (task->methods->privilege(task));
02274 }
02275 
02276 void
02277 isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) {
02278         if (!isc_bind9)
02279                 return;
02280 
02281         isc__task_getcurrenttime(task, t);
02282 }
02283 
02284 /*%
02285  * This is necessary for libisc's internal timer implementation.  Other
02286  * implementation might skip implementing this.
02287  */
02288 unsigned int
02289 isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
02290                     isc_eventtype_t last, void *tag)
02291 {
02292         REQUIRE(ISCAPI_TASK_VALID(task));
02293 
02294         if (isc_bind9)
02295                 return (isc__task_purgerange(task, sender, first, last, tag));
02296 
02297         return (task->methods->purgerange(task, sender, first, last, tag));
02298 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha