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