Situations in which race is generated:
(1) Multiple CPUs with symmetric multiprocessor (SMP)
(2) The process of single CPU and the process of preemption it
(3) between interrupt and process
Solving the race path: mutually exclusive access
Critical section: Access the code area of a shared resource
Mutually exclusive approaches: interrupt masking, atomic manipulation, spin lock, Semaphore, mutex
Interrupt Masking
Local_irq_disable ()/* Shielded interrupt */
...
Critical section/* Critical area */
...
Local_irq_enable ()/* Open Interrupt */
Interrupt masking can only prohibit and enable the interrupt within the CPU, not to solve the SMP multi-CPU race problem, is not recommended to use.
/* Disable interrupt operation, save current CPU's interrupt bit information */
Local_irq_save (Flags)
Local_irq_restore (Flags)
/* Only the bottom half of the interrupt is forbidden */
Local_bh_disable ()
Local_bh_enable ()
Atomic operation
1. Set the value of an atomic variable
void Atomic_set (atomic_t *v, int i); Set the value of the atomic variable to I
atomic_t v = atomic_init (0); Defines the atomic variable V and initializes it to 0
2. Get the value of an atomic variable
Atomic_read (atomic_t *v); Returns the value of an atomic variable
3. Atom variable Plus/minus
void Atomic_add (int i, atomic_t *v); Atomic variable Increase I
void Atomic_sub (int i, atomic_t *v); Atomic Variable Reduction i
4. Atomic variable self-increment/auto-decrement
void Atomic_inc (atomic_t *v); Atomic variable increased by 1
void Atomic_dec (atomic_t *v); 1 Reduction in atomic variables
5. Operation and Testing
int atomic_inc_and_test (atomic_t *v);
int atomic_dec_and_test (atomic_t *v);
int atomic_sub_and_test (int i, atomic_t *v);
The above operation returns True if the atomic variable is self-increment, self-decrement, and decrement (note no addition) to test whether it is 0, 0, or false.
6. Action and return
int Atomic_add_return (int i, atomic_t *v);
int Atomic_sub_return (int i, atomic_t *v);
int Atomic_inc_return (atomic_t *v);
int Atomic_dec_return (atomic_t *v);
The above operation adds/subtract and self-increment/decrement the atomic variable and returns the new value.
Staticatomic_t xxx_available = Atomic_init (1);/*defines an atomic variable, assigned a value of 1*/ Static intXxx_open (structInode *inode,structFile *Filp) { ... if(!atomic_dec_and_test (&xxx_available))/*A test value of 0 returns true otherwise false*/{atomic_inc (&xxx_available); return-Ebusy;/*has been opened*/ } ... return 0;/*Success*/ } Static intXxx_release (structInode *inode,structFile *Filp) {Atomic_inc (&xxx_available);/*releasing the device*/ return 0; }
Spin lock
spinlock_t lock; /* Definition */
Spin_lock_init (&lock); /* Initialize */
Spin_lock (&lock); /* Get spin Lock, protect critical zone */
.../* Critical section */
Spin_unlock (&lock); /* Unlock */
concurrency control in Linux device drivers