3 .\" Copyright (c) 2000 Doug Rabson
5 .\" All rights reserved.
7 .\" This program is free software.
9 .\" Redistribution and use in source and binary forms, with or without
10 .\" modification, are permitted provided that the following conditions
12 .\" 1. Redistributions of source code must retain the above copyright
13 .\" notice, this list of conditions and the following disclaimer.
14 .\" 2. Redistributions in binary form must reproduce the above copyright
15 .\" notice, this list of conditions and the following disclaimer in the
16 .\" documentation and/or other materials provided with the distribution.
18 .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
19 .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 .Nd asynchronous task execution
44 typedef void (*task_fn_t)(void *context, int pending);
46 typedef void (*taskqueue_enqueue_fn)(void *context);
49 STAILQ_ENTRY(task) ta_link; /* link for queue */
50 u_short ta_pending; /* count times queued */
51 u_short ta_priority; /* priority of task in queue */
52 task_fn_t ta_func; /* task handler */
53 void *ta_context; /* argument for handler */
56 enum taskqueue_callback_type {
57 TASKQUEUE_CALLBACK_TYPE_INIT,
58 TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
61 typedef void (*taskqueue_callback_fn)(void *context);
65 .Ft struct taskqueue *
66 .Fn taskqueue_create "const char *name" "int mflags" "taskqueue_enqueue_fn enqueue" "void *context"
67 .Ft struct taskqueue *
68 .Fn taskqueue_create_fast "const char *name" "int mflags" "taskqueue_enqueue_fn enqueue" "void *context"
70 .Fn taskqueue_start_threads "struct taskqueue **tqp" "int count" "int pri" "const char *name" "..."
72 .Fo taskqueue_start_threads_pinned
73 .Fa "struct taskqueue **tqp" "int count" "int pri" "int cpu_id"
74 .Fa "const char *name" "..."
77 .Fn taskqueue_set_callback "struct taskqueue *queue" "enum taskqueue_callback_type cb_type" "taskqueue_callback_fn callback" "void *context"
79 .Fn taskqueue_free "struct taskqueue *queue"
81 .Fn taskqueue_enqueue "struct taskqueue *queue" "struct task *task"
83 .Fn taskqueue_enqueue_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "int ticks"
85 .Fn taskqueue_cancel "struct taskqueue *queue" "struct task *task" "u_int *pendp"
87 .Fn taskqueue_cancel_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "u_int *pendp"
89 .Fn taskqueue_drain "struct taskqueue *queue" "struct task *task"
91 .Fn taskqueue_drain_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task"
93 .Fn taskqueue_drain_all "struct taskqueue *queue"
95 .Fn taskqueue_block "struct taskqueue *queue"
97 .Fn taskqueue_unblock "struct taskqueue *queue"
99 .Fn taskqueue_member "struct taskqueue *queue" "struct thread *td"
101 .Fn taskqueue_run "struct taskqueue *queue"
102 .Fn TASK_INIT "struct task *task" "int priority" "task_fn_t func" "void *context"
103 .Fn TASK_INITIALIZER "int priority" "task_fn_t func" "void *context"
104 .Fn TASKQUEUE_DECLARE "name"
105 .Fn TASKQUEUE_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
106 .Fn TASKQUEUE_FAST_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
107 .Fn TASKQUEUE_DEFINE_THREAD "name"
108 .Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
109 .Fn TIMEOUT_TASK_INIT "struct taskqueue *queue" "struct timeout_task *timeout_task" "int priority" "task_fn_t func" "void *context"
111 These functions provide a simple interface for asynchronous execution
116 is used to create new queues.
119 include a name that should be unique,
122 flags that specify whether the call to
125 a function that is called from
126 .Fn taskqueue_enqueue
127 when a task is added to the queue,
128 and a pointer to the memory location where the identity of the
129 thread that services the queue is recorded.
130 .\" XXX The rest of the sentence gets lots in relation to the first part.
131 The function called from
132 .Fn taskqueue_enqueue
133 must arrange for the queue to be processed
134 (for instance by scheduling a software interrupt or waking a kernel
136 The memory location where the thread identity is recorded is used
137 to signal the service thread(s) to terminate--when this value is set to
138 zero and the thread is signaled it will terminate.
139 If the queue is intended for use in fast interrupt handlers
140 .Fn taskqueue_create_fast
141 should be used in place of
142 .Fn taskqueue_create .
146 should be used to free the memory used by the queue.
147 Any tasks that are on the queue will be executed at this time after
148 which the thread servicing the queue will be signaled that it should exit.
150 Once a taskqueue has been created, its threads should be started using
151 .Fn taskqueue_start_threads
153 .Fn taskqueue_start_threads_pinned .
154 .Fn taskqueue_start_threads_pinned
157 argument which will cause the threads which are started for the taskqueue
158 to be pinned to run on the given CPU.
159 Callbacks may optionally be registered using
160 .Fn taskqueue_set_callback .
161 Currently, callbacks may be registered for the following purposes:
162 .Bl -tag -width TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
163 .It Dv TASKQUEUE_CALLBACK_TYPE_INIT
164 This callback is called by every thread in the taskqueue, before it executes
166 This callback must be set before the taskqueue's threads are started.
167 .It Dv TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
168 This callback is called by every thread in the taskqueue, after it executes
170 This callback will always be called before the taskqueue structure is
174 To add a task to the list of tasks queued on a taskqueue, call
175 .Fn taskqueue_enqueue
176 with pointers to the queue and task.
180 then it is simply incremented to reflect the number of times the task
181 was enqueued, up to a cap of USHRT_MAX.
183 the task is added to the list before the first task which has a lower
185 value or at the end of the list if no tasks have a lower priority.
186 Enqueueing a task does not perform any memory allocation which makes
187 it suitable for calling from an interrupt handler.
188 This function will return
190 if the queue is being freed.
192 When a task is executed,
193 first it is removed from the queue,
196 is recorded and then the field is zeroed.
199 from the task structure is called with the value of the field
201 as its first argument
204 as its second argument.
209 is called on the task pointer passed to
210 .Fn taskqueue_enqueue .
213 .Fn taskqueue_enqueue_timeout
214 is used to schedule the enqueue after the specified amount of
216 Only non-fast task queues can be used for
221 argument is negative, the already scheduled enqueueing is not re-scheduled.
222 Otherwise, the task is scheduled for enqueueing in the future,
223 after the absolute value of
226 This function returns -1 if the task is being drained.
227 Otherwise, the number of pending calls is returned.
231 function is used to cancel a task.
234 count is cleared, and the old value returned in the reference
239 If the task is currently running,
241 is returned, otherwise 0.
242 To implement a blocking
244 that waits for a running task to finish, it could look like:
245 .Bd -literal -offset indent
246 while (taskqueue_cancel(tq, task, NULL) != 0)
247 taskqueue_drain(tq, task);
251 .Fn taskqueue_drain ,
252 the caller is responsible for ensuring that the task is not re-enqueued
253 after being canceled.
256 .Fn taskqueue_cancel_timeout
257 function is used to cancel the scheduled task execution.
261 function is used to wait for the task to finish, and
263 .Fn taskqueue_drain_timeout
264 function is used to wait for the scheduled task to finish.
265 There is no guarantee that the task will not be
266 enqueued after call to
267 .Fn taskqueue_drain .
268 If the caller wants to put the task into a known state,
271 the caller should use out-of-band means to ensure that the task
272 would not be enqueued.
273 For example, if the task is enqueued by an interrupt filter, then
274 the interrupt could be disabled.
277 .Fn taskqueue_drain_all
278 function is used to wait for all pending and running tasks that
279 are enqueued on the taskqueue to finish.
280 Tasks posted to the taskqueue after
281 .Fn taskqueue_drain_all
283 including pending enqueues scheduled by a previous call to
284 .Fn taskqueue_enqueue_timeout ,
285 do not extend the wait time of
286 .Fn taskqueue_drain_all
287 and may complete after
288 .Fn taskqueue_drain_all
293 function blocks the taskqueue.
294 It prevents any enqueued but not running tasks from being executed.
296 .Fn taskqueue_enqueue
297 will enqueue tasks, but the tasks will not be run until
298 .Fn taskqueue_unblock
302 does not wait for any currently running tasks to finish.
305 does not provide a guarantee that
309 returns, but it does provide a guarantee that
311 will not be called again
313 .Fn taskqueue_unblock
315 If the caller requires a guarantee that
317 is not running, then this must be arranged by the caller.
320 is called on a task that is enqueued on a taskqueue that is blocked by
321 .Fn taskqueue_block ,
324 can not return until the taskqueue is unblocked.
325 This can result in a deadlock if the thread blocked in
327 is the thread that is supposed to call
328 .Fn taskqueue_unblock .
333 is discouraged, because the state of the task can not be known in advance.
334 The same caveat applies to
335 .Fn taskqueue_drain_all .
338 .Fn taskqueue_unblock
339 function unblocks the previously blocked taskqueue.
340 All enqueued tasks can be run after this call.
348 is part of the given taskqueue
356 function will run all pending tasks in the specified
358 Normally this function is only used internally.
361 .Fn TASK_INIT "task" "priority" "func" "context"
362 is provided to initialise a
367 macro generates an initializer for a task structure.
369 .Fn TIMEOUT_TASK_INIT "queue" "timeout_task" "priority" "func" "context"
378 are simply copied into the task structure fields and the
383 .Fn TASKQUEUE_DECLARE "name" ,
384 .Fn TASKQUEUE_DEFINE "name" "enqueue" "context" "init" ,
385 .Fn TASKQUEUE_FAST_DEFINE "name" "enqueue" "context" "init" ,
387 .Fn TASKQUEUE_DEFINE_THREAD "name"
388 .Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
389 are used to declare a reference to a global queue, to define the
390 implementation of the queue, and declare a queue that uses its own thread.
393 macro arranges to call
395 with the values of its
400 arguments during system initialisation.
402 .Fn taskqueue_create ,
405 argument to the macro is executed as a C statement,
406 allowing any further initialisation to be performed
407 (such as registering an interrupt handler, etc.).
410 .Fn TASKQUEUE_DEFINE_THREAD
411 macro defines a new taskqueue with its own kernel thread to serve tasks.
413 .Vt struct taskqueue *taskqueue_name
414 is used to enqueue tasks onto the queue.
416 .Fn TASKQUEUE_FAST_DEFINE
418 .Fn TASKQUEUE_FAST_DEFINE_THREAD
422 .Fn TASKQUEUE_DEFINE_THREAD
423 respectively but taskqueue is created with
424 .Fn taskqueue_create_fast .
425 .Ss Predefined Task Queues
426 The system provides four global taskqueues,
429 .Va taskqueue_swi_giant ,
431 .Va taskqueue_thread .
434 queue is for swi handlers dispatched from fast interrupt handlers,
435 where sleep mutexes cannot be used.
436 The swi taskqueues are run via a software interrupt mechanism.
439 queue runs without the protection of the
442 .Va taskqueue_swi_giant
443 queue runs with the protection of the
448 runs in a kernel thread context, and tasks run from this thread do
452 If the caller wants to run under
454 he should explicitly acquire and release
456 in his taskqueue handler routine.
460 .Fn taskqueue_enqueue
461 with the value of the global taskqueue variable for the queue you wish to
464 The software interrupt queues can be used,
465 for instance, for implementing interrupt handlers which must perform a
466 significant amount of processing in the handler.
467 The hardware interrupt handler would perform minimal processing of the
468 interrupt and then enqueue a task to finish the work.
469 This reduces to a minimum
470 the amount of time spent with interrupts disabled.
472 The thread queue can be used, for instance, by interrupt level routines
473 that need to call kernel functions that do things that can only be done
474 from a thread context.
475 (e.g., call malloc with the M_WAITOK flag.)
477 Note that tasks queued on shared taskqueues such as
479 may be delayed an indeterminate amount of time before execution.
480 If queueing delays cannot be tolerated then a private taskqueue should
481 be created with a dedicated processing thread.
487 This interface first appeared in
489 There is a similar facility called work_queue in the Linux kernel.
491 This manual page was written by