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_fast "struct taskqueue *queue" "struct task *task"
85 .Fn taskqueue_enqueue_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "int ticks"
87 .Fn taskqueue_cancel "struct taskqueue *queue" "struct task *task" "u_int *pendp"
89 .Fn taskqueue_cancel_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "u_int *pendp"
91 .Fn taskqueue_drain "struct taskqueue *queue" "struct task *task"
93 .Fn taskqueue_drain_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task"
95 .Fn taskqueue_drain_all "struct taskqueue *queue"
97 .Fn taskqueue_block "struct taskqueue *queue"
99 .Fn taskqueue_unblock "struct taskqueue *queue"
101 .Fn taskqueue_member "struct taskqueue *queue" "struct thread *td"
103 .Fn taskqueue_run "struct taskqueue *queue"
104 .Fn TASK_INIT "struct task *task" "int priority" "task_fn_t func" "void *context"
105 .Fn TASK_INITIALIZER "int priority" "task_fn_t func" "void *context"
106 .Fn TASKQUEUE_DECLARE "name"
107 .Fn TASKQUEUE_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
108 .Fn TASKQUEUE_FAST_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
109 .Fn TASKQUEUE_DEFINE_THREAD "name"
110 .Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
111 .Fn TIMEOUT_TASK_INIT "struct taskqueue *queue" "struct timeout_task *timeout_task" "int priority" "task_fn_t func" "void *context"
113 These functions provide a simple interface for asynchronous execution
118 is used to create new queues.
121 include a name that should be unique,
124 flags that specify whether the call to
127 a function that is called from
128 .Fn taskqueue_enqueue
129 when a task is added to the queue,
130 and a pointer to the memory location where the identity of the
131 thread that services the queue is recorded.
132 .\" XXX The rest of the sentence gets lots in relation to the first part.
133 The function called from
134 .Fn taskqueue_enqueue
135 must arrange for the queue to be processed
136 (for instance by scheduling a software interrupt or waking a kernel
138 The memory location where the thread identity is recorded is used
139 to signal the service thread(s) to terminate--when this value is set to
140 zero and the thread is signaled it will terminate.
141 If the queue is intended for use in fast interrupt handlers
142 .Fn taskqueue_create_fast
143 should be used in place of
144 .Fn taskqueue_create .
148 should be used to free the memory used by the queue.
149 Any tasks that are on the queue will be executed at this time after
150 which the thread servicing the queue will be signaled that it should exit.
152 Once a taskqueue has been created, its threads should be started using
153 .Fn taskqueue_start_threads
155 .Fn taskqueue_start_threads_pinned .
156 .Fn taskqueue_start_threads_pinned
159 argument which will cause the threads which are started for the taskqueue
160 to be pinned to run on the given CPU.
161 Callbacks may optionally be registered using
162 .Fn taskqueue_set_callback .
163 Currently, callbacks may be registered for the following purposes:
164 .Bl -tag -width TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
165 .It Dv TASKQUEUE_CALLBACK_TYPE_INIT
166 This callback is called by every thread in the taskqueue, before it executes
168 This callback must be set before the taskqueue's threads are started.
169 .It Dv TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
170 This callback is called by every thread in the taskqueue, after it executes
172 This callback will always be called before the taskqueue structure is
176 To add a task to the list of tasks queued on a taskqueue, call
177 .Fn taskqueue_enqueue
178 with pointers to the queue and task.
182 then it is simply incremented to reflect the number of times the task
183 was enqueued, up to a cap of USHRT_MAX.
185 the task is added to the list before the first task which has a lower
187 value or at the end of the list if no tasks have a lower priority.
188 Enqueueing a task does not perform any memory allocation which makes
189 it suitable for calling from an interrupt handler.
190 This function will return
192 if the queue is being freed.
195 .Fn taskqueue_enqueue_fast
196 should be used in place of
197 .Fn taskqueue_enqueue
198 when the enqueuing must happen from a fast interrupt handler.
199 This method uses spin locks to avoid the possibility of sleeping in the fast
202 When a task is executed,
203 first it is removed from the queue,
206 is recorded and then the field is zeroed.
209 from the task structure is called with the value of the field
211 as its first argument
214 as its second argument.
219 is called on the task pointer passed to
220 .Fn taskqueue_enqueue .
223 .Fn taskqueue_enqueue_timeout
224 is used to schedule the enqueue after the specified amount of
226 Only non-fast task queues can be used for
231 argument is negative, the already scheduled enqueueing is not re-scheduled.
232 Otherwise, the task is scheduled for enqueueing in the future,
233 after the absolute value of
239 function is used to cancel a task.
242 count is cleared, and the old value returned in the reference
247 If the task is currently running,
249 is returned, otherwise 0.
250 To implement a blocking
252 that waits for a running task to finish, it could look like:
253 .Bd -literal -offset indent
254 while (taskqueue_cancel(tq, task, NULL) != 0)
255 taskqueue_drain(tq, task);
259 .Fn taskqueue_drain ,
260 the caller is responsible for ensuring that the task is not re-enqueued
261 after being canceled.
264 .Fn taskqueue_cancel_timeout
265 function is used to cancel the scheduled task execution.
269 function is used to wait for the task to finish, and
271 .Fn taskqueue_drain_timeout
272 function is used to wait for the scheduled task to finish.
273 There is no guarantee that the task will not be
274 enqueued after call to
275 .Fn taskqueue_drain .
276 If the caller wants to put the task into a known state,
279 the caller should use out-of-band means to ensure that the task
280 would not be enqueued.
281 For example, if the task is enqueued by an interrupt filter, then
282 the interrupt could be disabled.
285 .Fn taskqueue_drain_all
286 function is used to wait for all pending and running tasks that
287 are enqueued on the taskqueue to finish.
288 The caller must arrange that the tasks are not re-enqueued.
290 .Fn taskqueue_drain_all
291 currently does not handle tasks with delayed enqueueing.
295 function blocks the taskqueue.
296 It prevents any enqueued but not running tasks from being executed.
298 .Fn taskqueue_enqueue
299 will enqueue tasks, but the tasks will not be run until
300 .Fn taskqueue_unblock
304 does not wait for any currently running tasks to finish.
307 does not provide a guarantee that
311 returns, but it does provide a guarantee that
313 will not be called again
315 .Fn taskqueue_unblock
317 If the caller requires a guarantee that
319 is not running, then this must be arranged by the caller.
322 is called on a task that is enqueued on a taskqueue that is blocked by
323 .Fn taskqueue_block ,
326 can not return until the taskqueue is unblocked.
327 This can result in a deadlock if the thread blocked in
329 is the thread that is supposed to call
330 .Fn taskqueue_unblock .
335 is discouraged, because the state of the task can not be known in advance.
336 The same caveat applies to
337 .Fn taskqueue_drain_all .
340 .Fn taskqueue_unblock
341 function unblocks the previously blocked taskqueue.
342 All enqueued tasks can be run after this call.
350 is part of the given taskqueue
358 function will run all pending tasks in the specified
360 Normally this function is only used internally.
363 .Fn TASK_INIT "task" "priority" "func" "context"
364 is provided to initialise a
369 macro generates an initializer for a task structure.
371 .Fn TIMEOUT_TASK_INIT "queue" "timeout_task" "priority" "func" "context"
380 are simply copied into the task structure fields and the
385 .Fn TASKQUEUE_DECLARE "name" ,
386 .Fn TASKQUEUE_DEFINE "name" "enqueue" "context" "init" ,
387 .Fn TASKQUEUE_FAST_DEFINE "name" "enqueue" "context" "init" ,
389 .Fn TASKQUEUE_DEFINE_THREAD "name"
390 .Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
391 are used to declare a reference to a global queue, to define the
392 implementation of the queue, and declare a queue that uses its own thread.
395 macro arranges to call
397 with the values of its
402 arguments during system initialisation.
404 .Fn taskqueue_create ,
407 argument to the macro is executed as a C statement,
408 allowing any further initialisation to be performed
409 (such as registering an interrupt handler etc.)
412 .Fn TASKQUEUE_DEFINE_THREAD
413 macro defines a new taskqueue with its own kernel thread to serve tasks.
415 .Vt struct taskqueue *taskqueue_name
416 is used to enqueue tasks onto the queue.
418 .Fn TASKQUEUE_FAST_DEFINE
420 .Fn TASKQUEUE_FAST_DEFINE_THREAD
424 .Fn TASKQUEUE_DEFINE_THREAD
425 respectively but taskqueue is created with
426 .Fn taskqueue_create_fast .
427 .Ss Predefined Task Queues
428 The system provides four global taskqueues,
431 .Va taskqueue_swi_giant ,
433 .Va taskqueue_thread .
436 queue is for swi handlers dispatched from fast interrupt handlers,
437 where sleep mutexes cannot be used.
438 The swi taskqueues are run via a software interrupt mechanism.
441 queue runs without the protection of the
444 .Va taskqueue_swi_giant
445 queue runs with the protection of the
450 runs in a kernel thread context, and tasks run from this thread do
454 If the caller wants to run under
456 he should explicitly acquire and release
458 in his taskqueue handler routine.
462 .Fn taskqueue_enqueue
463 with the value of the global taskqueue variable for the queue you wish to
465 .Va ( taskqueue_swi ,
466 .Va taskqueue_swi_giant ,
468 .Va taskqueue_thread ) .
470 .Fn taskqueue_enqueue_fast
471 for the global taskqueue variable
474 The software interrupt queues can be used,
475 for instance, for implementing interrupt handlers which must perform a
476 significant amount of processing in the handler.
477 The hardware interrupt handler would perform minimal processing of the
478 interrupt and then enqueue a task to finish the work.
479 This reduces to a minimum
480 the amount of time spent with interrupts disabled.
482 The thread queue can be used, for instance, by interrupt level routines
483 that need to call kernel functions that do things that can only be done
484 from a thread context.
485 (e.g., call malloc with the M_WAITOK flag.)
487 Note that tasks queued on shared taskqueues such as
489 may be delayed an indeterminate amount of time before execution.
490 If queueing delays cannot be tolerated then a private taskqueue should
491 be created with a dedicated processing thread.
497 This interface first appeared in
499 There is a similar facility called work_queue in the Linux kernel.
501 This manual page was written by