Implementation of Soft Interrupt in the lower half of Linux interrupt

Source: Internet
Author: User

Today, I will continue to read chapter 4 "the lower half and the work to be executed after the push". I wrote "Implementation of Soft Interrupt" the day before yesterday, but it was not saved. So I wrote it again today.

Let's start from scratch. We usually cut the interrupt processing process into two parts or two halves. The interrupt handler is the top half (top half), and the job with relatively loose time requirements is the execution target of the bottom half (bottom half.

Currently, there are three mechanisms for pushing and executing jobs: Soft Interrupt, tasklet, and work queue. Soft Interrupt is a statically defined lower half interface with 32 interfaces that can be executed simultaneously on all processors, even if the two types are the same. Tasklet is a soft interrupt-based implementation mechanism with high flexibility and dynamic creation. Two different types of tasklets can be executed simultaneously on different processors, but tasklets of the same type cannot be executed simultaneously. Soft Interrupt is statically allocated during compilation, but tasklet can be dynamically registered or removed. The working pair columns are completely different from them.

The following describes the implementation of Soft Interrupt.

Soft Interrupt is represented by the softirq_action structure, which is defined in Linux/interrupt. h:

  1. Struct softirq_action
  2. {
  3. Void (* Action) (struct softirq_action *);
  4. Void * data;
  5. };

Each registered Soft Interrupt occupies one of the arrays, so a maximum of 32 interrupts may exist.

The Soft Interrupt code is located in kernel/softirq. C.

This is the third time I wrote it. I did not save it yesterday, but left the above, so I had to start from here. I'm going crazy again !!!

1. Soft interrupt handling program

The function prototype of the soft interrupt handler action (the Action function pointer in the softirq_action structure) is as follows:

Void softirq_handler (struct softirq_action *)

When the kernel runs a soft interrupt handler, it executes this action function. Its unique parameter is the pointer to the corresponding softirq_action struct. Why should we upload this struct instead of data values? The reason for doing so is to ensure that all Soft Interrupt handlers do not need to be changed when new domains are added to the struct in the future. If needed, the soft interrupt handler can easily parse its parameters and extract values from data members. In my opinion, we can use macro containof.

  1. Struct softirq_action * h;
  2. H = softirq_vec [N];
  3. H-> action (h );

One Soft Interrupt will not preemptively another Soft Interrupt. In fact, the only thing that can seize soft interruptions is the interrupt processing program. However, other soft interrupts-or even the same type of soft interrupts-can be executed simultaneously on other processors.

2. Soft execution interruption

A registered Soft Interrupt must be executed only after it is marked. This is to trigger the Soft Interrupt (raising the softirq ). The interrupt handler marks its soft interrupt before it draws the response so that it will be executed later. (About registering and triggering a Soft Interrupt at http://blog.csdn.net/qinzhonghello/archive/2008/11/29/34084?aspx)

 

In the following cases, soft interruptions to be processed will be checked and executed:

1) returned from a hardware interrupt code

2) In the ksoftirqd kernel thread

3) in the code that explicitly checks and executes the Soft Interrupt to be processed, such as the network subsystem

 

The Soft Interrupt should be executed in the do_softirq () function:

  1. Asmlinkage void do_softirq (void)
  2. {
  3. _ U32 pending;
  4. Unsigned long flags;
  5. If (in_interrupt ())
  6. Return;
  7. Local_irq_save (flags );
  8. Pending = local_softirq_pending ();
  9. If (pending)
  10. _ Do_softirq ();
  11. Local_irq_restore (flags );
  12. }

The specific analysis is as follows:

1) The macro in_interrupt () is used to determine whether the kernel is in the interrupt context. If it returns a non-zero value, it indicates that the kernel is currently executing the interrupt handler or the lower half of the handler. Defined in <ASM/hardirq. h>:

  1. # Define in_interrupt () (irq_count ())
  2. # Define irq_count () (preempt_count () & (hardirq_mask | softirq_mask ))
  3. # Define preempt_count () (current_thread_info ()-> preempt_count)
  4. /* Return a thread_info struct .*/
  5. Static inline struct thread_info * current_thread_info (void)
  6. {
  7. Struct thread_info * ti;
  8. _ ASM _ volatile _ ("And. d $ sp, % 0": "= r" (Ti): "0 "(~ 8191ul ));
  9. Return Ti;
  10. }

