您的位置:首页 > 其它

ULK --- Chap 4: Softirqs and Tasklets (Note)

2015-12-03 01:16 344 查看
We mentioned earlier in the section "Interrupt Handling" that several tasks among those executed

by the kernel are not critical: they can be deferred for along period of time, if necessary. Remember

that the interrupt service routines of an interrupt handler are serialized, and often there should be

no occurrence of an interrupt until the corresponding interrupt handler has terminated. Conversely,

the deferrable tasks can execute with all interrupts enabled. Taking them out of the interrupt handler

helps keep kernel response time small. This is a very important property of many time-critical applications

that expect their interrupt requests to be serviced in a few milliseconds.

[b]Linux 2.6 answers such a challenge by using two kinds of non-urgent interruptible kernel functions:[/b]

the so-called deferrable functions (softirqs and tasklets), and those executed by means of some work

queues.

Softirqs and tasklets are strictly correlated, because tasklets are implemented on top of softirqs.

As a matter of fact, the term "softirq", which appears in the kernel source code, often denotes both

kinds of deferrable functions. Another widely used term is interrupt context: it specifies that the kernel

is currently executing either an interrupt handler or a deferrable function.

Softirqs are statically allocated (i.e., defined at compile time), while tasklets can also be allocated and

initialized at runtime (for instance, when loading a kernel module). Softirqs can run concurrently on several

CPUs, even if they are of the same type. Thus, softirqs are reentrant functions and must explicitly protect

their data structures with spin locks. Tasklets do not have to worry about this, because their execution is

controlled more strictly by the kernel. Tasklets of the same type are always serialized: in other words, the

same type of takslet cannot be executed by two CPUs at the same time. However, tasklets of different types

can be executed concurrently on several CPUs. Serializing the tasklet simplifies the life of device driver

developers, because the tasklet function needs not be reentrant.

Generally speaking, four kinds of operations can be performed on deferrable functions:

Initialization: Defines a new deferrable function; this operation is usually done when the kernel initializes

itself or a module is loaded.

Activation: Marks a deferrable function as "pending" --- to be run the next time the kernel schedules a round

of executions of deferrable functions.

Masking: Selectively disables a deferrable function so that it will not be executed by the kernel even if activated.

Execution: Executes a pending deferrable function together with all other pending deferrable functions of the

same type; execution is performed at well-specified times, explained later.

Activation and execution are bound together: a deferrable function that has been activated by a given CPU

must be executed on the same CPU. There is no self-evident reason suggesting that this rule is beneficial

for system performance. Binding the deferrable function to the activating CPU could in theory make better use of

the CPU hardware cache. After all, it is conceivable that the activating kernel thread accesses some data structures

that will also be used by the deferrable function. However, the relevant lines could esasily be no longer in the cache

when the deferrable function is run because its execution can be delayed a long time. Moreover, binding a function

to a CPU is always a potentially dangerous operation, because one CPU might end up very busy while the others

are mostly idle.

                        Softirqs

Linux 2.6 uses a limited number of irqs. For most purposes, tasklets are good enough and are much easier to

write because they do not need to be reentrant.

As a matter of fact, only the six kinds of softirqs listed in following table are currently defined.

softirq Index(priority) Description

HI_SOFTIRQ 0              Handles high priority tasklets

TIMER_SOFTIRQ 1                  Tasklets related to timer interrupts

NET_TX_SOFTIRQ 2                  Transmits packets to network cards

NET_RX_SOFTIRQ 3                  Receives packets from network cards

SCSI_SOFTIRQ   4                  Post-interrupt processing of SCSI commands

TASKLET_SOFTIRQ 5                  Handles regular tasklets

The index of a softirq determines its priority: a lower index means higher priority because softirq function

will be executed starting from index 0.

The main data structures used to represent softirqs is the softirq_vec array, which includes 32 elements of

type softirq_action. The priority of a softirq is the index of the corresponding softirq_action element inside

the array. As shown in above list, only the first six entries of the array are effectively used. The softirq_action

data structure consists of two fields: an action pointer to the softirq function and a data pointer to a generic

data structure that may be needed by the softirq function.

Another critical field used to keep track both of kernel preemption and of the nesting of kernel control paths

is the 32 bit preempt_count field stored in the thread_info field of each process descriptor. This field encodes

three distinct counters plus a flag shown in following table.

Bits              Description

0-7              Preemption counter (max value = 255)

8-15              Softirq counter (max value = 255)

16-27             Hardirq counter (max value = 4096)

28               PREEMPT_ACTIVE flag

The first counter keeps track of how many times kernel preemption has been explicitly disabled on the local CPU;

the value zero means that kernel preemption has not been explicitly disabled at all.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: