taskqueue(9)
NAME
taskqueue - asynchronous task execution
SYNOPSIS
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
typedef void (*task_fn_t)(void *context, int pending);
typedef void (*taskqueue_enqueue_fn)(void *context);
struct task {
STAILQ_ENTRY(task) ta_link; /* link for
queue */
u_short ta_pending; /* count
times queued */
u_short ta_priority; /* priority
of task in queue */
task_fn_t ta_func; /* task handler */
void *ta_context; /* argument
for handler */
};
struct taskqueue *
taskqueue_create(const char *name, int mflags,
taskqueue_enqueue_fn enqueue, void *context, struct
proc **);
void
taskqueue_free(struct taskqueue *queue);
struct taskqueue *
taskqueue_find(const char *name);
int
taskqueue_enqueue(struct taskqueue *queue, struct task
*task);
int
taskqueue_enqueue_fast(struct taskqueue *queue, struct task
*task);
void
taskqueue_run(struct taskqueue *queue);
void
taskqueue_run_fast(struct taskqueue *queue);
void
taskqueue_drain(struct taskqueue *queue, struct task *task);
TASK_INIT(struct task *task, int priority, task_fn_t *func,
void *context);
TASKQUEUE_DECLARE(name);
TASKQUEUE_DEFINE(name, taskqueue_enqueue_fn enqueue, void
*context,
init);
TASKQUEUE_DEFINE_THREAD(name);
DESCRIPTION
- These functions provide a simple interface for asynchronous
- execution of
code. - The function taskqueue_create() is used to create new
- queues. The arguments to taskqueue_create() include a name that should be
- unique, a set
of malloc(9) flags that specify whether the call to malloc() - is allowed
to sleep, a function that is called from taskqueue_enqueue() - when a task
is added to the queue, and a pointer to the memory location - where the
identity of the thread that services the queue is recorded. - The function
called from taskqueue_enqueue() must arrange for the queue - to be processed (for instance by scheduling a software interrupt or
- waking a kernel thread). The memory location where the thread identity
- is recorded
is used to signal the service thread(s) to terminate--when - this value is
set to zero and the thread is signaled it will terminate. - The function taskqueue_free() should be used to remove the
- queue from the
global list of queues and free the memory used by the queue. - Any tasks
that are on the queue will be executed at this time after - which the
thread servicing the queue will be signaled that it should - exit.
- The system maintains a list of all queues which can be
- searched using
taskqueue_find(). The first queue whose name matches is re - turned, otherwise NULL.
- To add a task to the list of tasks queued on a taskqueue,
- call
taskqueue_enqueue() with pointers to the queue and task. If - the task's
ta_pending field is non-zero, then it is simply incremented - to reflect
the number of times the task was enqueued. Otherwise, the - task is added
to the list before the first task which has a lower - ta_priority value or
at the end of the list if no tasks have a lower priority. - Enqueueing a
task does not perform any memory allocation which makes it - suitable for
calling from an interrupt handler. This function will re - turn EPIPE if
the queue is being freed. - The function taskqueue_enqueue_fast() should be used in
- place of
taskqueue_enqueue() when the enqueuing must happen from a - fast interrupt
handler. This method uses spin locks to avoid the possibil - ity of sleeping in the fast interrupt context.
- To execute all the tasks on a queue, call taskqueue_run() or taskqueue_run_fast() depending on the flavour of the queue.
- When a task
is executed, first it is removed from the queue, the value - of ta_pending
is recorded and then the field is zeroed. The function - ta_func from the
task structure is called with the value of the field - ta_context as its
first argument and the value of ta_pending as its second ar - gument.
- The taskqueue_drain() function is used to wait for the task
- to finish.
There is no guarantee that the task will not be enqueued af - ter call to
taskqueue_drain(). - A convenience macro, TASK_INIT(task, priority, func,
- context) is provided
to initialise a task structure. The values of priority, - func, and
context are simply copied into the task structure fields and - the
ta_pending field is cleared. - Three macros TASKQUEUE_DECLARE(name), TASKQUEUE_DEFINE(name,
- enqueue,
context, init), and TASKQUEUE_DEFINE_THREAD(name) are used - to declare a
reference to a global queue, to define the implementation of - the queue,
and declare a queue that uses its own thread. The
TASKQUEUE_DEFINE
- macro arranges to call taskqueue_create() with the values of
- its name,
enqueue and context arguments during system initialisation. - After calling taskqueue_create(), the init argument to the macro is
- executed as a C
statement, allowing any further initialisation to be per - formed (such as
registering an interrupt handler etc.) - The TASKQUEUE_DEFINE_THREAD() macro defines a new taskqueue
- with its own
kernel thread to serve tasks. The variable struct proc *taskqueue_name_proc is defined which contains the kernel - thread serving
the tasks. The variable struct taskqueue *taskqueue_name is - used to
enqueue tasks onto the queue. - Predefined Task Queues
- The system provides four global taskqueues, taskqueue_fast, taskqueue_swi, taskqueue_swi_giant, and taskqueue_thread.
- The
taskqueue_fast queue is for swi handlers dispatched from - fast interrupt
handlers, where sleep mutexes cannot be used. The swi - taskqueues are run
via a software interrupt mechanism. The taskqueue_swi queue - runs without
the protection of the Giant kernel lock, and the - taskqueue_swi_giant
queue runs with the protection of the Giant kernel lock. - The thread
taskqueue taskqueue_thread runs in a kernel thread context, - and tasks run
from this thread do not run under the Giant kernel lock. If - the caller
wants to run under Giant, he should explicitly acquire and - release Giant
in his taskqueue handler routine. - To use these queues, call taskqueue_enqueue() with the value
- of the
global taskqueue variable for the queue you wish to use - (taskqueue_swi,
taskqueue_swi_giant, or taskqueue_thread). Use - taskqueue_enqueue_fast()
for the global taskqueue variable taskqueue_fast. - The software interrupt queues can be used, for instance, for
- implementing
interrupt handlers which must perform a significant amount - of processing
in the handler. The hardware interrupt handler would per - form minimal
processing of the interrupt and then enqueue a task to fin - ish the work.
This reduces to a minimum the amount of time spent with in - terrupts disabled.
- The thread queue can be used, for instance, by interrupt
- level routines
that need to call kernel functions that do things that can - only be done
from a thread context. (e.g., call malloc with the M_WAITOK - flag.)
- Note that tasks queued on shared taskqueues such as
- taskqueue_swi may be
delayed an indeterminate amount of time before execution. - If queueing
delays cannot be tolerated then a private taskqueue should - be created
with a dedicated processing thread.
SEE ALSO
ithread(9), kthread(9), swi(9)
HISTORY
- This interface first appeared in FreeBSD 5.0. There is a
- similar facility called tqueue in the Linux kernel.
AUTHORS
This manual page was written by Doug Rabson.
BUGS
- There is no taskqueue_create_fast().
- BSD May 19, 2005