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