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