xref: /freebsd/share/man/man9/taskqueue.9 (revision 315ee00f)
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.Dd April 25, 2022
30.Dt TASKQUEUE 9
31.Os
32.Sh NAME
33.Nm taskqueue
34.Nd asynchronous task execution
35.Sh SYNOPSIS
36.In sys/param.h
37.In sys/kernel.h
38.In sys/malloc.h
39.In sys/queue.h
40.In sys/taskqueue.h
41.Bd -literal
42typedef void (*task_fn_t)(void *context, int pending);
43
44typedef void (*taskqueue_enqueue_fn)(void *context);
45
46struct task {
47	STAILQ_ENTRY(task)	ta_link;	/* link for queue */
48	u_short			ta_pending;	/* count times queued */
49	u_short			ta_priority;	/* priority of task in queue */
50	task_fn_t		ta_func;	/* task handler */
51	void			*ta_context;	/* argument for handler */
52};
53
54enum taskqueue_callback_type {
55	TASKQUEUE_CALLBACK_TYPE_INIT,
56	TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
57};
58
59typedef void (*taskqueue_callback_fn)(void *context);
60
61struct timeout_task;
62.Ed
63.Ft struct taskqueue *
64.Fn taskqueue_create "const char *name" "int mflags" "taskqueue_enqueue_fn enqueue" "void *context"
65.Ft struct taskqueue *
66.Fn taskqueue_create_fast "const char *name" "int mflags" "taskqueue_enqueue_fn enqueue" "void *context"
67.Ft int
68.Fn taskqueue_start_threads "struct taskqueue **tqp" "int count" "int pri" "const char *name" "..."
69.Ft int
70.Fo taskqueue_start_threads_cpuset
71.Fa "struct taskqueue **tqp" "int count" "int pri" "cpuset_t *mask"
72.Fa "const char *name" "..."
73.Fc
74.Ft int
75.Fo taskqueue_start_threads_in_proc
76.Fa "struct taskqueue **tqp" "int count" "int pri" "struct proc *proc"
77.Fa "const char *name" "..."
78.Fc
79.Ft void
80.Fn taskqueue_set_callback "struct taskqueue *queue" "enum taskqueue_callback_type cb_type" "taskqueue_callback_fn callback" "void *context"
81.Ft void
82.Fn taskqueue_free "struct taskqueue *queue"
83.Ft int
84.Fn taskqueue_enqueue "struct taskqueue *queue" "struct task *task"
85.Ft int
86.Fn taskqueue_enqueue_flags "struct taskqueue *queue" "struct task *task" "int flags"
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_flags
229accepts an extra
230.Va flags
231parameter which specifies a set of optional flags to alter the behavior of
232.Fn taskqueue_enqueue .
233It contains one or more of the following flags:
234.Bl -tag -width TASKQUEUE_FAIL_IF_CANCELING
235.It Dv TASKQUEUE_FAIL_IF_PENDING
236.Fn taskqueue_enqueue_flags
237fails if the task is already scheduled for execution.
238.Er EEXIST
239is returned and the
240.Va ta_pending
241counter value remains unchanged.
242.It Dv TASKQUEUE_FAIL_IF_CANCELING
243.Fn taskqueue_enqueue_flags
244fails if the task is in the canceling state and
245.Er ECANCELED
246is returned.
247.El
248.Pp
249The
250.Fn taskqueue_enqueue_timeout
251function is used to schedule the enqueue after the specified number of
252.Va ticks .
253The
254.Fn taskqueue_enqueue_timeout_sbt
255function provides finer control over the scheduling based on
256.Va sbt ,
257.Va pr ,
258and
259.Va flags ,
260as detailed in
261.Xr callout 9 .
262If the
263.Va ticks
264argument is negative, the already scheduled enqueueing is not re-scheduled.
265Otherwise, the task is scheduled for enqueueing in the future,
266after the absolute value of
267.Va ticks
268is passed.
269This function returns -1 if the task is being drained.
270Otherwise, the number of pending calls is returned.
271.Pp
272The
273.Fn taskqueue_cancel
274function is used to cancel a task.
275The
276.Va ta_pending
277count is cleared, and the old value returned in the reference
278parameter
279.Fa pendp ,
280if it is
281.Pf non- Dv NULL .
282If the task is currently running,
283.Dv EBUSY
284is returned, otherwise 0.
285To implement a blocking
286.Fn taskqueue_cancel
287that waits for a running task to finish, it could look like:
288.Bd -literal -offset indent
289while (taskqueue_cancel(tq, task, NULL) != 0)
290	taskqueue_drain(tq, task);
291.Ed
292.Pp
293Note that, as with
294.Fn taskqueue_drain ,
295the caller is responsible for ensuring that the task is not re-enqueued
296after being canceled.
297.Pp
298Similarly, the
299.Fn taskqueue_cancel_timeout
300function is used to cancel the scheduled task execution.
301.Pp
302The
303.Fn taskqueue_drain
304function is used to wait for the task to finish, and
305the
306.Fn taskqueue_drain_timeout
307function is used to wait for the scheduled task to finish.
308There is no guarantee that the task will not be
309enqueued after call to
310.Fn taskqueue_drain .
311If the caller wants to put the task into a known state,
312then before calling
313.Fn taskqueue_drain
314the caller should use out-of-band means to ensure that the task
315would not be enqueued.
316For example, if the task is enqueued by an interrupt filter, then
317the interrupt could be disabled.
318.Pp
319The
320.Fn taskqueue_drain_all
321function is used to wait for all pending and running tasks that
322are enqueued on the taskqueue to finish.
323Tasks posted to the taskqueue after
324.Fn taskqueue_drain_all
325begins processing,
326including pending enqueues scheduled by a previous call to
327.Fn taskqueue_enqueue_timeout ,
328do not extend the wait time of
329.Fn taskqueue_drain_all
330and may complete after
331.Fn taskqueue_drain_all
332returns.
333The
334.Fn taskqueue_quiesce
335function is used to wait for the queue to become empty and for all
336running tasks to finish.
337To avoid blocking indefinitely, the caller must ensure by some mechanism
338that tasks will eventually stop being posted to the queue.
339.Pp
340The
341.Fn taskqueue_block
342function blocks the taskqueue.
343It prevents any enqueued but not running tasks from being executed.
344Future calls to
345.Fn taskqueue_enqueue
346will enqueue tasks, but the tasks will not be run until
347.Fn taskqueue_unblock
348is called.
349Please note that
350.Fn taskqueue_block
351does not wait for any currently running tasks to finish.
352Thus, the
353.Fn taskqueue_block
354does not provide a guarantee that
355.Fn taskqueue_run
356is not running after
357.Fn taskqueue_block
358returns, but it does provide a guarantee that
359.Fn taskqueue_run
360will not be called again
361until
362.Fn taskqueue_unblock
363is called.
364If the caller requires a guarantee that
365.Fn taskqueue_run
366is not running, then this must be arranged by the caller.
367Note that if
368.Fn taskqueue_drain
369is called on a task that is enqueued on a taskqueue that is blocked by
370.Fn taskqueue_block ,
371then
372.Fn taskqueue_drain
373can not return until the taskqueue is unblocked.
374This can result in a deadlock if the thread blocked in
375.Fn taskqueue_drain
376is the thread that is supposed to call
377.Fn taskqueue_unblock .
378Thus, use of
379.Fn taskqueue_drain
380after
381.Fn taskqueue_block
382is discouraged, because the state of the task can not be known in advance.
383The same caveat applies to
384.Fn taskqueue_drain_all .
385.Pp
386The
387.Fn taskqueue_unblock
388function unblocks the previously blocked taskqueue.
389All enqueued tasks can be run after this call.
390.Pp
391The
392.Fn taskqueue_member
393function returns
394.No 1
395if the given thread
396.Fa td
397is part of the given taskqueue
398.Fa queue
399and
400.No 0
401otherwise.
402.Pp
403The
404.Fn taskqueue_run
405function will run all pending tasks in the specified
406.Fa queue .
407Normally this function is only used internally.
408.Pp
409A convenience macro,
410.Fn TASK_INIT "task" "priority" "func" "context"
411is provided to initialise a
412.Va task
413structure.
414The
415.Fn TASK_INITIALIZER
416macro generates an initializer for a task structure.
417A macro
418.Fn TIMEOUT_TASK_INIT "queue" "timeout_task" "priority" "func" "context"
419initializes the
420.Va timeout_task
421structure.
422The values of
423.Va priority ,
424.Va func ,
425and
426.Va context
427are simply copied into the task structure fields and the
428.Va ta_pending
429field is cleared.
430.Pp
431Five macros
432.Fn TASKQUEUE_DECLARE "name" ,
433.Fn TASKQUEUE_DEFINE "name" "enqueue" "context" "init" ,
434.Fn TASKQUEUE_FAST_DEFINE "name" "enqueue" "context" "init" ,
435and
436.Fn TASKQUEUE_DEFINE_THREAD "name"
437.Fn TASKQUEUE_FAST_DEFINE_THREAD "name"
438are used to declare a reference to a global queue, to define the
439implementation of the queue, and declare a queue that uses its own thread.
440The
441.Fn TASKQUEUE_DEFINE
442macro arranges to call
443.Fn taskqueue_create
444with the values of its
445.Va name ,
446.Va enqueue
447and
448.Va context
449arguments during system initialisation.
450After calling
451.Fn taskqueue_create ,
452the
453.Va init
454argument to the macro is executed as a C statement,
455allowing any further initialisation to be performed
456(such as registering an interrupt handler, etc.).
457.Pp
458The
459.Fn TASKQUEUE_DEFINE_THREAD
460macro defines a new taskqueue with its own kernel thread to serve tasks.
461The variable
462.Vt struct taskqueue *taskqueue_name
463is used to enqueue tasks onto the queue.
464.Pp
465.Fn TASKQUEUE_FAST_DEFINE
466and
467.Fn TASKQUEUE_FAST_DEFINE_THREAD
468act just like
469.Fn TASKQUEUE_DEFINE
470and
471.Fn TASKQUEUE_DEFINE_THREAD
472respectively but taskqueue is created with
473.Fn taskqueue_create_fast .
474.Ss Predefined Task Queues
475The system provides four global taskqueues,
476.Va taskqueue_fast ,
477.Va taskqueue_swi ,
478.Va taskqueue_swi_giant ,
479and
480.Va taskqueue_thread .
481The
482.Va taskqueue_fast
483queue is for swi handlers dispatched from fast interrupt handlers,
484where sleep mutexes cannot be used.
485The swi taskqueues are run via a software interrupt mechanism.
486The
487.Va taskqueue_swi
488queue runs without the protection of the
489.Va Giant
490kernel lock, and the
491.Va taskqueue_swi_giant
492queue runs with the protection of the
493.Va Giant
494kernel lock.
495The thread taskqueue
496.Va taskqueue_thread
497runs in a kernel thread context, and tasks run from this thread do
498not run under the
499.Va Giant
500kernel lock.
501If the caller wants to run under
502.Va Giant ,
503he should explicitly acquire and release
504.Va Giant
505in his taskqueue handler routine.
506.Pp
507To use these queues,
508call
509.Fn taskqueue_enqueue
510with the value of the global taskqueue variable for the queue you wish to
511use.
512.Pp
513The software interrupt queues can be used,
514for instance, for implementing interrupt handlers which must perform a
515significant amount of processing in the handler.
516The hardware interrupt handler would perform minimal processing of the
517interrupt and then enqueue a task to finish the work.
518This reduces to a minimum
519the amount of time spent with interrupts disabled.
520.Pp
521The thread queue can be used, for instance, by interrupt level routines
522that need to call kernel functions that do things that can only be done
523from a thread context.
524(e.g., call malloc with the M_WAITOK flag.)
525.Pp
526Note that tasks queued on shared taskqueues such as
527.Va taskqueue_swi
528may be delayed an indeterminate amount of time before execution.
529If queueing delays cannot be tolerated then a private taskqueue should
530be created with a dedicated processing thread.
531.Sh SEE ALSO
532.Xr callout 9 ,
533.Xr ithread 9 ,
534.Xr kthread 9 ,
535.Xr swi 9
536.Sh HISTORY
537This interface first appeared in
538.Fx 5.0 .
539There is a similar facility called work_queue in the Linux kernel.
540.Sh AUTHORS
541This manual page was written by
542.An Doug Rabson .
543