Mutual Exclusion and synchronization -- local_irq_enable and local_irq_disable

Source: Internet
Author: User

Kernel version: 2.6.30

Platform: Arm

In a single processor that cannot be preemptible, local_irq_enable and local_irq_disable can be used to eliminate asynchronous sources. Avoid using these two Macros in the driver (the system cannot respond to the interruption for a long time). These two macros are often used in the mutex mechanism, such as the spin lock, to be introduced later. Local_irq_enable macro is used to enable the interrupt of the local processor, while local_irq_disable macro is used to disable the interrupt of the local processor. The two macros are defined as follows:

 

Linux/include/linux/irqflags.h  59 #define local_irq_enable() \ 60         do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0) 61 #define local_irq_disable() \ 62         do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) 

Trace_hardirqs_on () and trace_hardirqs_off () are used for debugging. Here we will focus on raw_local_irq_enable () and raw_local_irq_disable (). The specific implementation of these two macros depends on the processor architecture, different processors have different commands to disable or enable the processor to respond to external interruptions. The implementation of the ARM platform is as follows:

Linux/ARCH/ARM/include/ASM/irqflags. H 8/* 9 * CPU interrupt mask handling. 10 */11 # If _ linux_arm_arch _> = 6 // armv6 and later instruction sets, use the cpsie command to complete 21 # define raw_local_irq_enable () _ ASM _ ("cpsie I @ _ STI": "Memory", "cc") 22 # define raw_local_irq_disable () _ ASM _ ("cpsid I @ _ CLI": "Memory", "cc") 23 # define local_fiq_enable () _ ASM _ ("cpsie f @ _ STF": "Memory", "cc") 24 # define local_fiq_disable () _ ASM _ ("cpsid f @ _ CLF": "Memory", "cc") 25 26 # else // armv6 instruction set, the S3C2440 instruction set is armv4t, run the MRS and MSR commands to complete 27 28/* 29 * Save the current interrupt enable State & disable irqs 30 */43 44/* 45 * enable irqs 46 */47 # define raw_local_irq_enable () \ 48 ({\ 49 unsigned long temp; \ 50 _ ASM _ volatile _ (\ 51 "Mrs % 0, CPSR @ local_irq_enable \ n "\ 52" Bic % 0, % 0, #128 \ n "\ 53" MSR cpsr_c, % 0 "\ // cpsr_c stands for 54 lower 8 bits: "= r" (temp) \ 55: \ 56: "Memory", "cc"); \ 57 }) 58 59/* 60 * disable irqs 61 */62 # define raw_local_irq_disable () \ 63 ({\ 64 unsigned long temp; \ 65 _ ASM _ volatile _ (\ 66 "Mrs % 0, CPSR @ local_irq_disable \ n" \ 67 "Orr % 0, % 0, #128 \ n "\ 68" MSR cpsr_c, % 0 "\ 69:" = r "(temp) \ 70: \ 71:" Memory "," cc "); \ 72}) 103 104 # endif

In a single processor cannot seize the system, if a piece of code needs to access a shared resource, use local_irq_disable to disable the interruption before entering the critical section. In this way, the asynchronous and source will not appear in the critical section, call local_irq_enable to enable interruption when the accessed shared data is in the out-of-critical section.

Local_irq_disable and local_irq_enable have another variants: local_irq_save and local_irq_restore, which are defined as follows:

 

Linux/include/linux/irqflags.h 63 #define local_irq_save(flags)                           \ 64         do {                                            \ 65                 typecheck(unsigned long, flags);        \ 66                 raw_local_irq_save(flags);              \ 67                 trace_hardirqs_off();                   \ 68         } while (0) 69  70  71 #define local_irq_restore(flags)                        \ 72         do {                                            \ 73                 typecheck(unsigned long, flags);        \ 74                 if (raw_irqs_disabled_flags(flags)) {   \ 75                         raw_local_irq_restore(flags);   \ 76                         trace_hardirqs_off();           \ 77                 } else {                                \ 78                         trace_hardirqs_on();            \ 79                         raw_local_irq_restore(flags);   \ 80                 }                                       \ 81         } while (0)

The biggest difference between these two macros and local_irq_disable and local_irq_enable is that local_irq_save will keep the current flag of the processor in an unsigned long flags before shutting down the interrupt. When local_irq_restore is called, restore the saved flags to the flags register of the processor. This is done to prevent the previous interruption response status from being damaged by calling local_irq_disable and local_irq_enable in a closed interrupt environment.

Next, let's take a look at the specific implementation of raw_local_irq_save and raw_local_irq_restore:

Linux/arch/arm/include/asm/irqflags.h 11 #if __LINUX_ARM_ARCH__ >= 6 12  13 #define raw_local_irq_save(x)                                   \ 14         ({                                                      \ 15         __asm__ __volatile__(                                   \ 16         "mrs    %0, cpsr                @ local_irq_save\n"     \ 17         "cpsid  i"                                              \ 18         : "=r" (x) : : "memory", "cc");                         \ 19         })  26 #else 27  28 /* 29  * Save the current interrupt enable state & disable IRQs 30  */ 31 #define raw_local_irq_save(x)                                   \ 32         ({                                                      \ 33                 unsigned long temp;                             \ 34                 (void) (&temp == &x);                           \ 35         __asm__ __volatile__(                                   \ 36         "mrs    %0, cpsr                @ local_irq_save\n"     \ 37 "       orr     %1, %0, #128\n"                                 \ 38 "       msr     cpsr_c, %1"                                     \ 39         : "=r" (x), "=r" (temp)                                 \ 40         :                                                       \ 41         : "memory", "cc");                                      \ 42         })104 #endif116 /*117  * restore saved IRQ & FIQ state118  */119 #define raw_local_irq_restore(x)                                \120         __asm__ __volatile__(                                   \121         "msr    cpsr_c, %0              @ local_irq_restore\n"  \122         :                                                       \123         : "r" (x)                                               \124         : "memory", "cc")125 

In a single processor that cannot be preemptible, using local_irq_disable and local_irq_enable and their variants is a simple and effective way to protect shared data. Note that local_irq_disable and local_irq_enable are mutually exclusive by disabling interruption. Therefore, you must ensure that the code execution time between the two cannot be too long, otherwise, the system performance will be affected.

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.