xref: /openbsd-src/usr.bin/dig/lib/isc/include/isc/task.h (revision b9558d14c675017cf470d7469a47201d05e39444)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: task.h,v 1.8 2020/02/25 05:00:43 jsg Exp $ */
18 
19 #ifndef ISC_TASK_H
20 #define ISC_TASK_H 1
21 
22 /*****
23  ***** Module Info
24  *****/
25 
26 /*! \file isc/task.h
27  * \brief The task system provides a lightweight execution context, which is
28  * basically an event queue.
29 
30  * When a task's event queue is non-empty, the
31  * task is runnable.  A small work crew of threads, typically one per CPU,
32  * execute runnable tasks by dispatching the events on the tasks' event
33  * queues.  Context switching between tasks is fast.
34  *
35  * \li MP:
36  *	The module ensures appropriate synchronization of data structures it
37  *	creates and manipulates.
38  *	The caller must ensure that isc_taskmgr_destroy() is called only
39  *	once for a given manager.
40  *
41  * \li Reliability:
42  *	No anticipated impact.
43  *
44  * \li Resources:
45  *	TBS
46  *
47  * \li Security:
48  *	No anticipated impact.
49  *
50  * \li Standards:
51  *	None.
52  *
53  * \section purge Purging and Unsending
54  *
55  * Events which have been queued for a task but not delivered may be removed
56  * from the task's event queue by purging or unsending.
57  *
58  * With both types, the caller specifies a matching pattern that selects
59  * events based upon their sender, type, and tag.
60  *
61  * Purging calls isc_event_free() on the matching events.
62  *
63  * Unsending returns a list of events that matched the pattern.
64  * The caller is then responsible for them.
65  *
66  * Consumers of events should purge, not unsend.
67  *
68  * Producers of events often want to remove events when the caller indicates
69  * it is no longer interested in the object, e.g. by canceling a timer.
70  * Sometimes this can be done by purging, but for some event types, the
71  * calls to isc_event_free() cause deadlock because the event free routine
72  * wants to acquire a lock the caller is already holding.  Unsending instead
73  * of purging solves this problem.  As a general rule, producers should only
74  * unsend events which they have sent.
75  */
76 
77 /***
78  *** Imports.
79  ***/
80 
81 #include <isc/eventclass.h>
82 #include <isc/types.h>
83 
84 #define ISC_TASKEVENT_FIRSTEVENT	(ISC_EVENTCLASS_TASK + 0)
85 #define ISC_TASKEVENT_SHUTDOWN		(ISC_EVENTCLASS_TASK + 1)
86 #define ISC_TASKEVENT_TEST		(ISC_EVENTCLASS_TASK + 1)
87 #define ISC_TASKEVENT_LASTEVENT		(ISC_EVENTCLASS_TASK + 65535)
88 
89 /*****
90  ***** Tasks.
91  *****/
92 
93 /***
94  *** Types
95  ***/
96 
97 typedef enum {
98 		isc_taskmgrmode_normal = 0,
99 		isc_taskmgrmode_privileged
100 } isc_taskmgrmode_t;
101 
102 isc_result_t
103 isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
104 		isc_task_t **taskp);
105 /*%<
106  * Create a task.
107  *
108  * Notes:
109  *
110  *\li	If 'quantum' is non-zero, then only that many events can be dispatched
111  *	before the task must yield to other tasks waiting to execute.  If
112  *	quantum is zero, then the default quantum of the task manager will
113  *	be used.
114  *
115  *\li	The 'quantum' option may be removed from isc_task_create() in the
116  *	future.  If this happens, isc_task_getquantum() and
117  *	isc_task_setquantum() will be provided.
118  *
119  * Requires:
120  *
121  *\li	'manager' is a valid task manager.
122  *
123  *\li	taskp != NULL && *taskp == NULL
124  *
125  * Ensures:
126  *
127  *\li	On success, '*taskp' is bound to the new task.
128  *
129  * Returns:
130  *
131  *\li   #ISC_R_SUCCESS
132  *\li	#ISC_R_NOMEMORY
133  *\li	#ISC_R_UNEXPECTED
134  *\li	#ISC_R_SHUTTINGDOWN
135  */
136 
137 void
138 isc_task_attach(isc_task_t *source, isc_task_t **targetp);
139 /*%<
140  * Attach *targetp to source.
141  *
142  * Requires:
143  *
144  *\li	'source' is a valid task.
145  *
146  *\li	'targetp' points to a NULL isc_task_t *.
147  *
148  * Ensures:
149  *
150  *\li	*targetp is attached to source.
151  */
152 
153 void
154 isc_task_detach(isc_task_t **taskp);
155 /*%<
156  * Detach *taskp from its task.
157  *
158  * Requires:
159  *
160  *\li	'*taskp' is a valid task.
161  *
162  * Ensures:
163  *
164  *\li	*taskp is NULL.
165  *
166  *\li	If '*taskp' is the last reference to the task, the task is idle (has
167  *	an empty event queue), and has not been shutdown, the task will be
168  *	shutdown.
169  *
170  *\li	If '*taskp' is the last reference to the task and
171  *	the task has been shutdown,
172  *		all resources used by the task will be freed.
173  */
174 
175 void
176 isc_task_send(isc_task_t *task, isc_event_t **eventp);
177 /*%<
178  * Send '*event' to 'task'.
179  *
180  * Requires:
181  *
182  *\li	'task' is a valid task.
183  *\li	eventp != NULL && *eventp != NULL.
184  *
185  * Ensures:
186  *
187  *\li	*eventp == NULL.
188  */
189 
190 void
191 isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
192 /*%<
193  * Send '*event' to '*taskp' and then detach '*taskp' from its
194  * task.
195  *
196  * Requires:
197  *
198  *\li	'*taskp' is a valid task.
199  *\li	eventp != NULL && *eventp != NULL.
200  *
201  * Ensures:
202  *
203  *\li	*eventp == NULL.
204  *
205  *\li	*taskp == NULL.
206  *
207  *\li	If '*taskp' is the last reference to the task, the task is
208  *	idle (has an empty event queue), and has not been shutdown,
209  *	the task will be shutdown.
210  *
211  *\li	If '*taskp' is the last reference to the task and
212  *	the task has been shutdown,
213  *		all resources used by the task will be freed.
214  */
215 
216 unsigned int
217 isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
218 		    isc_eventtype_t last, void *tag);
219 /*%<
220  * Purge events from a task's event queue.
221  *
222  * Requires:
223  *
224  *\li	'task' is a valid task.
225  *
226  *\li	last >= first
227  *
228  * Ensures:
229  *
230  *\li	Events in the event queue of 'task' whose sender is 'sender', whose
231  *	type is >= first and <= last, and whose tag is 'tag' will be purged,
232  *	unless they are marked as unpurgable.
233  *
234  *\li	A sender of NULL will match any sender.  A NULL tag matches any
235  *	tag.
236  *
237  * Returns:
238  *
239  *\li	The number of events purged.
240  */
241 
242 void
243 isc_task_setname(isc_task_t *task, const char *name, void *tag);
244 /*%<
245  * Name 'task'.
246  *
247  * Notes:
248  *
249  *\li	Only the first 15 characters of 'name' will be copied.
250  *
251  *\li	Naming a task is currently only useful for debugging purposes.
252  *
253  * Requires:
254  *
255  *\li	'task' is a valid task.
256  */
257 
258 /*****
259  ***** Task Manager.
260  *****/
261 
262 isc_result_t
263 isc_taskmgr_create(unsigned int workers,
264 		   unsigned int default_quantum, isc_taskmgr_t **managerp);
265 /*%<
266  * Create a new task manager.  isc_taskmgr_createinctx() also associates
267  * the new manager with the specified application context.
268  *
269  * Notes:
270  *
271  *\li	'workers' in the number of worker threads to create.  In general,
272  *	the value should be close to the number of processors in the system.
273  *	The 'workers' value is advisory only.  An attempt will be made to
274  *	create 'workers' threads, but if at least one thread creation
275  *	succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS.
276  *
277  *\li	If 'default_quantum' is non-zero, then it will be used as the default
278  *	quantum value when tasks are created.  If zero, then an implementation
279  *	defined default quantum will be used.
280  *
281  * Requires:
282  *
283  *\li      'mctx' is a valid memory context.
284  *
285  *\li	workers > 0
286  *
287  *\li	managerp != NULL && *managerp == NULL
288  *
289  *\li	'actx' is a valid application context (for createinctx()).
290  *
291  * Ensures:
292  *
293  *\li	On success, '*managerp' will be attached to the newly created task
294  *	manager.
295  *
296  * Returns:
297  *
298  *\li	#ISC_R_SUCCESS
299  *\li	#ISC_R_NOMEMORY
300  *\li	#ISC_R_NOTHREADS		No threads could be created.
301  *\li	#ISC_R_UNEXPECTED		An unexpected error occurred.
302  *\li	#ISC_R_SHUTTINGDOWN      	The non-threaded, shared, task
303  *					manager shutting down.
304  */
305 
306 void
307 isc_taskmgr_destroy(isc_taskmgr_t **managerp);
308 /*%<
309  * Destroy '*managerp'.
310  *
311  * Notes:
312  *
313  *\li	Calling isc_taskmgr_destroy() will shutdown all tasks managed by
314  *	*managerp that haven't already been shutdown.  The call will block
315  *	until all tasks have entered the done state.
316  *
317  *\li	isc_taskmgr_destroy() must not be called by a task event action,
318  *	because it would block forever waiting for the event action to
319  *	complete.  An event action that wants to cause task manager shutdown
320  *	should request some non-event action thread of execution to do the
321  *	shutdown, e.g. by signaling a condition variable or using
322  *	isc_app_shutdown().
323  *
324  *\li	Task manager references are not reference counted, so the caller
325  *	must ensure that no attempt will be made to use the manager after
326  *	isc_taskmgr_destroy() returns.
327  *
328  * Requires:
329  *
330  *\li	'*managerp' is a valid task manager.
331  *
332  *\li	isc_taskmgr_destroy() has not be called previously on '*managerp'.
333  *
334  * Ensures:
335  *
336  *\li	All resources used by the task manager, and any tasks it managed,
337  *	have been freed.
338  */
339 
340 /*%<
341  * See isc_taskmgr_create() above.
342  */
343 typedef isc_result_t
344 (*isc_taskmgrcreatefunc_t)(unsigned int workers,
345 			   unsigned int default_quantum,
346 			   isc_taskmgr_t **managerp);
347 
348 #endif /* ISC_TASK_H */
349