2) The local variable pending saves the return value of the macro softirq_pending. It is a 32-Bit Bitmap of the Soft Interrupt to be processed. If the nth value is set to 1, the Soft Interrupt of the nth value is waiting for processing.

  1. # Define local_softirq_pending ()/
  2. (Local_cpu_data (). _ softirq_pending)

3) function _ do_softirq ()

  1. /*
  2. * We restart softirq processing max_softirq_restart times,
  3. * And we fall back to softirqd after that.
  4. *
  5. * This number has been established via experimentation.
  6. * The two things to balance is latency against fairness-
  7. * We want to handle softirqs as soon as possible, but they
  8. * Shocould not be able to lock up the box.
  9. */
  10. # Define max_softirq_restart 10
  11. Asmlinkage void _ do_softirq (void)
  12. {
  13. Struct softirq_action * h;
  14. _ U32 pending;
  15. Int max_restart = max_softirq_restart;
  16. Int CPU;
  17. Pending = local_softirq_pending ();
  18. Account_system_vtime (current );
  19. _ Local_bh_disable (unsigned long) _ builtin_return_address (0 ));
  20. Trace_softirq_enter ();
  21. CPU = smp_processor_id ();
  22. Restart:
  23. /* Reset the pending bitmask before enabling irqs */
  24. Set_softirq_pending (0 );
  25. Local_irq_enable ();
  26. H = softirq_vec;
  27. Do {
  28. If (pending & 1 ){
  29. H-> action (h );
  30. Rcu_bh_qsctr_inc (CPU );
  31. }
  32. H ++;
  33. Pending> = 1;
  34. } While (pending );
  35. Local_irq_disable ();
  36. Pending = local_softirq_pending ();
  37. If (pending & -- max_restart)
  38. Goto restart;
  39. If (pending)
  40. Wakeup_softirqd ();
  41. Trace_softirq_exit ();
  42. Account_system_vtime (current );
  43. _ Local_bh_enable ();

The following code is the core part of Soft Interrupt Processing:

  1. H = softirq_vec;
  2. Do{
  3. If(Pending & 1 ){
  4. H-> action (h );
  5. Rcu_bh_qsctr_inc (CPU );
  6. }
  7. H ++;
  8. Pending> = 1;
  9. }While(Pending );

Point the pointer H to the first entry of softirq_vec. If the first entry of pending is set to 1, h-> action (H) is called, add 1 to the pointer and point to the next entry in the array. The bit mask pending shifts one bit to the right. In this way, the first bit is discarded, and other users are moved to the right one by one. Repeat until pengding changes to 0 and ends.

 

4) functions: local_irq_save (flags) and local_irq_restore (flags)

 

To disable/activate local interruptions on the current processor, run the following statement:

Local_irq_disable ();

Local_irq_enable ();

However, consider this situation: If the interruption has been disabled before local_irq_disable () is called; if the interruption may be disabled at the beginning, the call of local_irq_enable () will interrupt the unconditional activation. Therefore, a mechanism is required to restore the interruption to the previous state. The local_irq_save (flags) function saves the state of the interrupted system before the interruption is disabled. local_irq_restore (flags) restores the interruption to their original state when preparing to activate the interruption.

  1. # Define local_irq_restore (flags) do {typecheck (unsigned long, flags );/
  2. Set_signals (flags);} while (0)
  3. # Define local_irq_save (flags) do {local_save_flags (flags );/
  4. Local_irq_disable ();} while (0)

These methods appear in macro form, so the flags parameter (which must be defined as unsiged long) is passed as a value on the surface. This parameter contains the data of the specific architecture, that is, the status of the interrupted system. There is at least one architecture that combines the stack information with the value (iSCSI), so flags cannot be passed to another function (especially it must reside in the same stack frame ). For this reason, the call to local_irq_save and local_irq_restore () must be performed in the same function.


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.