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
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout