Analysis of the lower part of the Linux 2.6 interrupt

  

Abstract This article mainly analyzes the lower half of the Linux 2.6 kernel, softirq, tasklet and workqueue from the perspective of the user. The specific implementation of these three mechanisms in the kernel is not For in-depth analysis, if the reader is interested in understanding, you can directly read the relevant parts of the Linux kernel source code.

Description This document is collected by Meteor from the Internet and published in the spirit of free software open source. Anyone can get, use and re-publish it for free, but you have no restrictions on others to re-publish your content. The purpose of this article is to make it useful to the reader, but without any warranty or even an implied warranty for a specific purpose. See the GNU General Public License (GPL) and the GNU Free Documentation Protocol (GFDL) for more details.

Directory 1 Overview 2 Linux 2.6 kernel interrupt lower half mechanism 2.1 softirq mechanism 2.2 tasklet mechanism 2.3 workqueue mechanism 3 comparison of several lower half mechanisms 4 selection of lower half mechanism 5 Linux and NGSA lower half Departmental mechanism comparison 5.1 NGSA interrupt lower half mechanism analysis 5.2 NGSA lower half mechanism defect analysis

1 Overview Interrupt service routines often need to run in the case of CPU off interrupts to avoid interrupt nesting and control Complicated, but the time to turn off the interrupt can not be too long, otherwise it will cause the loss of the interrupt signal. For this reason, in Linux, the interrupt handler is divided into two parts, the upper half and the lower half. The top half is typically used to execute critical programs that are closely related to the hardware. This part of the execution time is very short and runs in an interrupted environment. The time requirements are not very strict, and some of the more time-consuming operations are usually carried out to the lower half for execution. This part of the code is executed in the open interrupt. The top half handles hardware-related, called hardware interrupts, which usually require immediate execution. The lower half can be delayed for a certain period of time, and the program is executed at the appropriate time of the kernel. This is the soft interrupt we will discuss here. This article takes the current version of the Linux kernel 2.6.22 as an example to discuss the lower half of the Linux interrupt mechanism. In the 2.6 kernel, the lower half of the mechanism is mainly implemented by softirq, tasklet and workqueue. The following three mechanisms are analyzed.

2 Linux 2.6 kernel interrupts the lower half mechanism In the old version of the Linux kernel, the lower half is implemented by a mechanism called Bottom Half (referred to as BH). Initially it is based on the interrupt vector. In practice, a set of 32 pointers are used in the system to represent 32 interrupt vectors. This implementation is currently visible in the 2.4 kernel. However, it is currently not visible in the 2.6 kernel. The current Linux kernel generally implements the lower half with a soft interrupt mechanism called softirq.

2.1 softirq mechanism The original BH mechanism has two obvious defects: First, only one CPU can execute BH code at a time, and the BH function does not allow nesting. This may not matter in a single-processor system, but it is a fatal flaw in SMP systems. But the soft interrupt mechanism is different. Linux's softirq mechanism is closely linked to SMP. The design and implementation of the entire softirq mechanism always runs through an idea: "Who triggers, who executes" (Who marks, who runs), that is, each CPU is separate Responsible for the soft interrupts it triggers, without interfering with each other. This effectively utilizes the performance and features of the SMP system and greatly improves processing efficiency. Linux defines a softirq_action structure in include/linux/interrupt.h to describe a softirq request, as follows: struct softirq_action{void (*action)(struct softirq_action *);void *data;}; where function pointer action The service function points to the soft interrupt request, and data points to the parameter data that is interpreted by the service function itself. Based on the above structure, the system defines a global softirq soft interrupt vector table softirq_vec[32] in kernel/softirq.c, corresponding to the soft interrupt descriptor represented by 32 softirq_action structures. But in fact, Linux does not use 32 soft interrupt vectors. The kernel predefines the meaning of some soft interrupt vectors for us to use: enum{HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, #ifdef CONFIG_HIGH_RES_TIMERSHRTIMER_SOFTIRQ , #endif}; where HI_SOFTIRQ is used to implement high-priority soft interrupts, such as high-priority hi_tasklets, and TASKLET_SOFTIRQ is used to implement general soft interrupts such as tasklets. About the tasklet, we will introduce later. We don't need to use 32 soft interrupt vectors. In fact, the kernel's predefined soft interrupt vectors are sufficient for most of our applications. Other vectors are reserved for future kernel extensions and we should not use them. To use softirq, we must initialize it first. We use the open_softirq() function to start a specified soft interrupt vector nr, initialize the descriptor corresponding to nr, softirq_vec[nr], and set the corresponding bit of the soft interrupt mask of all CPUs to 1. The function do_softirq() is responsible for executing the soft interrupt service function set in the array softirq_vec[32]. Each CPU executes the soft interrupt service by executing this function. Since the soft interrupt service routine on the same CPU does not allow nesting, the do_softirq() function checks at the outset whether the current CPU is already in the interrupt service, and if so, returns immediately. On the same CPU, do_softirq() is executed serially. After registering a soft interrupt with open_softirq(), we need to trigger it. The kernel uses the function raise_softirq() to trigger a soft interrupt. For a given softirq, there will only be one handler, which is shared by all CPUs. Since the same softirq handler may be executed concurrently on different CPUs and create race conditions, the synchronization mechanism of the handler itself is very important. Activating a soft interrupt is typically performed in the upper half of the interrupt. When an interrupt handler wants to activate a soft interrupt, raise_softirq() is called. At some later time, when do_softirq() is run on a CPU, the associated soft interrupt handler is called. It should be noted that in the softirq mechanism, there is also a small kernel thread ksoftirqd. This is to balance the system load. Imagine that if the system keeps triggering soft interrupt requests, the CPU will continue to process soft interrupts because at least once every clock interrupt, do_softirq() is executed. In this way, isn't the other important task in the system going to be hungry because you don't get the CPU for a long time? This small kernel thread is especially useful when the system is busy. Excessive soft interrupt requests are executed in the appropriate time period of the system, giving other processes more execution opportunities. In the 2.6 kernel, do_softirq() is executed in irq_exit(). In the processing of the upper half of the interrupt, do_softirq() is called only in irq_exit() for soft interrupt processing, which is very beneficial for the upgrade and porting of the soft interrupt module. If you need to port Linux soft interrupts in our NGSA, this kind of processing does give us a lot of convenience, because we only need to make minor changes to the execution of our upper half of the interrupt. If there are many entries for soft interrupt calls in the upper half of the interrupt, then isn't it painful for our transplant?

Copyright © Windows knowledge All Rights Reserved