1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #pragma once
13 
14 /*****
15  ***** Module Info
16  *****/
17 
18 /*! \file isc/task.h
19  * \brief The task system provides a lightweight execution context, which is
20  * basically an event queue.
21  *
22  * When a task's event queue is non-empty, the
23  * task is runnable.  A small work crew of threads, typically one per CPU,
24  * execute runnable tasks by dispatching the events on the tasks' event
25  * queues.  Context switching between tasks is fast.
26  *
27  * \li MP:
28  *	The module ensures appropriate synchronization of data structures it
29  *	creates and manipulates.
30  *	The caller must ensure that isc_taskmgr_destroy() is called only
31  *	once for a given manager.
32  *
33  * \li Reliability:
34  *	No anticipated impact.
35  *
36  * \li Resources:
37  *	TBS
38  *
39  * \li Security:
40  *	No anticipated impact.
41  *
42  * \li Standards:
43  *	None.
44  *
45  * \section purge Purging and Unsending
46  *
47  * Events which have been queued for a task but not delivered may be removed
48  * from the task's event queue by purging or unsending.
49  *
50  * With both types, the caller specifies a matching pattern that selects
51  * events based upon their sender, type, and tag.
52  *
53  * Purging calls isc_event_free() on the matching events.
54  *
55  * Unsending returns a list of events that matched the pattern.
56  * The caller is then responsible for them.
57  *
58  * Consumers of events should purge, not unsend.
59  *
60  * Producers of events often want to remove events when the caller indicates
61  * it is no longer interested in the object, e.g. by canceling a timer.
62  * Sometimes this can be done by purging, but for some event types, the
63  * calls to isc_event_free() cause deadlock because the event free routine
64  * wants to acquire a lock the caller is already holding.  Unsending instead
65  * of purging solves this problem.  As a general rule, producers should only
66  * unsend events which they have sent.
67  */
68 
69 /***
70  *** Imports.
71  ***/
72 
73 #include <stdbool.h>
74 
75 #include <isc/eventclass.h>
76 #include <isc/lang.h>
77 #include <isc/netmgr.h>
78 #include <isc/stdtime.h>
79 #include <isc/types.h>
80 
81 #define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
82 #define ISC_TASKEVENT_SHUTDOWN	 (ISC_EVENTCLASS_TASK + 1)
83 #define ISC_TASKEVENT_TEST	 (ISC_EVENTCLASS_TASK + 1)
84 #define ISC_TASKEVENT_LASTEVENT	 (ISC_EVENTCLASS_TASK + 65535)
85 
86 /*****
87  ***** Tasks.
88  *****/
89 
90 ISC_LANG_BEGINDECLS
91 
92 /***
93  *** Types
94  ***/
95 
96 typedef enum {
97 	isc_taskmgrmode_normal = 0,
98 	isc_taskmgrmode_privileged
99 } isc_taskmgrmode_t;
100 
101 isc_result_t
102 isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
103 		isc_task_t **taskp);
104 isc_result_t
105 isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum,
106 		      isc_task_t **taskp, int threadid);
107 /*%<
108  * Create a task, optionally bound to a particular threadid.
109  *
110  * Notes:
111  *
112  *\li	If 'quantum' is non-zero, then only that many events can be dispatched
113  *	before the task must yield to other tasks waiting to execute.  If
114  *	quantum is zero, then the default quantum of the task manager will
115  *	be used.
116  *
117  *\li	The 'quantum' option may be removed from isc_task_create() in the
118  *	future.  If this happens, isc_task_getquantum() and
119  *	isc_task_setquantum() will be provided.
120  *
121  * Requires:
122  *
123  *\li	'manager' is a valid task manager.
124  *
125  *\li	taskp != NULL && *taskp == NULL
126  *
127  * Ensures:
128  *
129  *\li	On success, '*taskp' is bound to the new task.
130  *
131  * Returns:
132  *
133  *\li   #ISC_R_SUCCESS
134  *\li	#ISC_R_NOMEMORY
135  *\li	#ISC_R_UNEXPECTED
136  *\li	#ISC_R_SHUTTINGDOWN
137  */
138 
139 void
140 isc_task_ready(isc_task_t *task);
141 /*%<
142  * Enqueue the task onto netmgr queue.
143  */
144 
145 isc_result_t
146 isc_task_run(isc_task_t *task);
147 /*%<
148  * Run all the queued events for the 'task', returning
149  * when the queue is empty or the number of events executed
150  * exceeds the 'quantum' specified when the task was created.
151  *
152  * Requires:
153  *
154  *\li	'task' is a valid task.
155  *
156  * Returns:
157  *
158  *\li	#ISC_R_SUCCESS
159  *\li	#ISC_R_QUOTA
160  */
161 
162 void
163 isc_task_attach(isc_task_t *source, isc_task_t **targetp);
164 /*%<
165  * Attach *targetp to source.
166  *
167  * Requires:
168  *
169  *\li	'source' is a valid task.
170  *
171  *\li	'targetp' points to a NULL isc_task_t *.
172  *
173  * Ensures:
174  *
175  *\li	*targetp is attached to source.
176  */
177 
178 void
179 isc_task_detach(isc_task_t **taskp);
180 /*%<
181  * Detach *taskp from its task.
182  *
183  * Requires:
184  *
185  *\li	'*taskp' is a valid task.
186  *
187  * Ensures:
188  *
189  *\li	*taskp is NULL.
190  *
191  *\li	If '*taskp' is the last reference to the task, the task is idle (has
192  *	an empty event queue), and has not been shutdown, the task will be
193  *	shutdown.
194  *
195  *\li	If '*taskp' is the last reference to the task and
196  *	the task has been shutdown,
197  *		all resources used by the task will be freed.
198  */
199 
200 void
201 isc_task_send(isc_task_t *task, isc_event_t **eventp);
202 
203 void
204 isc_task_sendto(isc_task_t *task, isc_event_t **eventp, int c);
205 /*%<
206  * Send '*event' to 'task', if task is idle try starting it on cpu 'c'
207  * If 'c' is smaller than 0 then cpu is selected randomly.
208  *
209  * Requires:
210  *
211  *\li	'task' is a valid task.
212  *\li	eventp != NULL && *eventp != NULL.
213  *
214  * Ensures:
215  *
216  *\li	*eventp == NULL.
217  */
218 
219 void
220 isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c);
221 
222 void
223 isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
224 /*%<
225  * Send '*event' to '*taskp' and then detach '*taskp' from its
226  * task. If task is idle try starting it on cpu 'c'
227  * If 'c' is smaller than 0 then cpu is selected randomly.
228  *
229  * Requires:
230  *
231  *\li	'*taskp' is a valid task.
232  *\li	eventp != NULL && *eventp != NULL.
233  *
234  * Ensures:
235  *
236  *\li	*eventp == NULL.
237  *
238  *\li	*taskp == NULL.
239  *
240  *\li	If '*taskp' is the last reference to the task, the task is
241  *	idle (has an empty event queue), and has not been shutdown,
242  *	the task will be shutdown.
243  *
244  *\li	If '*taskp' is the last reference to the task and
245  *	the task has been shutdown,
246  *		all resources used by the task will be freed.
247  */
248 
249 unsigned int
250 isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
251 		    isc_eventtype_t last, void *tag);
252 /*%<
253  * Purge events from a task's event queue.
254  *
255  * Requires:
256  *
257  *\li	'task' is a valid task.
258  *
259  *\li	last >= first
260  *
261  * Ensures:
262  *
263  *\li	Events in the event queue of 'task' whose sender is 'sender', whose
264  *	type is >= first and <= last, and whose tag is 'tag' will be purged,
265  *	unless they are marked as unpurgable.
266  *
267  *\li	A sender of NULL will match any sender.  A NULL tag matches any
268  *	tag.
269  *
270  * Returns:
271  *
272  *\li	The number of events purged.
273  */
274 
275 unsigned int
276 isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag);
277 /*%<
278  * Purge events from a task's event queue.
279  *
280  * Notes:
281  *
282  *\li	This function is equivalent to
283  *
284  *\code
285  *		isc_task_purgerange(task, sender, type, type, tag);
286  *\endcode
287  *
288  * Requires:
289  *
290  *\li	'task' is a valid task.
291  *
292  * Ensures:
293  *
294  *\li	Events in the event queue of 'task' whose sender is 'sender', whose
295  *	type is 'type', and whose tag is 'tag' will be purged, unless they
296  *	are marked as unpurgable.
297  *
298  *\li	A sender of NULL will match any sender.  A NULL tag matches any
299  *	tag.
300  *
301  * Returns:
302  *
303  *\li	The number of events purged.
304  */
305 
306 bool
307 isc_task_purgeevent(isc_task_t *task, isc_event_t *event);
308 /*%<
309  * Purge 'event' from a task's event queue.
310  *
311  * XXXRTH:  WARNING:  This method may be removed before beta.
312  *
313  * Notes:
314  *
315  *\li	If 'event' is on the task's event queue, it will be purged,
316  * 	unless it is marked as unpurgeable.  'event' does not have to be
317  *	on the task's event queue; in fact, it can even be an invalid
318  *	pointer.  Purging only occurs if the event is actually on the task's
319  *	event queue.
320  *
321  * \li	Purging never changes the state of the task.
322  *
323  * Requires:
324  *
325  *\li	'task' is a valid task.
326  *
327  * Ensures:
328  *
329  *\li	'event' is not in the event queue for 'task'.
330  *
331  * Returns:
332  *
333  *\li	#true			The event was purged.
334  *\li	#false			The event was not in the event queue,
335  *					or was marked unpurgeable.
336  */
337 
338 unsigned int
339 isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
340 		     isc_eventtype_t last, void *tag, isc_eventlist_t *events);
341 /*%<
342  * Remove events from a task's event queue.
343  *
344  * Requires:
345  *
346  *\li	'task' is a valid task.
347  *
348  *\li	last >= first.
349  *
350  *\li	*events is a valid list.
351  *
352  * Ensures:
353  *
354  *\li	Events in the event queue of 'task' whose sender is 'sender', whose
355  *	type is >= first and <= last, and whose tag is 'tag' will be dequeued
356  *	and appended to *events.
357  *
358  *\li	A sender of NULL will match any sender.  A NULL tag matches any
359  *	tag.
360  *
361  * Returns:
362  *
363  *\li	The number of events unsent.
364  */
365 
366 unsigned int
367 isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag,
368 		isc_eventlist_t *events);
369 /*%<
370  * Remove events from a task's event queue.
371  *
372  * Notes:
373  *
374  *\li	This function is equivalent to
375  *
376  *\code
377  *		isc_task_unsendrange(task, sender, type, type, tag, events);
378  *\endcode
379  *
380  * Requires:
381  *
382  *\li	'task' is a valid task.
383  *
384  *\li	*events is a valid list.
385  *
386  * Ensures:
387  *
388  *\li	Events in the event queue of 'task' whose sender is 'sender', whose
389  *	type is 'type', and whose tag is 'tag' will be dequeued and appended
390  *	to *events.
391  *
392  * Returns:
393  *
394  *\li	The number of events unsent.
395  */
396 
397 isc_result_t
398 isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg);
399 /*%<
400  * Send a shutdown event with action 'action' and argument 'arg' when
401  * 'task' is shutdown.
402  *
403  * Notes:
404  *
405  *\li	Shutdown events are posted in LIFO order.
406  *
407  * Requires:
408  *
409  *\li	'task' is a valid task.
410  *
411  *\li	'action' is a valid task action.
412  *
413  * Ensures:
414  *
415  *\li	When the task is shutdown, shutdown events requested with
416  *	isc_task_onshutdown() will be appended to the task's event queue.
417  *
418  *
419  * Returns:
420  *
421  *\li	#ISC_R_SUCCESS
422  *\li	#ISC_R_NOMEMORY
423  *\li	#ISC_R_SHUTTINGDOWN			Task is shutting down.
424  */
425 
426 void
427 isc_task_shutdown(isc_task_t *task);
428 /*%<
429  * Shutdown 'task'.
430  *
431  * Notes:
432  *
433  *\li	Shutting down a task causes any shutdown events requested with
434  *	isc_task_onshutdown() to be posted (in LIFO order).  The task
435  *	moves into a "shutting down" mode which prevents further calls
436  *	to isc_task_onshutdown().
437  *
438  *\li	Trying to shutdown a task that has already been shutdown has no
439  *	effect.
440  *
441  * Requires:
442  *
443  *\li	'task' is a valid task.
444  *
445  * Ensures:
446  *
447  *\li	Any shutdown events requested with isc_task_onshutdown() have been
448  *	posted (in LIFO order).
449  */
450 
451 void
452 isc_task_destroy(isc_task_t **taskp);
453 /*%<
454  * Destroy '*taskp'.
455  *
456  * Notes:
457  *
458  *\li	This call is equivalent to:
459  *
460  *\code
461  *		isc_task_shutdown(*taskp);
462  *		isc_task_detach(taskp);
463  *\endcode
464  *
465  * Requires:
466  *
467  *	'*taskp' is a valid task.
468  *
469  * Ensures:
470  *
471  *\li	Any shutdown events requested with isc_task_onshutdown() have been
472  *	posted (in LIFO order).
473  *
474  *\li	*taskp == NULL
475  *
476  *\li	If '*taskp' is the last reference to the task,
477  *		all resources used by the task will be freed.
478  */
479 
480 void
481 isc_task_setname(isc_task_t *task, const char *name, void *tag);
482 /*%<
483  * Name 'task'.
484  *
485  * Notes:
486  *
487  *\li	Only the first 15 characters of 'name' will be copied.
488  *
489  *\li	Naming a task is currently only useful for debugging purposes.
490  *
491  * Requires:
492  *
493  *\li	'task' is a valid task.
494  */
495 
496 const char *
497 isc_task_getname(isc_task_t *task);
498 /*%<
499  * Get the name of 'task', as previously set using isc_task_setname().
500  *
501  * Notes:
502  *\li	This function is for debugging purposes only.
503  *
504  * Requires:
505  *\li	'task' is a valid task.
506  *
507  * Returns:
508  *\li	A non-NULL pointer to a null-terminated string.
509  * 	If the task has not been named, the string is
510  * 	empty.
511  *
512  */
513 
514 isc_nm_t *
515 isc_task_getnetmgr(isc_task_t *task);
516 
517 void *
518 isc_task_gettag(isc_task_t *task);
519 /*%<
520  * Get the tag value for  'task', as previously set using isc_task_settag().
521  *
522  * Notes:
523  *\li	This function is for debugging purposes only.
524  *
525  * Requires:
526  *\li	'task' is a valid task.
527  */
528 
529 isc_result_t
530 isc_task_beginexclusive(isc_task_t *task);
531 /*%<
532  * Request exclusive access for 'task', which must be the calling
533  * task.  Waits for any other concurrently executing tasks to finish their
534  * current event, and prevents any new events from executing in any of the
535  * tasks sharing a task manager with 'task'.
536  * It also pauses processing of network events in netmgr if it was provided
537  * when taskmgr was created.
538  *
539  * The exclusive access must be relinquished by calling
540  * isc_task_endexclusive() before returning from the current event handler.
541  *
542  * Requires:
543  *\li	'task' is the calling task.
544  *
545  * Returns:
546  *\li	#ISC_R_SUCCESS		The current task now has exclusive access.
547  *\li	#ISC_R_LOCKBUSY		Another task has already requested exclusive
548  *				access.
549  */
550 
551 void
552 isc_task_endexclusive(isc_task_t *task);
553 /*%<
554  * Relinquish the exclusive access obtained by isc_task_beginexclusive(),
555  * allowing other tasks to execute.
556  *
557  * Requires:
558  *\li	'task' is the calling task, and has obtained
559  *		exclusive access by calling isc_task_spl().
560  */
561 
562 bool
563 isc_task_exiting(isc_task_t *t);
564 /*%<
565  * Returns true if the task is in the process of shutting down,
566  * false otherwise.
567  *
568  * Requires:
569  *\li	'task' is a valid task.
570  */
571 
572 void
573 isc_task_setprivilege(isc_task_t *task, bool priv);
574 /*%<
575  * Set or unset the task's "privileged" flag depending on the value of
576  * 'priv'.
577  *
578  * Under normal circumstances this flag has no effect on the task behavior,
579  * but when the task manager has been set to privileged execution mode via
580  * isc_taskmgr_setmode(), only tasks with the flag set will be executed,
581  * and all other tasks will wait until they're done.  Once all privileged
582  * tasks have finished executing, the task manager resumes running
583  * non-privileged tasks.
584  *
585  * Requires:
586  *\li	'task' is a valid task.
587  */
588 
589 bool
590 isc_task_getprivilege(isc_task_t *task);
591 /*%<
592  * Returns the current value of the task's privilege flag.
593  *
594  * Requires:
595  *\li	'task' is a valid task.
596  */
597 
598 bool
599 isc_task_privileged(isc_task_t *task);
600 /*%<
601  * Returns true if the task's privilege flag is set *and* the task
602  * manager is currently in privileged mode.
603  *
604  * Requires:
605  *\li	'task' is a valid task.
606  */
607 
608 /*****
609  ***** Task Manager.
610  *****/
611 
612 void
613 isc_taskmgr_attach(isc_taskmgr_t *, isc_taskmgr_t **);
614 void
615 isc_taskmgr_detach(isc_taskmgr_t **);
616 /*%<
617  * Attach/detach the task manager.
618  */
619 
620 void
621 isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode);
622 isc_taskmgrmode_t
623 isc_taskmgr_mode(isc_taskmgr_t *manager);
624 /*%<
625  * Set/get the operating mode of the task manager. Valid modes are:
626  *
627  *\li	isc_taskmgrmode_normal
628  *\li	isc_taskmgrmode_privileged
629  *
630  * In privileged execution mode, only tasks that have had the "privilege"
631  * flag set via isc_task_setprivilege() can be executed. When all such
632  * tasks are complete, non-privileged tasks resume running. The task calling
633  * this function should be in task-exclusive mode; the privileged tasks
634  * will be run after isc_task_endexclusive() is called.
635  *
636  * Requires:
637  *
638  *\li	'manager' is a valid task manager.
639  */
640 
641 void
642 isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task);
643 /*%<
644  * Set a task which will be used for all task-exclusive operations.
645  *
646  * Requires:
647  *\li	'manager' is a valid task manager.
648  *
649  *\li	'task' is a valid task.
650  */
651 
652 isc_result_t
653 isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp);
654 /*%<
655  * Attach '*taskp' to the task set by isc_taskmgr_getexcltask().
656  * This task should be used whenever running in task-exclusive mode,
657  * so as to prevent deadlock between two exclusive tasks.
658  *
659  * Requires:
660  *\li	'manager' is a valid task manager.
661  *
662  *\li	taskp != NULL && *taskp == NULL
663  */
664 
665 #ifdef HAVE_LIBXML2
666 int
667 isc_taskmgr_renderxml(isc_taskmgr_t *mgr, void *writer0);
668 #endif /* ifdef HAVE_LIBXML2 */
669 
670 #ifdef HAVE_JSON_C
671 isc_result_t
672 isc_taskmgr_renderjson(isc_taskmgr_t *mgr, void *tasksobj0);
673 #endif /* HAVE_JSON_C */
674 
675 ISC_LANG_ENDDECLS
676