Instructor Chen Lijun's description of the interruption (Classic + humorous)

Source: Internet
Author: User
Instructor Chen Lijun's understanding and explanation of the interruption. The article is wonderful. After reading it, he has a new understanding of the concept of the operating system of interruption and a better understanding of the operating system. P.s. Do not dare to enjoy it alone, so it will be difficult to sleep. (I have been suffering from insomnia recently) enjoy it! I. What is an interruption? The Chinese explanation of the interruption is that it is interrupted when a middle part is blocked, paused, or failed. In computer systems, why do we need to "block, pause, and disconnect? For example, I am burning a pot of water with gas in the kitchen, so that I can only stay in the kitchen and wait for the water to open, there may be a disaster. Wait, wait, and a strange cry came out, "Why don't you close the tap ?" So I was ashamed to find that I had forgotten the boring errand after just taking over the water, so I rushed to the pipe in a panic and shut down the faucet three times or two times, the voice sent to the ear again, "Why is it so cool? ". Stretch your tongue, this little thing has passed, and my eyes fell on the kettle again. Suddenly there was a strong song coming out of the door. My favorite costume drama was about to start. I really wanted to win the door. However, I knew the sound of "cool" from the kettle: I will not enjoy my life unless I wait for the water to open. What is the relationship between this scenario and interruption? If I concentrate on waiting for the water to open, isn't the sound and music on TV making the process "disconnected, paused, or broken down in the middle? Isn't that a living "interrupt? In this scenario, I am the only subject with processing capabilities. Whether it is boiling water, turning off the faucet or watching TV, I can only do one thing at the same time. However, when I concentrate on one task, there are always many urgent or urgent things that need to be taken into consideration, some of them need to be stopped and processed right away. Only after processing can we go back and complete the previous task. "Open a pot of water !" The interrupt mechanism not only gives me the ability to handle unexpected situations, but if I can make full use of this mechanism, I can "complete multiple tasks at the same time. Back to the example of boiling water, in fact, no matter whether I am in the kitchen, the gas stove will always boil the water. What I want to do is just to turn off the gas stove in time, in order to achieve this one-second operation, I kept waiting in the kitchen for 10 minutes without stopping watching whether the pot mouth was steam. I decided to watch TV. Of course, in my lifetime, I didn't want to turn the kitchen into a sea of fire, so I got an alarm and it would scream 10 minutes later, reminding me that the water on the stove had burned out, at that time, I had time to close the gas again. I used an interruption signal-making an alarm-for a 10-minute happy time, so I couldn't help but sigh: the interruption mechanism is really a good thing. It is precisely because of the interruption mechanism that I can methodically "complete multiple tasks at the same time". The interruption mechanism actually helps me improve the concurrent "processing" capability. It can also bring the same benefits to the computer system: if an interrupt signal is generated when the keyboard is pressed, the CPU does not have to wait for the keyboard input; if an interrupt signal is sent after hard disk reading and writing is completed, the CPU can free up its hands to "serve the masses"-whether it's a human hitting the keyboard's fingertip or a back-and-forth read media head, it is too slow compared with the CPU processing speed. There is no interrupt mechanism. Just like we keep ourselves in the kitchen, computers cannot talk about parallel processing capabilities. Similar to people, the CPU also needs to face a complicated situation-in reality, accidents are everywhere-it may be that users are waiting impatiently, hitting the keyboard; it may be that there is a division of 0 in the computation, or the NIC suddenly receives a new data packet. These require specific analysis of CPU conditions, either immediately processing, or suspending the response, or ignoring it. No matter how you deal with it, you need to pause the "on-hand" work of the CPU and come up with a countermeasure. Only after the response can you go back and complete the previous mission, "boil a pot of water !" First, let's take a look at the impact of the interrupt mechanism on concurrent processing. Let's use a program to discuss the problem of water burning. If there is no "interruption" (Note: here we just imitate the interruption scenario, in fact, asynchronous events-messages-processing mechanisms are used to demonstrate the effects of interruptions. After all, there is no way to directly relate to the actual interruption in the user space, but the asynchronous event mechanism provided by the operating system for the user space can be seen as a product of imitation interruption). The design is as follows: void stayinkitchen () {bool waterisboiled = false; while (waterisboiled! = True) {bool vaporgavenoff = false; If (vaporgavenoff) waterisboiled = true; else waterisboiled = false;} // close the gas stove printf ("close gas oven. /n "); // everything is settled, and you can watch TV at last. Ten minutes of valuable time, like the dead... Watching_ TV (); return;} we can see that the whole process is as described above. All work must be executed in sequence and there is no way to complete concurrent tasks. If "interrupt" is used, set a 10-minute "alarm" when starting to boil water, and then let the CPU watch the TV (a little difficult, the specific implementation is not within the scope of our concern, leave it to the reader: & gt ;). Turn off the stove in the kitchen when the alarm is triggered. # Include & lt; sys/types. H & gt; # include & lt; unistd. H & gt; # include & lt; sys/STAT. H & gt; # include & lt; signal. H & gt; # include & lt; stdio. H & gt; // The Void sig_alarm (INT signo) {// close the gas stove printf ("close gas oven. /n ");} void watching_ TV () {While (1) {// Haha, leisurely }} int main () {// set the scheduled interruption printf ("start to boil water, set alarm") after ignition; If (sigalrm, sig_alrm) = sig_err) {perror ("signal (sigalrm) error"); Return-1 ;} // Then you can enjoy the video program printf ("watching TV! /N "); watching_ TV (); Return 0;} The two programs are executed in the user space. The second stage does not have much to do with interruptions. In fact, it only uses the signal mechanism. However, by comparing the two programs, we can clearly see how the asynchronous event processing mechanism improves the concurrent processing capability. Alarm Timer: alarm is equivalent to a timer in the system. If we call alarm (5), an alarm will be triggered in five seconds (in fact, implemented by the signal mechanism, we don't want to go into details here. If you are interested in this, please refer to Richard Stevens's immortal book "Advanced Programming for UNIX environments"). What will happen when an alarm starts? The system will execute a function. The system allows the program to decide what function it is. The programmer writes a function and calls signal to register the function. Once the function arrives at a scheduled time, the system will call the callback function provided by the programmer? Yes, but how to implement it here is not critical. We will not introduce new concepts and details ). In the above example, we provide the function sig_alarm, which is easy to do and prints the message "Close the gas stove. The two examples above are very simple, but can explain the problem. First, it proves that the asynchronous message processing mechanism can improve the system's concurrent processing capability. More importantly, it reveals the mode of this processing mechanism. You can design a processing program as needed and bind the program to a specific external event. When an external event occurs, the system automatically calls the processing program to complete related work. This mode provides a unified management method for the system and provides endless function expansion space. Interrupt description (2)-it is a very complicated task to interrupt the computer system to implement the interrupt mechanism. How can we say that people are highly intelligent creatures, and computers are an iron, without a program, nothing can be done. When dealing with an interruption process, there are too many restrictions and things to learn. First, the computer can receive a very limited number of external signals. Interruption is caused by external input, which can be said to be a stimulus. In the case of boiling water, these inputs are music of call and TV. Here we only use sound as an example. In fact, the real world can input human CPU-the brain has a lot of signals, images and smells can be accepted by us, and human information interfaces are perfect. The computer does not. The more ways to receive external signals, the more complicated the design and implementation, and the higher the cost. Therefore, personal computers (PCs) only provide one input method for all external stimuli-an electrical signal in a specific format, the format, access method, response method, and processing steps of such signals are all standardized (details will be further explained later in this article). Such signals are interrupted or interrupted signals, the entire mechanism is the interrupt mechanism. Second, computers do not know how to handle signals. The human brain can handle external input on its own. I never worry that the alarm will be overwhelmed when the alarm goes off-entering the kitchen to turn off the gas. This is a natural thing. I also want to use my brain, we know everything about the calf-unfortunately, the computer doesn't work. Without a program, it won't move. Therefore, a mechanism must be established to ensure that a proper program is executed when the external interrupt signal arrives. In addition, computers do not know how to maintain continuous work. When I go to the kitchen to turn off the gas while watching TV, I will continue to perform the TV in the end after I come back. The computer does not. If you put down the work at hand to deal with "unexpected" interruptions directly, then it will no longer be able to think about what has been done and how far it has been done. Naturally, there is no chance to "redo the old job. Such a processing method is not concurrent execution, but the East is the first, the West is a bang. So how does a general computer system solve these problems? It relies on the combination of hardware and software to implement the entire process of Interrupt Processing. We will introduce this process through the implementation of intel X86 architecture. After the CPU executes a command, the logical address of the next command is stored in the register CS and EIP. Before executing a new command, the control unit checks whether there is any interruption or exception during the execution of the previous command. If yes, the control unit will drop the command and enter the following process: 1. Determine the vector I associated with the interrupt or exception (0 ~ 55) 2. search for the processing program corresponding to the vector 3. save the current "work site" and execute the interrupted or abnormal handling procedures. 4. after the processing program is executed, return the control to the control unit. the entire process of restoring the control unit to the site and returning to continue executing the original program is shown in Figure 1: The interrupt handling process let us go deep into this process to see what problems need to be faced. 1. What is an exception? When the processor executes a wrong instruction due to a programming error (for example, the divisor is 0) or a special case (for example, a page missing) occurs during execution ), the processor generates an exception when it needs to be processed by the operating system. For most processor architectures, exception handling and interrupt handling methods are basically the same, as is the X86 architecture CPU. Exceptions are different from interruptions. exceptions must be synchronized with the CPU clock. In fact, exceptions are often called synchronization interruptions. 2. What is the interrupt vector? The interrupt vector represents the interrupt source. To some extent, it can be considered an interrupt or an exception type. There are many types of interruptions and exceptions. For example, Division by 0 is an exception, while page missing is an exception. The NIC may interrupt, and the sound card may interrupt. How can the CPU differentiate them? The interrupt vector concept is derived from this. In fact, it is an integer sent to the CPU data line. The CPU allocates a type number to each IRQ, which is used to identify different types of interruptions. Many may ask why it is so troublesome to get an interrupt vector? Why not use irq0 directly ~ Irq15 is over? For example, set irq0 to 0 and irq1 to 1 ......, Isn't that easy? In fact, the modular design rules and saving rules are embodied here. First, let's talk about conservation rules. The so-called conservation rules mean that the smaller the number of signal lines used, the better. In this way, if each IRQ uses a data line independently, for example, irq0 uses line 0, irq1 line 1 ...... In this way, 16 IRQ will use 16 lines, which is obviously a waste. A friend may immediately say: Isn't it enough to use only four lines? (2 ^ 4 = 16 ). This problem reflects the module design rules. As we have mentioned earlier, there are many types of interruptions, which may be triggered by external hardware or software. However, for CPU interruptions, there is only one type of interruption, the CPU does not need to worry whether it is triggered by external hardware or by running software itself, because for the CPU, the process of interrupt processing is the same: interrupt the current program, go to the interrupted service program for execution and return to the interrupted program for further execution. The CPU can handle a total of 256 kinds of interruptions, but it does not know whether or not it should let the CPU know whether it is a hardware interruption or a software interruption. In this way, the CPU design can be independent from the interrupt controller design, so that the work required by the CPU is simple. The CPU provides only one interface for other modules. This is the 256 Interrupt Processing vector, also known as the interrupt number. These interrupt controllers use one of the 256 interrupt numbers to interact with the CPU. For example, the first 128 digits can be used for hardware interruption and the last 128 digits after software interruption, you can also use the first 128 digits for software interruption and the last 128 digits for hardware interruption. This has nothing to do with the CPU. When you need to handle this, you only need to tell the CPU which interrupt number you are using, instead of telling the CPU where the interrupt is from. This also facilitates future expansion. For example, if another 8259 chip is added to the machine, the chip can use the idle interrupt number to see which one is used when it is idle, instead of using the 0th or 1st interrupt number. In fact, this is equivalent to a ing mechanism that maps IRQ signals to different interrupt numbers. The arrangement or numbering of IRQ is fixed, but by changing the ing mechanism, you can map IRQ to different interrupt numbers, or call different interrupt service programs. 3. What is an interrupted service program? In response to a specific interrupt, the kernel executes a function called interrupt handler or interrupt service routine (ISR )). Each device that generates an interruption has an interrupt processing program. For example, one function is used to handle the interruption from the system clock, and the other function is used to handle the interruption caused by the keyboard. In general, the interrupt service program is responsible for interacting with the hardware and telling the device that the interrupt has been received. In addition, other related work needs to be completed. For example, in addition to responding to hardware, interrupt service programs of network devices also need to copy network data packets from hardware to the memory, process them, and then hand them over to the appropriate protocol stack or application. Each interrupted service program has different levels of complexity based on the tasks to be completed. In general, a device's interrupt service program is part of its device driver, which is the kernel code used to manage the device. 4. Isolated changes do not know whether you are aware of the simplicity and beauty of the design of the previous part of interrupt handling. People are highly intelligent and can handle various unexpected situations in a targeted manner. Computers are far different from each other. They can only operate according to predefined programs. For computers, hardware only supports the transmission of electrical signals and the receipt of such signals by the CPU. The operating system must be used to handle such interruptions. The operating system supports all the interrupt signals that can be predicted in advance. Theoretically, there are no major challenges. However, after the operating system is installed on computer devices, there will always be new peripheral devices added to the system, which may lead to unexpected "unexpected" interruptions during system installation. How to support such expansion is a must for the entire system. The collaboration between hardware and software brings us the perfect answer. When a new device introduces a new type of interrupt, the CPU and operating system do not need to care about how to handle it. The CPU is only responsible for receiving the interrupt signal and referencing the interrupt service program. The operating system provides the default interrupt service. Generally, the system ignores this signal and returns it. The CPU is responsible for providing interfaces, you can use this interface to register the interrupt service program based on the specific functions of the device. If a user registers a service program that corresponds to an interruption, the CPU will call the service program registered by the user when the interruption arrives. In this way, how to operate the hardware and how to implement the hardware functions are completely independent of the CPU architecture and operating system design when the temporary system is interrupted. When you need to add a new device, you only need to inform the operating system of the interrupt number occupied by the device and write the interrupt service program according to the Interface format required by the operating system, use the functions provided by the operating system to register the service program, and the device interruption will be supported by the system. The interrupt and the handling of the interrupt are unbound. In this way, whether it is when you need to add new interruptions, when you need to change the existing interrupted service program, or when you want to cancel the support for a certain interruption, the CPU architecture and operating system do not need to be changed. 5. Save the current job "on-site". After the interrupt processing is completed, the computer will generally go back to the work that was previously done. This brings some additional "meaning" to the concept of interruption ". Note: "turning back" does not mean starting from scratch, but continuing with the progress just now. In this case, we need to retain the "field" of work before processing the interrupt signal ". The word "field" is obscure. It actually refers to an information set. It can reflect the status of a task at a certain time point and ensure that the task can be restored to this status based on the information, continue. Simply put, the field is just a set of register values. How to protect the scene and recover the scenario is one of the key considerations of the interrupt mechanism. Every interrupt processing has to go through this save and recovery process. We can abstract the steps below: 1. save Site 2. execute the specific interrupt service program. 3. returns 4 from the interrupted service. as mentioned above, the "Site" seems to be constantly changing, and there is no instantaneous change. However, the elements that actually constitute the site will not change. That is to say, the field can be saved as long as the register status is saved. Restoring "on-site" means re-loading these registers. In other words, all operations performed to protect the site and recover the site for any interruption are exactly the same. Since the operations are the same, the process and code for implementing the operations are the same. Reducing code redundancy is the basic principle of modular design. There is no reason for all interrupt service programs to implement such a function repeatedly, it should be used as a basic structure by the underlying operating system or hardware. The process of Interrupt Processing needs to be completed quickly. Therefore, the Intel CPU controller undertakes this task. Instead, all the steps above are solidified and driven by the Controller. Both the storage site and the recovery site are automatically completed by the hardware, which greatly reduces the burden on the operating system and the device driver. 6. The following section describes the hardware interrupt support details, including 8259, interrupt controller programming, and Interrupt Descriptor Table, however, I have seen Jack Leng's "8259a chip programming and interrupt processing in protection mode" (see reference 1). the readers can simply read it. Interrupt description (3)-from the outside, Linux supports interrupt in Linux, and the interrupt handler looks like a common C function. However, these functions must be declared according to specific types, so that the kernel can pass information about the processing program in a standard way. In other aspects, they seem to have nothing to do with general functions. The real difference between the interrupt handler and other kernel functions is that the interrupt handler is called by the kernel to respond to the interrupt, and they run in a special context called the interrupt context. We will discuss the interrupt context later. The interrupt may occur at any time, so the interrupt processing program may be executed at any time. Therefore, you must ensure that the interrupt handler can be executed quickly to restore the execution of the interrupted code as quickly as possible. Therefore, even though the hardware is concerned, it is very important to quickly break the service. However, for other parts of the system, it is equally important to allow the interrupt handler to complete execution within the shortest time. Even the lite version of the interrupt service program, it interacts with the hardware to tell the device that the interrupt has been received. However, we usually cannot reduce the loss of service interruption programs at will. On the contrary, we need to rely on it to do a lot of other work. As an example, we can consider the challenges faced by network device interrupt handling programs. In addition to responding to the hardware, the processing program also copies network packets from the hardware to the memory, and then processes the packets to the appropriate protocol stack or application. Obviously, the amount of exercise is not too small. Now let's analyze what the Linux operating system needs to do to support the interrupt mechanism. First, the operating system must ensure that new interruptions are supported. The computer system hardware is left to peripherals with a unified interrupt signal interface. It reinforces the access and transmission methods of Interrupt signals. in PC, the interrupt mechanism is implemented by two 8259 blocks in collaboration with the CPU. All the peripherals need to do is to send the interrupt signal to a specific pin of 8259, so that 8259 will assign an identifier for the interrupt-the interrupt vector, which is usually referred to as the interrupt vector through the interrupt vector, the CPU can find the interrupt service program in the interrupt vector-index table-interrupt vector table, which determines how to deal with the interruption. (For details, please refer to reference 1. I have a wonderful description of why this mechanism is used.) This is a mechanism stipulated by hardware, and software can only obey it unconditionally. Therefore, the operating system's support for the new break is simply to maintain the interrupt vector table. When new peripheral devices are added to the system, you must first determine the number of Interrupt vectors and provide interrupted service programs. Then, you can use the Linux kernel to call the interface, enter the information of the interrupt vector number and interrupt service program in the interrupt vector table. In this way, the CPU automatically calls the interrupt service program when it receives the interrupt signal. This registration operation is generally completed by the device driver. Secondly, the operating system must provide a simple and reliable programming interface for programmers to support interruptions. The basic process of interruption is described earlier. It will interrupt the ongoing work to execute the interrupted service program and then return to the previous Task for further execution. There are a lot of problems to be solved: How to protect the site, how to handle nested interruptions, and so on, the operating system should be resolved one by one. Programmers, even driver developers, seldom need to feel pity for interrupted processes when writing interrupted service programs. (Of course, for the sake of improving the system efficiency, writing drivers is more organized than writing user-level programs. Who puts us in the aura of system programmers ?) The operating system shields us from the details of dealing with interrupt-related hardware mechanisms and provides a set of streamlined interfaces, allowing us to easily support actual interruptions, how does Linux achieve this perfectly? CPU interrupt processing process: first, we must understand what the CPU will do when it receives the interrupt signal. No way, the operating system must understand the hardware mechanism, and it is hard to work without the hardware. Now we assume that the kernel has been initialized and the CPU runs in protected mode. After the CPU executes a command, the logical address of the next command is stored in the register CS and EIP. Before executing a new command, the control unit checks whether there is any interruption or exception during the execution of the previous command. If yes, the control unit will drop the command and enter the following process: 1. Determine the vector I associated with the interrupt or exception (0 ~ 255 ). 2. The idtr register reads item I from the IDT table (in the following description, we assume that this IDT table item contains an interrupt door or a trap door ). 3. Obtain the base address of gdt from the GDTR register and search in the gdt table to read the segment descriptor identified by the selector in the IDT table. This descriptor specifies the base address of the segment where the interrupt or exception handling program is located. 4. Make sure that the interruption is initiated by the authorized (interrupted) source. First, compare the current privileged CPL (the lower two digits of the CS register) with the descriptor privileged level of the segment descriptor (that is, DPL, stored in gdt). If CPL is smaller than DPL, A general protection exception occurs because the privileges of the interrupt handler cannot be lower than those of the program that causes the interruption. For programming exceptions, perform a further security check: Compare CPL with the DPL of the door descriptor in IDT. If DPL is smaller than CPL, a general protection exception is generated. This last check prevents user applications from accessing special traps or interrupting the door. 5. Check whether the privilege level changes, that is, whether CPL is different from the DPL of the selected segment descriptor. If yes, the control unit must start to use the stack associated with the new privileged level. Perform the following steps: A. Read the tr register to access the TSS segment of the running process. B. Load the SS and ESP registers with the correct values of stack segments and stack pointers related to the new feature level. These values can be found in TSS (see "task status segment" in Chapter 3 ). C. Save SS and ESP values in the new stack. These values define the Logical Address of the stack associated with the old privileged level. 6. If the fault has occurred, use the abnormal command address to load the Cs and EIP registers so that the command can be executed again. 7. Save eflag, Cs, and EIP content in the stack. 8. If an exception produces a hard error code, save it in the stack. 9. Load the Cs and EIP registers, whose values are the segment selector and offset field of the I-entry descriptor in the IDT table. These values provide the Logical Address of the first instruction of the interrupt or exception handling program. The last step of the control unit is to jump to the interrupt or exception handling program. In other words, after the interrupt signal is processed, the Command executed by the control unit is the first command of the selected processing program. After an interrupt or exception is handled, the corresponding handler must generate an iret command to forward control to the interrupted process, which forces the control unit: 1. load CS, EIP, or eflag registers with the values saved in the stack. If a hard error code has been pushed into the stack and is on the EIP content, the hard error code must be displayed before executing the iret command. 2. Check whether the CPL of the processing program is equal to the minimum two values in CS (this means that the interrupted process and the processing program run at the same privileged level ). If yes, iret terminates the execution; otherwise, it is transferred to the next step. 3. Load the SS and ESP registers from the stack, and therefore return to the stack associated with the old privilege level. 4. check the content of DS, es, FS, and GS segment registers. If one register contains a segment descriptor and Its DPL value is smaller than CPL, clear the corresponding segment register. The control unit is used to prohibit user-state programs (CPL = 3) from using the segment registers previously used by the kernel (DPL = 0 ). If these registers are not clear, malicious user programs may use them to access the kernel address space. Thirdly, the operating system must ensure that the interrupt information can be efficiently and reliably transmitted. (4) -Learn from RTC device interruption learn from RTC device interruption system real clock each PC has a real time clock device. When you turn off the computer power, it maintains the system's date and time information. In addition, it can also be used to generate periodic signals with a frequency change ranging from 2Hz to 8192Hz -- of course, the frequency must be a multiple of 2. In this way, the device can be used as a timer. For example, if we set the frequency to 4Hz, after the device is started, the system's real clock sends four scheduled signals per second to the CPU, which are submitted to the system through the interruption of the 8 th (the IRQ 8 of the standard PC is set in this way ). Since the real-time clock of the system is programmable, you can also set it as an alarm to trigger an alarm at a specific time-send an IRQ 8 interrupt signal to the system. From this point of view, IRQ 8 is similar to the alarm in life: the interrupt signal represents the occurrence of an alarm or timer. In the Linux operating system, the above interrupt signal can be obtained through the/dev/RTC (master device number 10, from device number 135, read-only character device) device. After the read operation is performed on the device, the returned value of the unsigned long type is obtained. The lowest byte indicates the type of interruption (Update-done after update), which is scheduled to reach alarm-rang, cycle signal periodic); the remaining bytes contain the number of times the last read operation was interrupted. If the system supports the/proc file system, the same status information can also be reflected in/proc/driver/RTC. This device can only be exclusive to each process. That is to say, after a process opens the device, other processes are not allowed to open it before it is released. In this way, your program can monitor the interruption by executing read () or select () system calls to/dev/RTC-the user process will be blocked, until the system receives the next interruption signal. For some high-speed data collection programs, this function is very useful, and the program does not have to stick to repeated queries, consuming all CPU resources; as long as you set it up, you can query it at a certain frequency. For more details and other precautions, see documentations/rtc.txt # include & lt; stdio in the kernel source code package. H & gt; # include & lt; Linux/RTC. H & gt; # include & lt; sys/IOCTL. H & gt; # include & lt; sys/time. H & gt; # include & lt; sys/types. H & gt; # include & lt; fcntl. H & gt; # include & lt; unistd. H & gt; # include & lt; errno. H & gt; int main (void) {int I, FD, retval, irqcount = 0; unsigned long TMP, data; struct rtc_time rtc_tm; // enable the RTC device FD = open ("/dev/RTC", o_rdonly); If (FD =-1) {perror ("/dev/RTC"); exit (errno);} fprintf (stderr, "/n/T/tenjoy TV while boiling water. /n "); // first, it is an example of an alarm, set "Bell" 10 minutes later // get the current date and time saved in RTC/* read the RTC time/date */retval = IOCTL (FD, rtc_rd_time, & rtc_tm ); if (retval =-1) {perror ("IOCTL"); exit (errno);} fprintf (stderr, "/n/ncurrent RTC date/time is % d-% d, % 02d: % 02d: % 02d. /n ", rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm _ Year + 1900, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); // avoid overflow rtc_tm.tm_min + = 10; If (rtc_tm.tm_sec & gt; = 60) {rtc_tm.tm_sec % = 60; rtc_tm.tm_min ++;} If (rtc_tm.tm_min = 60) {rtc_tm.tm_min = 0; rtc_tm.tm_hour ++;} If (hour = 24) Then = 0; // The actual setting is retval = IOCTL (FD, rtc_alm_set, & rtc_tm); If (retval =-1) {perror ("IOCTL"); exit (errno );} // check to see if it is set Work/* read the current alarm settings */retval = IOCTL (FD, rtc_alm_read, & rtc_tm); If (retval =-1) {perror ("IOCTL "); exit (errno);} fprintf (stderr, "alarm time now set to % 02d: % 02d: % 02d. /n ", listen, rtc_tm.tm_min, rtc_tm.tm_sec); // if the light setting is not complete, enable the alarm-type interrupt./* enable alarm interrupts */retval = IOCTL (FD, rtc_aie_on, 0); If (retval =-1) {perror ("IOCTL"); exit (errno) ;}// now the program can patiently sleep When the interruption arrives in 10 minutes, it will be awakened/* This blocks until the alarm ring causes an interrupt */retval = read (FD, & data, sizeof (unsigned long); If (retval =-1) {perror ("read"); exit (errno);} irqcount ++; fprintf (stderr, "Okay. alarm rang. /n ");} This example is a little complicated and uses open, ioctl, read, and many other system calls. It looks dazzling at the beginning. In fact, if it is simplified, the process is still "Boiling Water": set the timer, wait for the timer to time out, and execute the corresponding operations ("off the gas stove "). What readers may not understand is: This example shows the benefits of interruptions. During the 10-minute timeout process, the program can only sleep? Readers need to pay attention to their own perspectives. We say that interruptions can improve the concurrent processing capability and improve the CPU's concurrent processing capability. Here, the above program can be regarded as boiling water. before boiling water, the alarm has been well performed, and the CPU will be interrupted (with an alarm) after 10 minutes, come and execute the subsequent gas close work. That is to say, the CPU is the only subject with processing capabilities. We take the initiative to use the interrupt mechanism in the program to save CPU consumption and improve the concurrent processing capability of the CPU. What are the benefits? Imagine if we still need CPU to bake, the CPU will be able to complete the corresponding work, and other work will be the same. This is actually the moral foundation for program survival in a multi-task operating system environment-"I am for everyone, everyone is for me ". Well, this program is actually an introduction to the Linux interrupt mechanism. Now we are in the Linux interrupt world.
RTC interrupt service program contains driver/Char/RTC under the root directory of the kernel source code. in the c file, this file is the driver of the RTC device-we once mentioned that the interrupt service program is generally provided by the device driver to implement the unique operation of the device interrupt. The steps for registering an interrupt in sagalinux are equally rare in Linux. In fact, the principles of the two are slightly different, linux uses more complex implementation methods to solve a large number of practical problems (such as SMP support and interrupted sharing. When the RTC driver is loaded, the rtc_init () function is called to initialize the driver. An important role of this function is to register the interrupt handler: If (request_irq (rtc_irq, rtc_interrupt, sa_interrupt, "RTC", null) {printk (kern_err "RTC: cannot register IRQ % d/N ", rtc_irq); Return-EIO;} This request_irq function is obviously much more complicated than the function with the same name in sagalinux. You just need to check the number of parameters. However, there is no difference between the first two parameters. It can be inferred that their main functions are to bind the interrupt number to the interrupt service program. Many books provide detailed descriptions of interrupt-related functions provided by Linux to system programmers, such as "Linux kernel development ". I will not repeat the work here, and now I am focusing on interrupting the service program itself. Static irqreturn_t rtc_interrupt (int irq, void * dev_id, struct pt_regs * regs) {/** can be an alarm interrupt, update complete interrupt, * or a periodic interrupt. we store the status in the * low byte and the number of interrupts initialized ed since * The Last read in the remainder of rtc_irq_data. */spin_lock (& rtc_lock); rtc_irq_data + = 0x100; rtc_irq_data & = ~ 0xff; rtc_irq_data | = (cmos_read (rtc_intr_flags) & 0xf0); If (rtc_status & rtc_timer_on) mod_timer (& rtc_irq_timer, jiffies + Hz/rtc_freq
+ 2 * Hz/100); spin_unlock (& rtc_lock);/* now do the rest of the actions */spin_lock (& rtc_task_lock); If (rtc_callback) rtc_callback-& gt; func (rtc_callback-& gt; private_data); spin_unlock (& rtc_task_lock); unlock (& rtc_wait); kill_fasync (& signature, sigio, poll_in); Return irq_handled ;} here, we should first remind you that the interrupted service program is of the static type. That is to say, this function is a local function and can only be used in RTC. c file. How is this possible? Based on our experience gained from sagalinux, when the interruption arrives, the core code of the OS interrupt will certainly call this function. Otherwise, what is the significance of this function? In fact, the request_irq function registers the pointer pointing to this function to the corresponding query table (remember irq_handler [] In sagalinux ?). Static can only ensure that code other than the RTC. c file cannot explicitly call a function through the function name, but it cannot be hard to draw a pointer. The program uses the spin_lock function, which is a spin lock function provided by Linux. For details about the spin lock, we will introduce it in future articles. Remember that the spin lock is used to prevent other CPUs in the SMP structure from accessing data concurrently. The protected data here is rtc_irq_data. Rtc_irq_data stores information about RTC, which is updated each time it is interrupted to reflect the interrupted status. Next, if the RTC periodic timer is set, update it through the mod_timer () function. Timer is a very important concept in the Linux operating system. We will explain it in detail in future articles. The last part of the Code should be protected by setting the spin lock, which will execute a callback function that may be preset. The RTC driver allows you to register a callback function and execute it when every RTC is interrupted. Wake_up_interruptible is a very important call. After it is executed, the system will wake up the sleeping processes and the RTC interruption they are waiting for will arrive. This part involves waiting for the queue. We will also explain it in a later article. The simplest change is to further feel the interruption. It is very simple. We need to add a printk statement to the RTC interrupt service program and print what? "I'm coming, interrupt !". Next, we will add it :...... Spin_unlock (& rtc_task_lock); printk ("I'm coming, interrupt! /N "); wake_up_interruptible (& rtc_wait );...... Yes, just do this first. Please find the drivers/Char/RTC. c file of the code tree and add this printk statement to the irqreturn_t rtc_interrupt function. Then re-compile the kernel module (of course, you need to include RTC When configuring the kernel compilation option, and in the form of a module). Now, when we insert the compiled RTC. O module, execute the user space program described in the previous real-time clock section, and you will see the printed "I'm coming, interrupt!" Information. This is a real process of service interruption. If we change the running mode of the RTC device through IOCTL and set the periodic interruption, let's assume that the frequency is located at 8Hz, you will find that the information is printed eight times per second on the screen. Modifying RTC is actually the most intuitive way to understand the interrupt. I suggest you not only interrupt the service program, but also take a look at the implementation of IOCTL In the RTC driver, in this way, you will be more familiar with the actual interaction between external devices and drivers and interrupt service programs. In addition, by modifying the RTC driver, I have done a lot of strange work, for example, in the high-speed data collection process, I used high-frequency RTC interruptions to check the hardware buffer usage of the high-speed AD sampling board, and cooperated with DMA to complete data collection. Of course, this is not necessarily applicable when there are very strict time limits. However, when two 12-bit, 20-gigabit sampling rate adcards work alternately, and one kHz radar video data is continuously sampled per second, my RTC runs quite well. Of course, this may not be a beautiful and standard practice. However, I am only a programmer, not an artist. I just learned a little bit about interruptions and I finished my work, I think maybe you want to get the benefits from the secrets at the bottom of the system. Let's see you later.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.