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