File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / task.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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.1.1.1 2012/05/29 12:08:38 misho 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>