Linux Device Drivers (3rd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Linux Device Drivers (3rd Edition) [Electronic resources] - نسخه متنی

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








7.5. Tasklets


Another kernel facility related to




timing issues is the tasklet mechanism. It is
mostly used in interrupt management (we'll see it
again in Chapter 10.)

Tasklets resemble kernel timers in some ways. They are always run at
interrupt time, they always run on the same CPU that schedules them,
and they receive an unsigned
long argument. Unlike kernel timers, however, you
can't ask to execute the function at a specific
time. By scheduling a tasklet, you simply ask for it to be executed
at a later time chosen by the kernel. This behavior is especially
useful with interrupt handlers, where the hardware interrupt must be
managed as quickly as possible, but most of the data management can
be safely delayed to a later time. Actually, a tasklet, just like a
kernel timer, is executed (in atomic mode) in the context of a
"soft interrupt," a kernel
mechanism that executes asynchronous tasks with hardware interrupts
enabled.

A tasklet exists as a data structure that must be initialized before
use. Initialization can be performed by calling a specific function
or by declaring the structure using certain macros:

#include <linux/interrupt.h>
struct tasklet_struct {
/* ... */
void (*func)(unsigned long);
unsigned long data;
};
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
DECLARE_TASKLET(name, func, data);
DECLARE_TASKLET_DISABLED(name, func, data);

Tasklets offer a number of interesting features:

  • A tasklet can be disabled and re-enabled later; it
    won't be executed until it is enabled as many times
    as it has been disabled.

  • Just like timers, a tasklet can reregister itself.

  • A tasklet can be scheduled to execute at normal priority or high
    priority. The latter group is always executed first.

  • Tasklets may be run immediately if the system is not under heavy load
    but never later than the next timer tick.

  • A tasklets can be concurrent with other tasklets but is strictly
    serialized with respect to itselfthe same tasklet never runs
    simultaneously on more than one processor. Also, as already noted, a
    tasklet always runs on the same CPU that schedules it.


The jit module includes two files,
/proc/jitasklet and
/proc/jitasklethi, that return the same data as
/proc/jitimer, introduced in Section 7.4 When you read one of the files, you get
back a header and six data lines. The first data line describes the
context of the calling process, and the other lines describe the
context of successive runs of a tasklet procedure. This is a sample
run while compiling a kernel:

phon% cat /proc/jitasklet
time delta inirq pid cpu command
6076139 0 0 4370 0 cat
6076140 1 1 4368 0 cc1
6076141 1 1 4368 0 cc1
6076141 0 1 2 0 ksoftirqd/0
6076141 0 1 2 0 ksoftirqd/0
6076141 0 1 2 0 ksoftirqd/0

As confirmed by the above data, the tasklet is run at the next timer
tick as long as the CPU is busy running a process, but it is run
immediately when the CPU is otherwise idle. The kernel provides a set
of ksoftirqd kernel threads, one per CPU, just
to run "soft interrupt" handlers,
such as the tasklet_action function. Thus, the
final three runs of the tasklet take place in the context of the
ksoftirqd kernel thread associated to CPU
0. The jitasklethi
implementation uses a high-priority tasklet, explained in an upcoming
list of functions.

The actual code in jit that implements
/proc/jitasklet and
/proc/jitasklethi is almost identical to the
code that implements /proc/jitimer, but it uses
the tasklet calls instead of the timer ones. The following list lays
out in detail the kernel interface to tasklets after the tasklet
structure has been initialized:

void tasklet_disable(struct tasklet_struct *t);


This function disables the given tasklet. The tasklet may still be
scheduled with tasklet_schedule, but its
execution is deferred until the tasklet has been enabled again. If
the tasklet is currently running, this function busy-waits until the
tasklet exits; thus, after calling
tasklet_disable, you can be sure that the
tasklet is not running anywhere in the system.


void tasklet_disable_nosync(struct tasklet_struct *t);


Disable the tasklet, but without waiting for any currently-running
function to exit. When it returns, the tasklet is disabled and
won't be scheduled in the future until re-enabled,
but it may be still running on another CPU when the function returns.


void tasklet_enable(struct tasklet_struct *t);


Enables a tasklet that had been previously disabled. If the tasklet
has already been scheduled, it will run soon. A call to
tasklet_enable must match each call to
tasklet_disable, as the kernel keeps track of
the "disable count" for each
tasklet.


void tasklet_schedule(struct tasklet_struct *t);


Schedule the tasklet for execution. If a tasklet is scheduled again
before it has a chance to run, it runs only once. However, if it is
scheduled while it runs, it runs again after it
completes; this ensures that events occurring while other events are
being processed receive due attention. This behavior also allows a
tasklet to reschedule itself.


void tasklet_hi_schedule(struct tasklet_struct *t);


Schedule the tasklet for execution with higher priority. When the
soft interrupt handler runs, it deals with high-priority tasklets
before other soft interrupt tasks, including
"normal" tasklets. Ideally, only
tasks with low-latency requirements (such as filling the audio
buffer) should use this function, to avoid the additional latencies
introduced by other soft interrupt handlers. Actually,
/proc/jitasklethi shows no human-visible
difference from /proc/jitasklet.


void tasklet_kill(struct tasklet_struct *t);


This function ensures that the tasklet is not scheduled to run again;
it is usually called when a device is being closed or the module
removed. If the tasklet is scheduled to run, the function waits until
it has executed. If the tasklet reschedules itself, you must prevent
it from rescheduling itself before calling
tasklet_kill, as with
del_timer_sync.



Tasklets are implemented in
kernel/softirq.c. The two tasklet lists (normal
and high-priority) are declared as per-CPU data structures, using the
same CPU-affinity mechanism used by kernel timers. The data structure
used in tasklet management is a simple linked list, because tasklets
have none of the sorting requirements of kernel timers.


    / 202