Annotation of embedaddon/ntp/lib/isc/task.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 1998-2003 Internet Software Consortium.
! 4: *
! 5: * Permission to use, copy, modify, and/or distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 15: * PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /* $Id: task.c,v 1.107 2008/03/27 23:46:57 tbox Exp $ */
! 19:
! 20: /*! \file
! 21: * \author Principal Author: Bob Halley
! 22: */
! 23:
! 24: /*
! 25: * XXXRTH Need to document the states a task can be in, and the rules
! 26: * for changing states.
! 27: */
! 28:
! 29: #include <config.h>
! 30:
! 31: #include <isc/condition.h>
! 32: #include <isc/event.h>
! 33: #include <isc/magic.h>
! 34: #include <isc/mem.h>
! 35: #include <isc/msgs.h>
! 36: #include <isc/platform.h>
! 37: #include <isc/string.h>
! 38: #include <isc/task.h>
! 39: #include <isc/thread.h>
! 40: #include <isc/util.h>
! 41: #include <isc/xml.h>
! 42:
! 43: #ifndef ISC_PLATFORM_USETHREADS
! 44: #include "task_p.h"
! 45: #endif /* ISC_PLATFORM_USETHREADS */
! 46:
! 47: #ifdef ISC_TASK_TRACE
! 48: #define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \
! 49: task, isc_thread_self(), (m))
! 50: #define XTTRACE(t, m) fprintf(stderr, "task %p thread %lu: %s\n", \
! 51: (t), isc_thread_self(), (m))
! 52: #define XTHREADTRACE(m) fprintf(stderr, "thread %lu: %s\n", \
! 53: isc_thread_self(), (m))
! 54: #else
! 55: #define XTRACE(m)
! 56: #define XTTRACE(t, m)
! 57: #define XTHREADTRACE(m)
! 58: #endif
! 59:
! 60: /***
! 61: *** Types.
! 62: ***/
! 63:
! 64: typedef enum {
! 65: task_state_idle, task_state_ready, task_state_running,
! 66: task_state_done
! 67: } task_state_t;
! 68:
! 69: #ifdef HAVE_LIBXML2
! 70: static const char *statenames[] = {
! 71: "idle", "ready", "running", "done",
! 72: };
! 73: #endif
! 74:
! 75: #define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K')
! 76: #define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC)
! 77:
! 78: struct isc_task {
! 79: /* Not locked. */
! 80: unsigned int magic;
! 81: isc_taskmgr_t * manager;
! 82: isc_mutex_t lock;
! 83: /* Locked by task lock. */
! 84: task_state_t state;
! 85: unsigned int references;
! 86: isc_eventlist_t events;
! 87: isc_eventlist_t on_shutdown;
! 88: unsigned int quantum;
! 89: unsigned int flags;
! 90: isc_stdtime_t now;
! 91: char name[16];
! 92: void * tag;
! 93: /* Locked by task manager lock. */
! 94: LINK(isc_task_t) link;
! 95: LINK(isc_task_t) ready_link;
! 96: };
! 97:
! 98: #define TASK_F_SHUTTINGDOWN 0x01
! 99:
! 100: #define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \
! 101: != 0)
! 102:
! 103: #define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M')
! 104: #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
! 105:
! 106: struct isc_taskmgr {
! 107: /* Not locked. */
! 108: unsigned int magic;
! 109: isc_mem_t * mctx;
! 110: isc_mutex_t lock;
! 111: #ifdef ISC_PLATFORM_USETHREADS
! 112: unsigned int workers;
! 113: isc_thread_t * threads;
! 114: #endif /* ISC_PLATFORM_USETHREADS */
! 115: /* Locked by task manager lock. */
! 116: unsigned int default_quantum;
! 117: LIST(isc_task_t) tasks;
! 118: isc_tasklist_t ready_tasks;
! 119: #ifdef ISC_PLATFORM_USETHREADS
! 120: isc_condition_t work_available;
! 121: isc_condition_t exclusive_granted;
! 122: #endif /* ISC_PLATFORM_USETHREADS */
! 123: unsigned int tasks_running;
! 124: isc_boolean_t exclusive_requested;
! 125: isc_boolean_t exiting;
! 126: #ifndef ISC_PLATFORM_USETHREADS
! 127: unsigned int refs;
! 128: #endif /* ISC_PLATFORM_USETHREADS */
! 129: };
! 130:
! 131: #define DEFAULT_TASKMGR_QUANTUM 10
! 132: #define DEFAULT_DEFAULT_QUANTUM 5
! 133: #define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
! 134:
! 135: #ifndef ISC_PLATFORM_USETHREADS
! 136: static isc_taskmgr_t *taskmgr = NULL;
! 137: #endif /* ISC_PLATFORM_USETHREADS */
! 138:
! 139: /***
! 140: *** Tasks.
! 141: ***/
! 142:
! 143: static void
! 144: task_finished(isc_task_t *task) {
! 145: isc_taskmgr_t *manager = task->manager;
! 146:
! 147: REQUIRE(EMPTY(task->events));
! 148: REQUIRE(EMPTY(task->on_shutdown));
! 149: REQUIRE(task->references == 0);
! 150: REQUIRE(task->state == task_state_done);
! 151:
! 152: XTRACE("task_finished");
! 153:
! 154: LOCK(&manager->lock);
! 155: UNLINK(manager->tasks, task, link);
! 156: #ifdef ISC_PLATFORM_USETHREADS
! 157: if (FINISHED(manager)) {
! 158: /*
! 159: * All tasks have completed and the
! 160: * task manager is exiting. Wake up
! 161: * any idle worker threads so they
! 162: * can exit.
! 163: */
! 164: BROADCAST(&manager->work_available);
! 165: }
! 166: #endif /* ISC_PLATFORM_USETHREADS */
! 167: UNLOCK(&manager->lock);
! 168:
! 169: DESTROYLOCK(&task->lock);
! 170: task->magic = 0;
! 171: isc_mem_put(manager->mctx, task, sizeof(*task));
! 172: }
! 173:
! 174: isc_result_t
! 175: isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
! 176: isc_task_t **taskp)
! 177: {
! 178: isc_task_t *task;
! 179: isc_boolean_t exiting;
! 180: isc_result_t result;
! 181:
! 182: REQUIRE(VALID_MANAGER(manager));
! 183: REQUIRE(taskp != NULL && *taskp == NULL);
! 184:
! 185: task = isc_mem_get(manager->mctx, sizeof(*task));
! 186: if (task == NULL)
! 187: return (ISC_R_NOMEMORY);
! 188: XTRACE("isc_task_create");
! 189: task->manager = manager;
! 190: result = isc_mutex_init(&task->lock);
! 191: if (result != ISC_R_SUCCESS) {
! 192: isc_mem_put(manager->mctx, task, sizeof(*task));
! 193: return (result);
! 194: }
! 195: task->state = task_state_idle;
! 196: task->references = 1;
! 197: INIT_LIST(task->events);
! 198: INIT_LIST(task->on_shutdown);
! 199: task->quantum = quantum;
! 200: task->flags = 0;
! 201: task->now = 0;
! 202: memset(task->name, 0, sizeof(task->name));
! 203: task->tag = NULL;
! 204: INIT_LINK(task, link);
! 205: INIT_LINK(task, ready_link);
! 206:
! 207: exiting = ISC_FALSE;
! 208: LOCK(&manager->lock);
! 209: if (!manager->exiting) {
! 210: if (task->quantum == 0)
! 211: task->quantum = manager->default_quantum;
! 212: APPEND(manager->tasks, task, link);
! 213: } else
! 214: exiting = ISC_TRUE;
! 215: UNLOCK(&manager->lock);
! 216:
! 217: if (exiting) {
! 218: DESTROYLOCK(&task->lock);
! 219: isc_mem_put(manager->mctx, task, sizeof(*task));
! 220: return (ISC_R_SHUTTINGDOWN);
! 221: }
! 222:
! 223: task->magic = TASK_MAGIC;
! 224: *taskp = task;
! 225:
! 226: return (ISC_R_SUCCESS);
! 227: }
! 228:
! 229: void
! 230: isc_task_attach(isc_task_t *source, isc_task_t **targetp) {
! 231:
! 232: /*
! 233: * Attach *targetp to source.
! 234: */
! 235:
! 236: REQUIRE(VALID_TASK(source));
! 237: REQUIRE(targetp != NULL && *targetp == NULL);
! 238:
! 239: XTTRACE(source, "isc_task_attach");
! 240:
! 241: LOCK(&source->lock);
! 242: source->references++;
! 243: UNLOCK(&source->lock);
! 244:
! 245: *targetp = source;
! 246: }
! 247:
! 248: static inline isc_boolean_t
! 249: task_shutdown(isc_task_t *task) {
! 250: isc_boolean_t was_idle = ISC_FALSE;
! 251: isc_event_t *event, *prev;
! 252:
! 253: /*
! 254: * Caller must be holding the task's lock.
! 255: */
! 256:
! 257: XTRACE("task_shutdown");
! 258:
! 259: if (! TASK_SHUTTINGDOWN(task)) {
! 260: XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 261: ISC_MSG_SHUTTINGDOWN, "shutting down"));
! 262: task->flags |= TASK_F_SHUTTINGDOWN;
! 263: if (task->state == task_state_idle) {
! 264: INSIST(EMPTY(task->events));
! 265: task->state = task_state_ready;
! 266: was_idle = ISC_TRUE;
! 267: }
! 268: INSIST(task->state == task_state_ready ||
! 269: task->state == task_state_running);
! 270: /*
! 271: * Note that we post shutdown events LIFO.
! 272: */
! 273: for (event = TAIL(task->on_shutdown);
! 274: event != NULL;
! 275: event = prev) {
! 276: prev = PREV(event, ev_link);
! 277: DEQUEUE(task->on_shutdown, event, ev_link);
! 278: ENQUEUE(task->events, event, ev_link);
! 279: }
! 280: }
! 281:
! 282: return (was_idle);
! 283: }
! 284:
! 285: static inline void
! 286: task_ready(isc_task_t *task) {
! 287: isc_taskmgr_t *manager = task->manager;
! 288:
! 289: REQUIRE(VALID_MANAGER(manager));
! 290: REQUIRE(task->state == task_state_ready);
! 291:
! 292: XTRACE("task_ready");
! 293:
! 294: LOCK(&manager->lock);
! 295:
! 296: ENQUEUE(manager->ready_tasks, task, ready_link);
! 297: #ifdef ISC_PLATFORM_USETHREADS
! 298: SIGNAL(&manager->work_available);
! 299: #endif /* ISC_PLATFORM_USETHREADS */
! 300:
! 301: UNLOCK(&manager->lock);
! 302: }
! 303:
! 304: static inline isc_boolean_t
! 305: task_detach(isc_task_t *task) {
! 306:
! 307: /*
! 308: * Caller must be holding the task lock.
! 309: */
! 310:
! 311: REQUIRE(task->references > 0);
! 312:
! 313: XTRACE("detach");
! 314:
! 315: task->references--;
! 316: if (task->references == 0 && task->state == task_state_idle) {
! 317: INSIST(EMPTY(task->events));
! 318: /*
! 319: * There are no references to this task, and no
! 320: * pending events. We could try to optimize and
! 321: * either initiate shutdown or clean up the task,
! 322: * depending on its state, but it's easier to just
! 323: * make the task ready and allow run() or the event
! 324: * loop to deal with shutting down and termination.
! 325: */
! 326: task->state = task_state_ready;
! 327: return (ISC_TRUE);
! 328: }
! 329:
! 330: return (ISC_FALSE);
! 331: }
! 332:
! 333: void
! 334: isc_task_detach(isc_task_t **taskp) {
! 335: isc_task_t *task;
! 336: isc_boolean_t was_idle;
! 337:
! 338: /*
! 339: * Detach *taskp from its task.
! 340: */
! 341:
! 342: REQUIRE(taskp != NULL);
! 343: task = *taskp;
! 344: REQUIRE(VALID_TASK(task));
! 345:
! 346: XTRACE("isc_task_detach");
! 347:
! 348: LOCK(&task->lock);
! 349: was_idle = task_detach(task);
! 350: UNLOCK(&task->lock);
! 351:
! 352: if (was_idle)
! 353: task_ready(task);
! 354:
! 355: *taskp = NULL;
! 356: }
! 357:
! 358: static inline isc_boolean_t
! 359: task_send(isc_task_t *task, isc_event_t **eventp) {
! 360: isc_boolean_t was_idle = ISC_FALSE;
! 361: isc_event_t *event;
! 362:
! 363: /*
! 364: * Caller must be holding the task lock.
! 365: */
! 366:
! 367: REQUIRE(eventp != NULL);
! 368: event = *eventp;
! 369: REQUIRE(event != NULL);
! 370: REQUIRE(event->ev_type > 0);
! 371: REQUIRE(task->state != task_state_done);
! 372:
! 373: XTRACE("task_send");
! 374:
! 375: if (task->state == task_state_idle) {
! 376: was_idle = ISC_TRUE;
! 377: INSIST(EMPTY(task->events));
! 378: task->state = task_state_ready;
! 379: }
! 380: INSIST(task->state == task_state_ready ||
! 381: task->state == task_state_running);
! 382: ENQUEUE(task->events, event, ev_link);
! 383: *eventp = NULL;
! 384:
! 385: return (was_idle);
! 386: }
! 387:
! 388: void
! 389: isc_task_send(isc_task_t *task, isc_event_t **eventp) {
! 390: isc_boolean_t was_idle;
! 391:
! 392: /*
! 393: * Send '*event' to 'task'.
! 394: */
! 395:
! 396: REQUIRE(VALID_TASK(task));
! 397:
! 398: XTRACE("isc_task_send");
! 399:
! 400: /*
! 401: * We're trying hard to hold locks for as short a time as possible.
! 402: * We're also trying to hold as few locks as possible. This is why
! 403: * some processing is deferred until after the lock is released.
! 404: */
! 405: LOCK(&task->lock);
! 406: was_idle = task_send(task, eventp);
! 407: UNLOCK(&task->lock);
! 408:
! 409: if (was_idle) {
! 410: /*
! 411: * We need to add this task to the ready queue.
! 412: *
! 413: * We've waited until now to do it because making a task
! 414: * ready requires locking the manager. If we tried to do
! 415: * this while holding the task lock, we could deadlock.
! 416: *
! 417: * We've changed the state to ready, so no one else will
! 418: * be trying to add this task to the ready queue. The
! 419: * only way to leave the ready state is by executing the
! 420: * task. It thus doesn't matter if events are added,
! 421: * removed, or a shutdown is started in the interval
! 422: * between the time we released the task lock, and the time
! 423: * we add the task to the ready queue.
! 424: */
! 425: task_ready(task);
! 426: }
! 427: }
! 428:
! 429: void
! 430: isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
! 431: isc_boolean_t idle1, idle2;
! 432: isc_task_t *task;
! 433:
! 434: /*
! 435: * Send '*event' to '*taskp' and then detach '*taskp' from its
! 436: * task.
! 437: */
! 438:
! 439: REQUIRE(taskp != NULL);
! 440: task = *taskp;
! 441: REQUIRE(VALID_TASK(task));
! 442:
! 443: XTRACE("isc_task_sendanddetach");
! 444:
! 445: LOCK(&task->lock);
! 446: idle1 = task_send(task, eventp);
! 447: idle2 = task_detach(task);
! 448: UNLOCK(&task->lock);
! 449:
! 450: /*
! 451: * If idle1, then idle2 shouldn't be true as well since we're holding
! 452: * the task lock, and thus the task cannot switch from ready back to
! 453: * idle.
! 454: */
! 455: INSIST(!(idle1 && idle2));
! 456:
! 457: if (idle1 || idle2)
! 458: task_ready(task);
! 459:
! 460: *taskp = NULL;
! 461: }
! 462:
! 463: #define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
! 464:
! 465: static unsigned int
! 466: dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first,
! 467: isc_eventtype_t last, void *tag,
! 468: isc_eventlist_t *events, isc_boolean_t purging)
! 469: {
! 470: isc_event_t *event, *next_event;
! 471: unsigned int count = 0;
! 472:
! 473: REQUIRE(VALID_TASK(task));
! 474: REQUIRE(last >= first);
! 475:
! 476: XTRACE("dequeue_events");
! 477:
! 478: /*
! 479: * Events matching 'sender', whose type is >= first and <= last, and
! 480: * whose tag is 'tag' will be dequeued. If 'purging', matching events
! 481: * which are marked as unpurgable will not be dequeued.
! 482: *
! 483: * sender == NULL means "any sender", and tag == NULL means "any tag".
! 484: */
! 485:
! 486: LOCK(&task->lock);
! 487:
! 488: for (event = HEAD(task->events); event != NULL; event = next_event) {
! 489: next_event = NEXT(event, ev_link);
! 490: if (event->ev_type >= first && event->ev_type <= last &&
! 491: (sender == NULL || event->ev_sender == sender) &&
! 492: (tag == NULL || event->ev_tag == tag) &&
! 493: (!purging || PURGE_OK(event))) {
! 494: DEQUEUE(task->events, event, ev_link);
! 495: ENQUEUE(*events, event, ev_link);
! 496: count++;
! 497: }
! 498: }
! 499:
! 500: UNLOCK(&task->lock);
! 501:
! 502: return (count);
! 503: }
! 504:
! 505: unsigned int
! 506: isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
! 507: isc_eventtype_t last, void *tag)
! 508: {
! 509: unsigned int count;
! 510: isc_eventlist_t events;
! 511: isc_event_t *event, *next_event;
! 512:
! 513: /*
! 514: * Purge events from a task's event queue.
! 515: */
! 516:
! 517: XTRACE("isc_task_purgerange");
! 518:
! 519: ISC_LIST_INIT(events);
! 520:
! 521: count = dequeue_events(task, sender, first, last, tag, &events,
! 522: ISC_TRUE);
! 523:
! 524: for (event = HEAD(events); event != NULL; event = next_event) {
! 525: next_event = NEXT(event, ev_link);
! 526: isc_event_free(&event);
! 527: }
! 528:
! 529: /*
! 530: * Note that purging never changes the state of the task.
! 531: */
! 532:
! 533: return (count);
! 534: }
! 535:
! 536: unsigned int
! 537: isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
! 538: void *tag)
! 539: {
! 540: /*
! 541: * Purge events from a task's event queue.
! 542: */
! 543:
! 544: XTRACE("isc_task_purge");
! 545:
! 546: return (isc_task_purgerange(task, sender, type, type, tag));
! 547: }
! 548:
! 549: isc_boolean_t
! 550: isc_task_purgeevent(isc_task_t *task, isc_event_t *event) {
! 551: isc_event_t *curr_event, *next_event;
! 552:
! 553: /*
! 554: * Purge 'event' from a task's event queue.
! 555: *
! 556: * XXXRTH: WARNING: This method may be removed before beta.
! 557: */
! 558:
! 559: REQUIRE(VALID_TASK(task));
! 560:
! 561: /*
! 562: * If 'event' is on the task's event queue, it will be purged,
! 563: * unless it is marked as unpurgeable. 'event' does not have to be
! 564: * on the task's event queue; in fact, it can even be an invalid
! 565: * pointer. Purging only occurs if the event is actually on the task's
! 566: * event queue.
! 567: *
! 568: * Purging never changes the state of the task.
! 569: */
! 570:
! 571: LOCK(&task->lock);
! 572: for (curr_event = HEAD(task->events);
! 573: curr_event != NULL;
! 574: curr_event = next_event) {
! 575: next_event = NEXT(curr_event, ev_link);
! 576: if (curr_event == event && PURGE_OK(event)) {
! 577: DEQUEUE(task->events, curr_event, ev_link);
! 578: break;
! 579: }
! 580: }
! 581: UNLOCK(&task->lock);
! 582:
! 583: if (curr_event == NULL)
! 584: return (ISC_FALSE);
! 585:
! 586: isc_event_free(&curr_event);
! 587:
! 588: return (ISC_TRUE);
! 589: }
! 590:
! 591: unsigned int
! 592: isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
! 593: isc_eventtype_t last, void *tag,
! 594: isc_eventlist_t *events)
! 595: {
! 596: /*
! 597: * Remove events from a task's event queue.
! 598: */
! 599:
! 600: XTRACE("isc_task_unsendrange");
! 601:
! 602: return (dequeue_events(task, sender, first, last, tag, events,
! 603: ISC_FALSE));
! 604: }
! 605:
! 606: unsigned int
! 607: isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
! 608: void *tag, isc_eventlist_t *events)
! 609: {
! 610: /*
! 611: * Remove events from a task's event queue.
! 612: */
! 613:
! 614: XTRACE("isc_task_unsend");
! 615:
! 616: return (dequeue_events(task, sender, type, type, tag, events,
! 617: ISC_FALSE));
! 618: }
! 619:
! 620: isc_result_t
! 621: isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg)
! 622: {
! 623: isc_boolean_t disallowed = ISC_FALSE;
! 624: isc_result_t result = ISC_R_SUCCESS;
! 625: isc_event_t *event;
! 626:
! 627: /*
! 628: * Send a shutdown event with action 'action' and argument 'arg' when
! 629: * 'task' is shutdown.
! 630: */
! 631:
! 632: REQUIRE(VALID_TASK(task));
! 633: REQUIRE(action != NULL);
! 634:
! 635: event = isc_event_allocate(task->manager->mctx,
! 636: NULL,
! 637: ISC_TASKEVENT_SHUTDOWN,
! 638: action,
! 639: arg,
! 640: sizeof(*event));
! 641: if (event == NULL)
! 642: return (ISC_R_NOMEMORY);
! 643:
! 644: LOCK(&task->lock);
! 645: if (TASK_SHUTTINGDOWN(task)) {
! 646: disallowed = ISC_TRUE;
! 647: result = ISC_R_SHUTTINGDOWN;
! 648: } else
! 649: ENQUEUE(task->on_shutdown, event, ev_link);
! 650: UNLOCK(&task->lock);
! 651:
! 652: if (disallowed)
! 653: isc_mem_put(task->manager->mctx, event, sizeof(*event));
! 654:
! 655: return (result);
! 656: }
! 657:
! 658: void
! 659: isc_task_shutdown(isc_task_t *task) {
! 660: isc_boolean_t was_idle;
! 661:
! 662: /*
! 663: * Shutdown 'task'.
! 664: */
! 665:
! 666: REQUIRE(VALID_TASK(task));
! 667:
! 668: LOCK(&task->lock);
! 669: was_idle = task_shutdown(task);
! 670: UNLOCK(&task->lock);
! 671:
! 672: if (was_idle)
! 673: task_ready(task);
! 674: }
! 675:
! 676: void
! 677: isc_task_destroy(isc_task_t **taskp) {
! 678:
! 679: /*
! 680: * Destroy '*taskp'.
! 681: */
! 682:
! 683: REQUIRE(taskp != NULL);
! 684:
! 685: isc_task_shutdown(*taskp);
! 686: isc_task_detach(taskp);
! 687: }
! 688:
! 689: void
! 690: isc_task_setname(isc_task_t *task, const char *name, void *tag) {
! 691:
! 692: /*
! 693: * Name 'task'.
! 694: */
! 695:
! 696: REQUIRE(VALID_TASK(task));
! 697:
! 698: LOCK(&task->lock);
! 699: memset(task->name, 0, sizeof(task->name));
! 700: strncpy(task->name, name, sizeof(task->name) - 1);
! 701: task->tag = tag;
! 702: UNLOCK(&task->lock);
! 703: }
! 704:
! 705: const char *
! 706: isc_task_getname(isc_task_t *task) {
! 707: return (task->name);
! 708: }
! 709:
! 710: void *
! 711: isc_task_gettag(isc_task_t *task) {
! 712: return (task->tag);
! 713: }
! 714:
! 715: void
! 716: isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) {
! 717: REQUIRE(VALID_TASK(task));
! 718: REQUIRE(t != NULL);
! 719:
! 720: LOCK(&task->lock);
! 721:
! 722: *t = task->now;
! 723:
! 724: UNLOCK(&task->lock);
! 725: }
! 726:
! 727: /***
! 728: *** Task Manager.
! 729: ***/
! 730: static void
! 731: dispatch(isc_taskmgr_t *manager) {
! 732: isc_task_t *task;
! 733: #ifndef ISC_PLATFORM_USETHREADS
! 734: unsigned int total_dispatch_count = 0;
! 735: isc_tasklist_t ready_tasks;
! 736: #endif /* ISC_PLATFORM_USETHREADS */
! 737:
! 738: REQUIRE(VALID_MANAGER(manager));
! 739:
! 740: /*
! 741: * Again we're trying to hold the lock for as short a time as possible
! 742: * and to do as little locking and unlocking as possible.
! 743: *
! 744: * In both while loops, the appropriate lock must be held before the
! 745: * while body starts. Code which acquired the lock at the top of
! 746: * the loop would be more readable, but would result in a lot of
! 747: * extra locking. Compare:
! 748: *
! 749: * Straightforward:
! 750: *
! 751: * LOCK();
! 752: * ...
! 753: * UNLOCK();
! 754: * while (expression) {
! 755: * LOCK();
! 756: * ...
! 757: * UNLOCK();
! 758: *
! 759: * Unlocked part here...
! 760: *
! 761: * LOCK();
! 762: * ...
! 763: * UNLOCK();
! 764: * }
! 765: *
! 766: * Note how if the loop continues we unlock and then immediately lock.
! 767: * For N iterations of the loop, this code does 2N+1 locks and 2N+1
! 768: * unlocks. Also note that the lock is not held when the while
! 769: * condition is tested, which may or may not be important, depending
! 770: * on the expression.
! 771: *
! 772: * As written:
! 773: *
! 774: * LOCK();
! 775: * while (expression) {
! 776: * ...
! 777: * UNLOCK();
! 778: *
! 779: * Unlocked part here...
! 780: *
! 781: * LOCK();
! 782: * ...
! 783: * }
! 784: * UNLOCK();
! 785: *
! 786: * For N iterations of the loop, this code does N+1 locks and N+1
! 787: * unlocks. The while expression is always protected by the lock.
! 788: */
! 789:
! 790: #ifndef ISC_PLATFORM_USETHREADS
! 791: ISC_LIST_INIT(ready_tasks);
! 792: #endif
! 793: LOCK(&manager->lock);
! 794: while (!FINISHED(manager)) {
! 795: #ifdef ISC_PLATFORM_USETHREADS
! 796: /*
! 797: * For reasons similar to those given in the comment in
! 798: * isc_task_send() above, it is safe for us to dequeue
! 799: * the task while only holding the manager lock, and then
! 800: * change the task to running state while only holding the
! 801: * task lock.
! 802: */
! 803: while ((EMPTY(manager->ready_tasks) ||
! 804: manager->exclusive_requested) &&
! 805: !FINISHED(manager))
! 806: {
! 807: XTHREADTRACE(isc_msgcat_get(isc_msgcat,
! 808: ISC_MSGSET_GENERAL,
! 809: ISC_MSG_WAIT, "wait"));
! 810: WAIT(&manager->work_available, &manager->lock);
! 811: XTHREADTRACE(isc_msgcat_get(isc_msgcat,
! 812: ISC_MSGSET_TASK,
! 813: ISC_MSG_AWAKE, "awake"));
! 814: }
! 815: #else /* ISC_PLATFORM_USETHREADS */
! 816: if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
! 817: EMPTY(manager->ready_tasks))
! 818: break;
! 819: #endif /* ISC_PLATFORM_USETHREADS */
! 820: XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
! 821: ISC_MSG_WORKING, "working"));
! 822:
! 823: task = HEAD(manager->ready_tasks);
! 824: if (task != NULL) {
! 825: unsigned int dispatch_count = 0;
! 826: isc_boolean_t done = ISC_FALSE;
! 827: isc_boolean_t requeue = ISC_FALSE;
! 828: isc_boolean_t finished = ISC_FALSE;
! 829: isc_event_t *event;
! 830:
! 831: INSIST(VALID_TASK(task));
! 832:
! 833: /*
! 834: * Note we only unlock the manager lock if we actually
! 835: * have a task to do. We must reacquire the manager
! 836: * lock before exiting the 'if (task != NULL)' block.
! 837: */
! 838: DEQUEUE(manager->ready_tasks, task, ready_link);
! 839: manager->tasks_running++;
! 840: UNLOCK(&manager->lock);
! 841:
! 842: LOCK(&task->lock);
! 843: INSIST(task->state == task_state_ready);
! 844: task->state = task_state_running;
! 845: XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 846: ISC_MSG_RUNNING, "running"));
! 847: isc_stdtime_get(&task->now);
! 848: do {
! 849: if (!EMPTY(task->events)) {
! 850: event = HEAD(task->events);
! 851: DEQUEUE(task->events, event, ev_link);
! 852:
! 853: /*
! 854: * Execute the event action.
! 855: */
! 856: XTRACE(isc_msgcat_get(isc_msgcat,
! 857: ISC_MSGSET_TASK,
! 858: ISC_MSG_EXECUTE,
! 859: "execute action"));
! 860: if (event->ev_action != NULL) {
! 861: UNLOCK(&task->lock);
! 862: (event->ev_action)(task,event);
! 863: LOCK(&task->lock);
! 864: }
! 865: dispatch_count++;
! 866: #ifndef ISC_PLATFORM_USETHREADS
! 867: total_dispatch_count++;
! 868: #endif /* ISC_PLATFORM_USETHREADS */
! 869: }
! 870:
! 871: if (task->references == 0 &&
! 872: EMPTY(task->events) &&
! 873: !TASK_SHUTTINGDOWN(task)) {
! 874: isc_boolean_t was_idle;
! 875:
! 876: /*
! 877: * There are no references and no
! 878: * pending events for this task,
! 879: * which means it will not become
! 880: * runnable again via an external
! 881: * action (such as sending an event
! 882: * or detaching).
! 883: *
! 884: * We initiate shutdown to prevent
! 885: * it from becoming a zombie.
! 886: *
! 887: * We do this here instead of in
! 888: * the "if EMPTY(task->events)" block
! 889: * below because:
! 890: *
! 891: * If we post no shutdown events,
! 892: * we want the task to finish.
! 893: *
! 894: * If we did post shutdown events,
! 895: * will still want the task's
! 896: * quantum to be applied.
! 897: */
! 898: was_idle = task_shutdown(task);
! 899: INSIST(!was_idle);
! 900: }
! 901:
! 902: if (EMPTY(task->events)) {
! 903: /*
! 904: * Nothing else to do for this task
! 905: * right now.
! 906: */
! 907: XTRACE(isc_msgcat_get(isc_msgcat,
! 908: ISC_MSGSET_TASK,
! 909: ISC_MSG_EMPTY,
! 910: "empty"));
! 911: if (task->references == 0 &&
! 912: TASK_SHUTTINGDOWN(task)) {
! 913: /*
! 914: * The task is done.
! 915: */
! 916: XTRACE(isc_msgcat_get(
! 917: isc_msgcat,
! 918: ISC_MSGSET_TASK,
! 919: ISC_MSG_DONE,
! 920: "done"));
! 921: finished = ISC_TRUE;
! 922: task->state = task_state_done;
! 923: } else
! 924: task->state = task_state_idle;
! 925: done = ISC_TRUE;
! 926: } else if (dispatch_count >= task->quantum) {
! 927: /*
! 928: * Our quantum has expired, but
! 929: * there is more work to be done.
! 930: * We'll requeue it to the ready
! 931: * queue later.
! 932: *
! 933: * We don't check quantum until
! 934: * dispatching at least one event,
! 935: * so the minimum quantum is one.
! 936: */
! 937: XTRACE(isc_msgcat_get(isc_msgcat,
! 938: ISC_MSGSET_TASK,
! 939: ISC_MSG_QUANTUM,
! 940: "quantum"));
! 941: task->state = task_state_ready;
! 942: requeue = ISC_TRUE;
! 943: done = ISC_TRUE;
! 944: }
! 945: } while (!done);
! 946: UNLOCK(&task->lock);
! 947:
! 948: if (finished)
! 949: task_finished(task);
! 950:
! 951: LOCK(&manager->lock);
! 952: manager->tasks_running--;
! 953: #ifdef ISC_PLATFORM_USETHREADS
! 954: if (manager->exclusive_requested &&
! 955: manager->tasks_running == 1) {
! 956: SIGNAL(&manager->exclusive_granted);
! 957: }
! 958: #endif /* ISC_PLATFORM_USETHREADS */
! 959: if (requeue) {
! 960: /*
! 961: * We know we're awake, so we don't have
! 962: * to wakeup any sleeping threads if the
! 963: * ready queue is empty before we requeue.
! 964: *
! 965: * A possible optimization if the queue is
! 966: * empty is to 'goto' the 'if (task != NULL)'
! 967: * block, avoiding the ENQUEUE of the task
! 968: * and the subsequent immediate DEQUEUE
! 969: * (since it is the only executable task).
! 970: * We don't do this because then we'd be
! 971: * skipping the exit_requested check. The
! 972: * cost of ENQUEUE is low anyway, especially
! 973: * when you consider that we'd have to do
! 974: * an extra EMPTY check to see if we could
! 975: * do the optimization. If the ready queue
! 976: * were usually nonempty, the 'optimization'
! 977: * might even hurt rather than help.
! 978: */
! 979: #ifdef ISC_PLATFORM_USETHREADS
! 980: ENQUEUE(manager->ready_tasks, task,
! 981: ready_link);
! 982: #else
! 983: ENQUEUE(ready_tasks, task, ready_link);
! 984: #endif
! 985: }
! 986: }
! 987: }
! 988: #ifndef ISC_PLATFORM_USETHREADS
! 989: ISC_LIST_APPENDLIST(manager->ready_tasks, ready_tasks, ready_link);
! 990: #endif
! 991: UNLOCK(&manager->lock);
! 992: }
! 993:
! 994: #ifdef ISC_PLATFORM_USETHREADS
! 995: static isc_threadresult_t
! 996: #ifdef _WIN32
! 997: WINAPI
! 998: #endif
! 999: run(void *uap) {
! 1000: isc_taskmgr_t *manager = uap;
! 1001:
! 1002: XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 1003: ISC_MSG_STARTING, "starting"));
! 1004:
! 1005: dispatch(manager);
! 1006:
! 1007: XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 1008: ISC_MSG_EXITING, "exiting"));
! 1009:
! 1010: return ((isc_threadresult_t)0);
! 1011: }
! 1012: #endif /* ISC_PLATFORM_USETHREADS */
! 1013:
! 1014: static void
! 1015: manager_free(isc_taskmgr_t *manager) {
! 1016: isc_mem_t *mctx;
! 1017:
! 1018: #ifdef ISC_PLATFORM_USETHREADS
! 1019: (void)isc_condition_destroy(&manager->exclusive_granted);
! 1020: (void)isc_condition_destroy(&manager->work_available);
! 1021: isc_mem_free(manager->mctx, manager->threads);
! 1022: #endif /* ISC_PLATFORM_USETHREADS */
! 1023: DESTROYLOCK(&manager->lock);
! 1024: manager->magic = 0;
! 1025: mctx = manager->mctx;
! 1026: isc_mem_put(mctx, manager, sizeof(*manager));
! 1027: isc_mem_detach(&mctx);
! 1028: }
! 1029:
! 1030: isc_result_t
! 1031: isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
! 1032: unsigned int default_quantum, isc_taskmgr_t **managerp)
! 1033: {
! 1034: isc_result_t result;
! 1035: unsigned int i, started = 0;
! 1036: isc_taskmgr_t *manager;
! 1037:
! 1038: /*
! 1039: * Create a new task manager.
! 1040: */
! 1041:
! 1042: REQUIRE(workers > 0);
! 1043: REQUIRE(managerp != NULL && *managerp == NULL);
! 1044:
! 1045: #ifndef ISC_PLATFORM_USETHREADS
! 1046: UNUSED(i);
! 1047: UNUSED(started);
! 1048: UNUSED(workers);
! 1049:
! 1050: if (taskmgr != NULL) {
! 1051: taskmgr->refs++;
! 1052: *managerp = taskmgr;
! 1053: return (ISC_R_SUCCESS);
! 1054: }
! 1055: #endif /* ISC_PLATFORM_USETHREADS */
! 1056:
! 1057: manager = isc_mem_get(mctx, sizeof(*manager));
! 1058: if (manager == NULL)
! 1059: return (ISC_R_NOMEMORY);
! 1060: manager->magic = TASK_MANAGER_MAGIC;
! 1061: manager->mctx = NULL;
! 1062: result = isc_mutex_init(&manager->lock);
! 1063: if (result != ISC_R_SUCCESS)
! 1064: goto cleanup_mgr;
! 1065:
! 1066: #ifdef ISC_PLATFORM_USETHREADS
! 1067: manager->workers = 0;
! 1068: manager->threads = isc_mem_allocate(mctx,
! 1069: workers * sizeof(isc_thread_t));
! 1070: if (manager->threads == NULL) {
! 1071: result = ISC_R_NOMEMORY;
! 1072: goto cleanup_lock;
! 1073: }
! 1074: if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
! 1075: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 1076: "isc_condition_init() %s",
! 1077: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 1078: ISC_MSG_FAILED, "failed"));
! 1079: result = ISC_R_UNEXPECTED;
! 1080: goto cleanup_threads;
! 1081: }
! 1082: if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
! 1083: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 1084: "isc_condition_init() %s",
! 1085: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 1086: ISC_MSG_FAILED, "failed"));
! 1087: result = ISC_R_UNEXPECTED;
! 1088: goto cleanup_workavailable;
! 1089: }
! 1090: #endif /* ISC_PLATFORM_USETHREADS */
! 1091: if (default_quantum == 0)
! 1092: default_quantum = DEFAULT_DEFAULT_QUANTUM;
! 1093: manager->default_quantum = default_quantum;
! 1094: INIT_LIST(manager->tasks);
! 1095: INIT_LIST(manager->ready_tasks);
! 1096: manager->tasks_running = 0;
! 1097: manager->exclusive_requested = ISC_FALSE;
! 1098: manager->exiting = ISC_FALSE;
! 1099:
! 1100: isc_mem_attach(mctx, &manager->mctx);
! 1101:
! 1102: #ifdef ISC_PLATFORM_USETHREADS
! 1103: LOCK(&manager->lock);
! 1104: /*
! 1105: * Start workers.
! 1106: */
! 1107: for (i = 0; i < workers; i++) {
! 1108: if (isc_thread_create(run, manager,
! 1109: &manager->threads[manager->workers]) ==
! 1110: ISC_R_SUCCESS) {
! 1111: manager->workers++;
! 1112: started++;
! 1113: }
! 1114: }
! 1115: UNLOCK(&manager->lock);
! 1116:
! 1117: if (started == 0) {
! 1118: manager_free(manager);
! 1119: return (ISC_R_NOTHREADS);
! 1120: }
! 1121: isc_thread_setconcurrency(workers);
! 1122: #else /* ISC_PLATFORM_USETHREADS */
! 1123: manager->refs = 1;
! 1124: taskmgr = manager;
! 1125: #endif /* ISC_PLATFORM_USETHREADS */
! 1126:
! 1127: *managerp = manager;
! 1128:
! 1129: return (ISC_R_SUCCESS);
! 1130:
! 1131: #ifdef ISC_PLATFORM_USETHREADS
! 1132: cleanup_workavailable:
! 1133: (void)isc_condition_destroy(&manager->work_available);
! 1134: cleanup_threads:
! 1135: isc_mem_free(mctx, manager->threads);
! 1136: cleanup_lock:
! 1137: DESTROYLOCK(&manager->lock);
! 1138: #endif
! 1139: cleanup_mgr:
! 1140: isc_mem_put(mctx, manager, sizeof(*manager));
! 1141: return (result);
! 1142: }
! 1143:
! 1144: void
! 1145: isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
! 1146: isc_taskmgr_t *manager;
! 1147: isc_task_t *task;
! 1148: unsigned int i;
! 1149:
! 1150: /*
! 1151: * Destroy '*managerp'.
! 1152: */
! 1153:
! 1154: REQUIRE(managerp != NULL);
! 1155: manager = *managerp;
! 1156: REQUIRE(VALID_MANAGER(manager));
! 1157:
! 1158: #ifndef ISC_PLATFORM_USETHREADS
! 1159: UNUSED(i);
! 1160:
! 1161: if (manager->refs > 1) {
! 1162: manager->refs--;
! 1163: *managerp = NULL;
! 1164: return;
! 1165: }
! 1166: #endif /* ISC_PLATFORM_USETHREADS */
! 1167:
! 1168: XTHREADTRACE("isc_taskmgr_destroy");
! 1169: /*
! 1170: * Only one non-worker thread may ever call this routine.
! 1171: * If a worker thread wants to initiate shutdown of the
! 1172: * task manager, it should ask some non-worker thread to call
! 1173: * isc_taskmgr_destroy(), e.g. by signalling a condition variable
! 1174: * that the startup thread is sleeping on.
! 1175: */
! 1176:
! 1177: /*
! 1178: * Unlike elsewhere, we're going to hold this lock a long time.
! 1179: * We need to do so, because otherwise the list of tasks could
! 1180: * change while we were traversing it.
! 1181: *
! 1182: * This is also the only function where we will hold both the
! 1183: * task manager lock and a task lock at the same time.
! 1184: */
! 1185:
! 1186: LOCK(&manager->lock);
! 1187:
! 1188: /*
! 1189: * Make sure we only get called once.
! 1190: */
! 1191: INSIST(!manager->exiting);
! 1192: manager->exiting = ISC_TRUE;
! 1193:
! 1194: /*
! 1195: * Post shutdown event(s) to every task (if they haven't already been
! 1196: * posted).
! 1197: */
! 1198: for (task = HEAD(manager->tasks);
! 1199: task != NULL;
! 1200: task = NEXT(task, link)) {
! 1201: LOCK(&task->lock);
! 1202: if (task_shutdown(task))
! 1203: ENQUEUE(manager->ready_tasks, task, ready_link);
! 1204: UNLOCK(&task->lock);
! 1205: }
! 1206: #ifdef ISC_PLATFORM_USETHREADS
! 1207: /*
! 1208: * Wake up any sleeping workers. This ensures we get work done if
! 1209: * there's work left to do, and if there are already no tasks left
! 1210: * it will cause the workers to see manager->exiting.
! 1211: */
! 1212: BROADCAST(&manager->work_available);
! 1213: UNLOCK(&manager->lock);
! 1214:
! 1215: /*
! 1216: * Wait for all the worker threads to exit.
! 1217: */
! 1218: for (i = 0; i < manager->workers; i++)
! 1219: (void)isc_thread_join(manager->threads[i], NULL);
! 1220: #else /* ISC_PLATFORM_USETHREADS */
! 1221: /*
! 1222: * Dispatch the shutdown events.
! 1223: */
! 1224: UNLOCK(&manager->lock);
! 1225: while (isc__taskmgr_ready())
! 1226: (void)isc__taskmgr_dispatch();
! 1227: if (!ISC_LIST_EMPTY(manager->tasks))
! 1228: isc_mem_printallactive(stderr);
! 1229: INSIST(ISC_LIST_EMPTY(manager->tasks));
! 1230: #endif /* ISC_PLATFORM_USETHREADS */
! 1231:
! 1232: manager_free(manager);
! 1233:
! 1234: *managerp = NULL;
! 1235: }
! 1236:
! 1237: #ifndef ISC_PLATFORM_USETHREADS
! 1238: isc_boolean_t
! 1239: isc__taskmgr_ready(void) {
! 1240: if (taskmgr == NULL)
! 1241: return (ISC_FALSE);
! 1242: return (ISC_TF(!ISC_LIST_EMPTY(taskmgr->ready_tasks)));
! 1243: }
! 1244:
! 1245: isc_result_t
! 1246: isc__taskmgr_dispatch(void) {
! 1247: isc_taskmgr_t *manager = taskmgr;
! 1248:
! 1249: if (taskmgr == NULL)
! 1250: return (ISC_R_NOTFOUND);
! 1251:
! 1252: dispatch(manager);
! 1253:
! 1254: return (ISC_R_SUCCESS);
! 1255: }
! 1256:
! 1257: #endif /* ISC_PLATFORM_USETHREADS */
! 1258:
! 1259: isc_result_t
! 1260: isc_task_beginexclusive(isc_task_t *task) {
! 1261: #ifdef ISC_PLATFORM_USETHREADS
! 1262: isc_taskmgr_t *manager = task->manager;
! 1263: REQUIRE(task->state == task_state_running);
! 1264: LOCK(&manager->lock);
! 1265: if (manager->exclusive_requested) {
! 1266: UNLOCK(&manager->lock);
! 1267: return (ISC_R_LOCKBUSY);
! 1268: }
! 1269: manager->exclusive_requested = ISC_TRUE;
! 1270: while (manager->tasks_running > 1) {
! 1271: WAIT(&manager->exclusive_granted, &manager->lock);
! 1272: }
! 1273: UNLOCK(&manager->lock);
! 1274: #else
! 1275: UNUSED(task);
! 1276: #endif
! 1277: return (ISC_R_SUCCESS);
! 1278: }
! 1279:
! 1280: void
! 1281: isc_task_endexclusive(isc_task_t *task) {
! 1282: #ifdef ISC_PLATFORM_USETHREADS
! 1283: isc_taskmgr_t *manager = task->manager;
! 1284: REQUIRE(task->state == task_state_running);
! 1285: LOCK(&manager->lock);
! 1286: REQUIRE(manager->exclusive_requested);
! 1287: manager->exclusive_requested = ISC_FALSE;
! 1288: BROADCAST(&manager->work_available);
! 1289: UNLOCK(&manager->lock);
! 1290: #else
! 1291: UNUSED(task);
! 1292: #endif
! 1293: }
! 1294:
! 1295: #ifdef HAVE_LIBXML2
! 1296:
! 1297: void
! 1298: isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer)
! 1299: {
! 1300: isc_task_t *task;
! 1301:
! 1302: LOCK(&mgr->lock);
! 1303:
! 1304: /*
! 1305: * Write out the thread-model, and some details about each depending
! 1306: * on which type is enabled.
! 1307: */
! 1308: xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model");
! 1309: #ifdef ISC_PLATFORM_USETHREADS
! 1310: xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
! 1311: xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded");
! 1312: xmlTextWriterEndElement(writer); /* type */
! 1313:
! 1314: xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads");
! 1315: xmlTextWriterWriteFormatString(writer, "%d", mgr->workers);
! 1316: xmlTextWriterEndElement(writer); /* worker-threads */
! 1317: #else /* ISC_PLATFORM_USETHREADS */
! 1318: xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
! 1319: xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded");
! 1320: xmlTextWriterEndElement(writer); /* type */
! 1321:
! 1322: xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
! 1323: xmlTextWriterWriteFormatString(writer, "%d", mgr->refs);
! 1324: xmlTextWriterEndElement(writer); /* references */
! 1325: #endif /* ISC_PLATFORM_USETHREADS */
! 1326:
! 1327: xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum");
! 1328: xmlTextWriterWriteFormatString(writer, "%d", mgr->default_quantum);
! 1329: xmlTextWriterEndElement(writer); /* default-quantum */
! 1330:
! 1331: xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running");
! 1332: xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running);
! 1333: xmlTextWriterEndElement(writer); /* tasks-running */
! 1334:
! 1335: xmlTextWriterEndElement(writer); /* thread-model */
! 1336:
! 1337: xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks");
! 1338: task = ISC_LIST_HEAD(mgr->tasks);
! 1339: while (task != NULL) {
! 1340: LOCK(&task->lock);
! 1341: xmlTextWriterStartElement(writer, ISC_XMLCHAR "task");
! 1342:
! 1343: if (task->name[0] != 0) {
! 1344: xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
! 1345: xmlTextWriterWriteFormatString(writer, "%s",
! 1346: task->name);
! 1347: xmlTextWriterEndElement(writer); /* name */
! 1348: }
! 1349:
! 1350: xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
! 1351: xmlTextWriterWriteFormatString(writer, "%d", task->references);
! 1352: xmlTextWriterEndElement(writer); /* references */
! 1353:
! 1354: xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
! 1355: xmlTextWriterWriteFormatString(writer, "%p", task);
! 1356: xmlTextWriterEndElement(writer); /* id */
! 1357:
! 1358: xmlTextWriterStartElement(writer, ISC_XMLCHAR "state");
! 1359: xmlTextWriterWriteFormatString(writer, "%s",
! 1360: statenames[task->state]);
! 1361: xmlTextWriterEndElement(writer); /* state */
! 1362:
! 1363: xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum");
! 1364: xmlTextWriterWriteFormatString(writer, "%d", task->quantum);
! 1365: xmlTextWriterEndElement(writer); /* quantum */
! 1366:
! 1367: xmlTextWriterEndElement(writer);
! 1368:
! 1369: UNLOCK(&task->lock);
! 1370: task = ISC_LIST_NEXT(task, link);
! 1371: }
! 1372: xmlTextWriterEndElement(writer); /* tasks */
! 1373:
! 1374: UNLOCK(&mgr->lock);
! 1375: }
! 1376: #endif /* HAVE_LIBXML2 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>