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