标签:
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.
Linux 2.6 answers such a challenge by using two kinds of non-urgent interruptible kernel functions:
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.
ULK --- Chap 4: Softirqs and Tasklets (Note)
标签:
原文地址:http://www.cnblogs.com/miaoyong/p/5014896.html