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 June 6, 2020 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 . 240Only non-fast task queues can be used for 241.Va timeout_task 242scheduling. 243If the 244.Va ticks 245argument is negative, the already scheduled enqueueing is not re-scheduled. 246Otherwise, the task is scheduled for enqueueing in the future, 247after the absolute value of 248.Va ticks 249is passed. 250This function returns -1 if the task is being drained. 251Otherwise, the number of pending calls is returned. 252.Pp 253The 254.Fn taskqueue_cancel 255function is used to cancel a task. 256The 257.Va ta_pending 258count is cleared, and the old value returned in the reference 259parameter 260.Fa pendp , 261if it is 262.Pf non- Dv NULL . 263If the task is currently running, 264.Dv EBUSY 265is returned, otherwise 0. 266To implement a blocking 267.Fn taskqueue_cancel 268that waits for a running task to finish, it could look like: 269.Bd -literal -offset indent 270while (taskqueue_cancel(tq, task, NULL) != 0) 271 taskqueue_drain(tq, task); 272.Ed 273.Pp 274Note that, as with 275.Fn taskqueue_drain , 276the caller is responsible for ensuring that the task is not re-enqueued 277after being canceled. 278.Pp 279Similarly, the 280.Fn taskqueue_cancel_timeout 281function is used to cancel the scheduled task execution. 282.Pp 283The 284.Fn taskqueue_drain 285function is used to wait for the task to finish, and 286the 287.Fn taskqueue_drain_timeout 288function is used to wait for the scheduled task to finish. 289There is no guarantee that the task will not be 290enqueued after call to 291.Fn taskqueue_drain . 292If the caller wants to put the task into a known state, 293then before calling 294.Fn taskqueue_drain 295the caller should use out-of-band means to ensure that the task 296would not be enqueued. 297For example, if the task is enqueued by an interrupt filter, then 298the interrupt could be disabled. 299.Pp 300The 301.Fn taskqueue_drain_all 302function is used to wait for all pending and running tasks that 303are enqueued on the taskqueue to finish. 304Tasks posted to the taskqueue after 305.Fn taskqueue_drain_all 306begins processing, 307including pending enqueues scheduled by a previous call to 308.Fn taskqueue_enqueue_timeout , 309do not extend the wait time of 310.Fn taskqueue_drain_all 311and may complete after 312.Fn taskqueue_drain_all 313returns. 314The 315.Fn taskqueue_quiesce 316function is used to wait for the queue to become empty and for all 317running tasks to finish. 318To avoid blocking indefinitely, the caller must ensure by some mechanism 319that tasks will eventually stop being posted to the queue. 320.Pp 321The 322.Fn taskqueue_block 323function blocks the taskqueue. 324It prevents any enqueued but not running tasks from being executed. 325Future calls to 326.Fn taskqueue_enqueue 327will enqueue tasks, but the tasks will not be run until 328.Fn taskqueue_unblock 329is called. 330Please note that 331.Fn taskqueue_block 332does not wait for any currently running tasks to finish. 333Thus, the 334.Fn taskqueue_block 335does not provide a guarantee that 336.Fn taskqueue_run 337is not running after 338.Fn taskqueue_block 339returns, but it does provide a guarantee that 340.Fn taskqueue_run 341will not be called again 342until 343.Fn taskqueue_unblock 344is called. 345If the caller requires a guarantee that 346.Fn taskqueue_run 347is not running, then this must be arranged by the caller. 348Note that if 349.Fn taskqueue_drain 350is called on a task that is enqueued on a taskqueue that is blocked by 351.Fn taskqueue_block , 352then 353.Fn taskqueue_drain 354can not return until the taskqueue is unblocked. 355This can result in a deadlock if the thread blocked in 356.Fn taskqueue_drain 357is the thread that is supposed to call 358.Fn taskqueue_unblock . 359Thus, use of 360.Fn taskqueue_drain 361after 362.Fn taskqueue_block 363is discouraged, because the state of the task can not be known in advance. 364The same caveat applies to 365.Fn taskqueue_drain_all . 366.Pp 367The 368.Fn taskqueue_unblock 369function unblocks the previously blocked taskqueue. 370All enqueued tasks can be run after this call. 371.Pp 372The 373.Fn taskqueue_member 374function returns 375.No 1 376if the given thread 377.Fa td 378is part of the given taskqueue 379.Fa queue 380and 381.No 0 382otherwise. 383.Pp 384The 385.Fn taskqueue_run 386function will run all pending tasks in the specified 387.Fa queue . 388Normally this function is only used internally. 389.Pp 390A convenience macro, 391.Fn TASK_INIT "task" "priority" "func" "context" 392is provided to initialise a 393.Va task 394structure. 395The 396.Fn TASK_INITIALIZER 397macro generates an initializer for a task structure. 398A macro 399.Fn TIMEOUT_TASK_INIT "queue" "timeout_task" "priority" "func" "context" 400initializes the 401.Va timeout_task 402structure. 403The values of 404.Va priority , 405.Va func , 406and 407.Va context 408are simply copied into the task structure fields and the 409.Va ta_pending 410field is cleared. 411.Pp 412Five macros 413.Fn TASKQUEUE_DECLARE "name" , 414.Fn TASKQUEUE_DEFINE "name" "enqueue" "context" "init" , 415.Fn TASKQUEUE_FAST_DEFINE "name" "enqueue" "context" "init" , 416and 417.Fn TASKQUEUE_DEFINE_THREAD "name" 418.Fn TASKQUEUE_FAST_DEFINE_THREAD "name" 419are used to declare a reference to a global queue, to define the 420implementation of the queue, and declare a queue that uses its own thread. 421The 422.Fn TASKQUEUE_DEFINE 423macro arranges to call 424.Fn taskqueue_create 425with the values of its 426.Va name , 427.Va enqueue 428and 429.Va context 430arguments during system initialisation. 431After calling 432.Fn taskqueue_create , 433the 434.Va init 435argument to the macro is executed as a C statement, 436allowing any further initialisation to be performed 437(such as registering an interrupt handler, etc.). 438.Pp 439The 440.Fn TASKQUEUE_DEFINE_THREAD 441macro defines a new taskqueue with its own kernel thread to serve tasks. 442The variable 443.Vt struct taskqueue *taskqueue_name 444is used to enqueue tasks onto the queue. 445.Pp 446.Fn TASKQUEUE_FAST_DEFINE 447and 448.Fn TASKQUEUE_FAST_DEFINE_THREAD 449act just like 450.Fn TASKQUEUE_DEFINE 451and 452.Fn TASKQUEUE_DEFINE_THREAD 453respectively but taskqueue is created with 454.Fn taskqueue_create_fast . 455.Ss Predefined Task Queues 456The system provides four global taskqueues, 457.Va taskqueue_fast , 458.Va taskqueue_swi , 459.Va taskqueue_swi_giant , 460and 461.Va taskqueue_thread . 462The 463.Va taskqueue_fast 464queue is for swi handlers dispatched from fast interrupt handlers, 465where sleep mutexes cannot be used. 466The swi taskqueues are run via a software interrupt mechanism. 467The 468.Va taskqueue_swi 469queue runs without the protection of the 470.Va Giant 471kernel lock, and the 472.Va taskqueue_swi_giant 473queue runs with the protection of the 474.Va Giant 475kernel lock. 476The thread taskqueue 477.Va taskqueue_thread 478runs in a kernel thread context, and tasks run from this thread do 479not run under the 480.Va Giant 481kernel lock. 482If the caller wants to run under 483.Va Giant , 484he should explicitly acquire and release 485.Va Giant 486in his taskqueue handler routine. 487.Pp 488To use these queues, 489call 490.Fn taskqueue_enqueue 491with the value of the global taskqueue variable for the queue you wish to 492use. 493.Pp 494The software interrupt queues can be used, 495for instance, for implementing interrupt handlers which must perform a 496significant amount of processing in the handler. 497The hardware interrupt handler would perform minimal processing of the 498interrupt and then enqueue a task to finish the work. 499This reduces to a minimum 500the amount of time spent with interrupts disabled. 501.Pp 502The thread queue can be used, for instance, by interrupt level routines 503that need to call kernel functions that do things that can only be done 504from a thread context. 505(e.g., call malloc with the M_WAITOK flag.) 506.Pp 507Note that tasks queued on shared taskqueues such as 508.Va taskqueue_swi 509may be delayed an indeterminate amount of time before execution. 510If queueing delays cannot be tolerated then a private taskqueue should 511be created with a dedicated processing thread. 512.Sh SEE ALSO 513.Xr callout 9 , 514.Xr ithread 9 , 515.Xr kthread 9 , 516.Xr swi 9 517.Sh HISTORY 518This interface first appeared in 519.Fx 5.0 . 520There is a similar facility called work_queue in the Linux kernel. 521.Sh AUTHORS 522This manual page was written by 523.An Doug Rabson . 524