xref: /freebsd/share/man/man9/taskqueue.9 (revision 53b70c86)
1.\" -*- nroff -*-
2.\"
3.\" Copyright (c) 2000 Doug Rabson
4.\"
5.\" All rights reserved.
6.\"
7.\" This program is free software.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
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.
17.\"
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.
28.\"
29.\" $FreeBSD$
30.\"
31.Dd September 1, 2021
32.Dt TASKQUEUE 9
33.Os
34.Sh NAME
35.Nm taskqueue
36.Nd asynchronous task execution
37.Sh SYNOPSIS
38.In sys/param.h
39.In sys/kernel.h
40.In sys/malloc.h
41.In sys/queue.h
42.In sys/taskqueue.h
43.Bd -literal
44typedef void (*task_fn_t)(void *context, int pending);
45
46typedef void (*taskqueue_enqueue_fn)(void *context);
47
48struct task {
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 */
54};
55
56enum taskqueue_callback_type {
57	TASKQUEUE_CALLBACK_TYPE_INIT,
58	TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
59};
60
61typedef void (*taskqueue_callback_fn)(void *context);
62
63struct timeout_task;
64.Ed
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"
69.Ft int
70.Fn taskqueue_start_threads "struct taskqueue **tqp" "int count" "int pri" "const char *name" "..."
71.Ft int
72.Fo taskqueue_start_threads_cpuset
73.Fa "struct taskqueue **tqp" "int count" "int pri" "cpuset_t *mask"
74.Fa "const char *name" "..."
75.Fc
76.Ft int
77.Fo taskqueue_start_threads_in_proc
78.Fa "struct taskqueue **tqp" "int count" "int pri" "struct proc *proc"
79.Fa "const char *name" "..."
80.Fc
81.Ft void
82.Fn taskqueue_set_callback "struct taskqueue *queue" "enum taskqueue_callback_type cb_type" "taskqueue_callback_fn callback" "void *context"
83.Ft void
84.Fn taskqueue_free "struct taskqueue *queue"
85.Ft int
86.Fn taskqueue_enqueue "struct taskqueue *queue" "struct task *task"
87.Ft int
88.Fn taskqueue_enqueue_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "int ticks"
89.Ft int
90.Fn taskqueue_enqueue_timeout_sbt "struct taskqueue *queue" "struct timeout_task *timeout_task" "sbintime_t sbt" "sbintime_t pr" "int flags"
91.Ft int
92.Fn taskqueue_cancel "struct taskqueue *queue" "struct task *task" "u_int *pendp"
93.Ft int
94.Fn taskqueue_cancel_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "u_int *pendp"
95.Ft void
96.Fn taskqueue_drain "struct taskqueue *queue" "struct task *task"
97.Ft void
98.Fn taskqueue_drain_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task"
99.Ft void
100.Fn taskqueue_drain_all "struct taskqueue *queue"
101.Ft void
102.Fn taskqueue_quiesce "struct taskqueue *queue"
103.Ft void
104.Fn taskqueue_block "struct taskqueue *queue"
105.Ft void
106.Fn taskqueue_unblock "struct taskqueue *queue"
107.Ft int
108.Fn taskqueue_member "struct taskqueue *queue" "struct thread *td"
109.Ft void
110.Fn taskqueue_run "struct taskqueue *queue"
111.Fn TASK_INIT "struct task *task" "int priority" "task_fn_t func" "void *context"
112.Fn TASK_INITIALIZER "int priority" "task_fn_t func" "void *context"
113.Fn TASKQUEUE_DECLARE "name"
114.Fn TASKQUEUE_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
115.Fn TASKQUEUE_FAST_DEFINE "name" "taskqueue_enqueue_fn enqueue" "void *context" "init"
116.Fn TASKQUEUE_DEFINE_THREAD "name"
117.Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
118.Fn TIMEOUT_TASK_INIT "struct taskqueue *queue" "struct timeout_task *timeout_task" "int priority" "task_fn_t func" "void *context"
119.Sh DESCRIPTION
120These functions provide a simple interface for asynchronous execution
121of code.
122.Pp
123The function
124.Fn taskqueue_create
125is used to create new queues.
126The arguments to
127.Fn taskqueue_create
128include a name that should be unique,
129a set of
130.Xr malloc 9
131flags that specify whether the call to
132.Fn malloc
133is allowed to sleep,
134a function that is called from
135.Fn taskqueue_enqueue
136when a task is added to the queue,
137and a pointer to the memory location where the identity of the
138thread that services the queue is recorded.
139.\" XXX	The rest of the sentence gets lots in relation to the first part.
140The function called from
141.Fn taskqueue_enqueue
142must arrange for the queue to be processed
143(for instance by scheduling a software interrupt or waking a kernel
144thread).
145The memory location where the thread identity is recorded is used
146to signal the service thread(s) to terminate--when this value is set to
147zero and the thread is signaled it will terminate.
148If the queue is intended for use in fast interrupt handlers
149.Fn taskqueue_create_fast
150should be used in place of
151.Fn taskqueue_create .
152.Pp
153The function
154.Fn taskqueue_free
155should be used to free the memory used by the queue.
156Any tasks that are on the queue will be executed at this time after
157which the thread servicing the queue will be signaled that it should exit.
158.Pp
159Once a taskqueue has been created, its threads should be started using
160.Fn taskqueue_start_threads ,
161.Fn taskqueue_start_threads_cpuset
162or
163.Fn taskqueue_start_threads_in_proc .
164.Fn taskqueue_start_threads_cpuset
165takes a
166.Va cpuset
167argument which will cause the threads which are started for the taskqueue
168to be restricted to run on the given CPUs.
169.Fn taskqueue_start_threads_in_proc
170takes a
171.Va proc
172argument which will cause the threads which are started for the taskqueue
173to be assigned to the given kernel process.
174Callbacks may optionally be registered using
175.Fn taskqueue_set_callback .
176Currently, callbacks may be registered for the following purposes:
177.Bl -tag -width TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
178.It Dv TASKQUEUE_CALLBACK_TYPE_INIT
179This callback is called by every thread in the taskqueue, before it executes
180any tasks.
181This callback must be set before the taskqueue's threads are started.
182.It Dv TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
183This callback is called by every thread in the taskqueue, after it executes
184its last task.
185This callback will always be called before the taskqueue structure is
186reclaimed.
187.El
188.Pp
189To add a task to the list of tasks queued on a taskqueue, call
190.Fn taskqueue_enqueue
191with pointers to the queue and task.
192If the task's
193.Va ta_pending
194field is non-zero,
195then it is simply incremented to reflect the number of times the task
196was enqueued, up to a cap of USHRT_MAX.
197Otherwise,
198the task is added to the list before the first task which has a lower
199.Va ta_priority
200value or at the end of the list if no tasks have a lower priority.
201Enqueueing a task does not perform any memory allocation which makes
202it suitable for calling from an interrupt handler.
203This function will return
204.Er EPIPE
205if the queue is being freed.
206.Pp
207When a task is executed,
208first it is removed from the queue,
209the value of
210.Va ta_pending
211is recorded and then the field is zeroed.
212The function
213.Va ta_func
214from the task structure is called with the value of the field
215.Va ta_context
216as its first argument
217and the value of
218.Va ta_pending
219as its second argument.
220After the function
221.Va ta_func
222returns,
223.Xr wakeup 9
224is called on the task pointer passed to
225.Fn taskqueue_enqueue .
226.Pp
227The
228.Fn taskqueue_enqueue_timeout
229function is used to schedule the enqueue after the specified number of
230.Va ticks .
231The
232.Fn taskqueue_enqueue_timeout_sbt
233function provides finer control over the scheduling based on
234.Va sbt ,
235.Va pr ,
236and
237.Va flags ,
238as detailed in
239.Xr callout 9 .
240If the
241.Va ticks
242argument is negative, the already scheduled enqueueing is not re-scheduled.
243Otherwise, the task is scheduled for enqueueing in the future,
244after the absolute value of
245.Va ticks
246is passed.
247This function returns -1 if the task is being drained.
248Otherwise, the number of pending calls is returned.
249.Pp
250The
251.Fn taskqueue_cancel
252function is used to cancel a task.
253The
254.Va ta_pending
255count is cleared, and the old value returned in the reference
256parameter
257.Fa pendp ,
258if it is
259.Pf non- Dv NULL .
260If the task is currently running,
261.Dv EBUSY
262is returned, otherwise 0.
263To implement a blocking
264.Fn taskqueue_cancel
265that waits for a running task to finish, it could look like:
266.Bd -literal -offset indent
267while (taskqueue_cancel(tq, task, NULL) != 0)
268	taskqueue_drain(tq, task);
269.Ed
270.Pp
271Note that, as with
272.Fn taskqueue_drain ,
273the caller is responsible for ensuring that the task is not re-enqueued
274after being canceled.
275.Pp
276Similarly, the
277.Fn taskqueue_cancel_timeout
278function is used to cancel the scheduled task execution.
279.Pp
280The
281.Fn taskqueue_drain
282function is used to wait for the task to finish, and
283the
284.Fn taskqueue_drain_timeout
285function is used to wait for the scheduled task to finish.
286There is no guarantee that the task will not be
287enqueued after call to
288.Fn taskqueue_drain .
289If the caller wants to put the task into a known state,
290then before calling
291.Fn taskqueue_drain
292the caller should use out-of-band means to ensure that the task
293would not be enqueued.
294For example, if the task is enqueued by an interrupt filter, then
295the interrupt could be disabled.
296.Pp
297The
298.Fn taskqueue_drain_all
299function is used to wait for all pending and running tasks that
300are enqueued on the taskqueue to finish.
301Tasks posted to the taskqueue after
302.Fn taskqueue_drain_all
303begins processing,
304including pending enqueues scheduled by a previous call to
305.Fn taskqueue_enqueue_timeout ,
306do not extend the wait time of
307.Fn taskqueue_drain_all
308and may complete after
309.Fn taskqueue_drain_all
310returns.
311The
312.Fn taskqueue_quiesce
313function is used to wait for the queue to become empty and for all
314running tasks to finish.
315To avoid blocking indefinitely, the caller must ensure by some mechanism
316that tasks will eventually stop being posted to the queue.
317.Pp
318The
319.Fn taskqueue_block
320function blocks the taskqueue.
321It prevents any enqueued but not running tasks from being executed.
322Future calls to
323.Fn taskqueue_enqueue
324will enqueue tasks, but the tasks will not be run until
325.Fn taskqueue_unblock
326is called.
327Please note that
328.Fn taskqueue_block
329does not wait for any currently running tasks to finish.
330Thus, the
331.Fn taskqueue_block
332does not provide a guarantee that
333.Fn taskqueue_run
334is not running after
335.Fn taskqueue_block
336returns, but it does provide a guarantee that
337.Fn taskqueue_run
338will not be called again
339until
340.Fn taskqueue_unblock
341is called.
342If the caller requires a guarantee that
343.Fn taskqueue_run
344is not running, then this must be arranged by the caller.
345Note that if
346.Fn taskqueue_drain
347is called on a task that is enqueued on a taskqueue that is blocked by
348.Fn taskqueue_block ,
349then
350.Fn taskqueue_drain
351can not return until the taskqueue is unblocked.
352This can result in a deadlock if the thread blocked in
353.Fn taskqueue_drain
354is the thread that is supposed to call
355.Fn taskqueue_unblock .
356Thus, use of
357.Fn taskqueue_drain
358after
359.Fn taskqueue_block
360is discouraged, because the state of the task can not be known in advance.
361The same caveat applies to
362.Fn taskqueue_drain_all .
363.Pp
364The
365.Fn taskqueue_unblock
366function unblocks the previously blocked taskqueue.
367All enqueued tasks can be run after this call.
368.Pp
369The
370.Fn taskqueue_member
371function returns
372.No 1
373if the given thread
374.Fa td
375is part of the given taskqueue
376.Fa queue
377and
378.No 0
379otherwise.
380.Pp
381The
382.Fn taskqueue_run
383function will run all pending tasks in the specified
384.Fa queue .
385Normally this function is only used internally.
386.Pp
387A convenience macro,
388.Fn TASK_INIT "task" "priority" "func" "context"
389is provided to initialise a
390.Va task
391structure.
392The
393.Fn TASK_INITIALIZER
394macro generates an initializer for a task structure.
395A macro
396.Fn TIMEOUT_TASK_INIT "queue" "timeout_task" "priority" "func" "context"
397initializes the
398.Va timeout_task
399structure.
400The values of
401.Va priority ,
402.Va func ,
403and
404.Va context
405are simply copied into the task structure fields and the
406.Va ta_pending
407field is cleared.
408.Pp
409Five macros
410.Fn TASKQUEUE_DECLARE "name" ,
411.Fn TASKQUEUE_DEFINE "name" "enqueue" "context" "init" ,
412.Fn TASKQUEUE_FAST_DEFINE "name" "enqueue" "context" "init" ,
413and
414.Fn TASKQUEUE_DEFINE_THREAD "name"
415.Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
416are used to declare a reference to a global queue, to define the
417implementation of the queue, and declare a queue that uses its own thread.
418The
419.Fn TASKQUEUE_DEFINE
420macro arranges to call
421.Fn taskqueue_create
422with the values of its
423.Va name ,
424.Va enqueue
425and
426.Va context
427arguments during system initialisation.
428After calling
429.Fn taskqueue_create ,
430the
431.Va init
432argument to the macro is executed as a C statement,
433allowing any further initialisation to be performed
434(such as registering an interrupt handler, etc.).
435.Pp
436The
437.Fn TASKQUEUE_DEFINE_THREAD
438macro defines a new taskqueue with its own kernel thread to serve tasks.
439The variable
440.Vt struct taskqueue *taskqueue_name
441is used to enqueue tasks onto the queue.
442.Pp
443.Fn TASKQUEUE_FAST_DEFINE
444and
445.Fn TASKQUEUE_FAST_DEFINE_THREAD
446act just like
447.Fn TASKQUEUE_DEFINE
448and
449.Fn TASKQUEUE_DEFINE_THREAD
450respectively but taskqueue is created with
451.Fn taskqueue_create_fast .
452.Ss Predefined Task Queues
453The system provides four global taskqueues,
454.Va taskqueue_fast ,
455.Va taskqueue_swi ,
456.Va taskqueue_swi_giant ,
457and
458.Va taskqueue_thread .
459The
460.Va taskqueue_fast
461queue is for swi handlers dispatched from fast interrupt handlers,
462where sleep mutexes cannot be used.
463The swi taskqueues are run via a software interrupt mechanism.
464The
465.Va taskqueue_swi
466queue runs without the protection of the
467.Va Giant
468kernel lock, and the
469.Va taskqueue_swi_giant
470queue runs with the protection of the
471.Va Giant
472kernel lock.
473The thread taskqueue
474.Va taskqueue_thread
475runs in a kernel thread context, and tasks run from this thread do
476not run under the
477.Va Giant
478kernel lock.
479If the caller wants to run under
480.Va Giant ,
481he should explicitly acquire and release
482.Va Giant
483in his taskqueue handler routine.
484.Pp
485To use these queues,
486call
487.Fn taskqueue_enqueue
488with the value of the global taskqueue variable for the queue you wish to
489use.
490.Pp
491The software interrupt queues can be used,
492for instance, for implementing interrupt handlers which must perform a
493significant amount of processing in the handler.
494The hardware interrupt handler would perform minimal processing of the
495interrupt and then enqueue a task to finish the work.
496This reduces to a minimum
497the amount of time spent with interrupts disabled.
498.Pp
499The thread queue can be used, for instance, by interrupt level routines
500that need to call kernel functions that do things that can only be done
501from a thread context.
502(e.g., call malloc with the M_WAITOK flag.)
503.Pp
504Note that tasks queued on shared taskqueues such as
505.Va taskqueue_swi
506may be delayed an indeterminate amount of time before execution.
507If queueing delays cannot be tolerated then a private taskqueue should
508be created with a dedicated processing thread.
509.Sh SEE ALSO
510.Xr callout 9 ,
511.Xr ithread 9 ,
512.Xr kthread 9 ,
513.Xr swi 9
514.Sh HISTORY
515This interface first appeared in
516.Fx 5.0 .
517There is a similar facility called work_queue in the Linux kernel.
518.Sh AUTHORS
519This manual page was written by
520.An Doug Rabson .
521