00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #ifdef ISC_PLATFORM_USETHREADS
00063 #define USE_WORKER_THREADS
00064 #else
00065 #define USE_SHARED_MANAGER
00066 #endif
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
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
00106 isc_task_t common;
00107 isc__taskmgr_t * manager;
00108 isc_mutex_t lock;
00109
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
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
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
00146
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
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
00165
00166
00167
00168 isc_mutex_t excl_lock;
00169 isc__task_t *excl;
00170 #ifdef USE_SHARED_MANAGER
00171 unsigned int refs;
00172 #endif
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
00182
00183
00184
00185
00186
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
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
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
00324
00325
00326
00327
00328 BROADCAST(&manager->work_available);
00329 }
00330 #endif
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
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
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
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
00460
00461
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
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
00481 UNLOCK(&manager->lock);
00482 }
00483
00484 static inline isc_boolean_t
00485 task_detach(isc__task_t *task) {
00486
00487
00488
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
00500
00501
00502
00503
00504
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
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
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
00576
00577
00578 REQUIRE(VALID_TASK(task));
00579
00580 XTRACE("isc_task_send");
00581
00582
00583
00584
00585
00586
00587 LOCK(&task->lock);
00588 was_idle = task_send(task, eventp);
00589 UNLOCK(&task->lock);
00590
00591 if (was_idle) {
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
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
00618
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
00634
00635
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
00662
00663
00664
00665
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
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
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
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
00740
00741
00742
00743
00744 REQUIRE(VALID_TASK(task));
00745
00746
00747
00748
00749
00750
00751
00752
00753
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
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
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
00817
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
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
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
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
00927
00928
00929
00930
00931
00932
00933
00934
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
00950
00951
00952
00953
00954
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
00977
00978
00979
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
00999
01000 REQUIRE(VALID_MANAGER(manager));
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
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
01062
01063
01064
01065
01066
01067
01068
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
01082 if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
01083 empty_readyq(manager))
01084 break;
01085 #endif
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
01101
01102
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
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
01138 }
01139
01140 if (task->references == 0 &&
01141 EMPTY(task->events) &&
01142 !TASK_SHUTTINGDOWN(task)) {
01143 isc_boolean_t was_idle;
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167 was_idle = task_shutdown(task);
01168 INSIST(!was_idle);
01169 }
01170
01171 if (EMPTY(task->events)) {
01172
01173
01174
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
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
01198
01199
01200
01201
01202
01203
01204
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
01231 if (requeue) {
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
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
01266
01267
01268
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
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
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
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
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
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
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
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
01453 #ifdef USE_SHARED_MANAGER
01454 manager->refs = 1;
01455 taskmgr = manager;
01456 #endif
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
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
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
01506
01507
01508
01509
01510
01511
01512
01513
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
01522
01523
01524
01525
01526
01527
01528
01529 LOCK(&manager->lock);
01530
01531
01532
01533
01534 INSIST(!manager->exiting);
01535 manager->exiting = ISC_TRUE;
01536
01537
01538
01539
01540 manager->mode = isc_taskmgrmode_normal;
01541
01542
01543
01544
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
01557
01558
01559
01560 BROADCAST(&manager->work_available);
01561 UNLOCK(&manager->lock);
01562
01563
01564
01565
01566 for (i = 0; i < manager->workers; i++)
01567 (void)isc_thread_join(manager->threads[i], NULL);
01568 #else
01569
01570
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
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
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
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
01806
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));
01813
01814 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads"));
01815 TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->workers));
01816 TRY0(xmlTextWriterEndElement(writer));
01817 #else
01818 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
01819 TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded"));
01820 TRY0(xmlTextWriterEndElement(writer));
01821
01822 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
01823 TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->refs));
01824 TRY0(xmlTextWriterEndElement(writer));
01825 #endif
01826
01827 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum"));
01828 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01829 mgr->default_quantum));
01830 TRY0(xmlTextWriterEndElement(writer));
01831
01832 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running"));
01833 TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running));
01834 TRY0(xmlTextWriterEndElement(writer));
01835
01836 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"));
01837 TRY0(xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_ready));
01838 TRY0(xmlTextWriterEndElement(writer));
01839
01840 TRY0(xmlTextWriterEndElement(writer));
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));
01854 }
01855
01856 TRY0(xmlTextWriterStartElement(writer,
01857 ISC_XMLCHAR "references"));
01858 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01859 task->references));
01860 TRY0(xmlTextWriterEndElement(writer));
01861
01862 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
01863 TRY0(xmlTextWriterWriteFormatString(writer, "%p", task));
01864 TRY0(xmlTextWriterEndElement(writer));
01865
01866 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "state"));
01867 TRY0(xmlTextWriterWriteFormatString(writer, "%s",
01868 statenames[task->state]));
01869 TRY0(xmlTextWriterEndElement(writer));
01870
01871 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum"));
01872 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01873 task->quantum));
01874 TRY0(xmlTextWriterEndElement(writer));
01875
01876 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "events"));
01877 TRY0(xmlTextWriterWriteFormatString(writer, "%d",
01878 task->nevents));
01879 TRY0(xmlTextWriterEndElement(writer));
01880
01881 TRY0(xmlTextWriterEndElement(writer));
01882
01883 UNLOCK(&task->lock);
01884 task = ISC_LIST_NEXT(task, link);
01885 }
01886 TRY0(xmlTextWriterEndElement(writer));
01887
01888 error:
01889 if (task != NULL)
01890 UNLOCK(&task->lock);
01891 UNLOCK(&mgr->lock);
01892
01893 return (xmlrc);
01894 }
01895 #endif
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
01916
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
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
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
02286
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 }