Now that you have so many tips, you don't care about the remaining two or three tips:
Outbound table 5: sequential lock)
When sequential locks are used, read execution units are never blocked by write execution units. At the same time, write execution units do not need to wait for all read execution units to complete the read operation. However, write execution units are mutually exclusive. If the write Execution Unit has been operated during the read operation, the read execution unit must re-read the data to ensure that the obtained data is complete.
Fatal weakness: there is a limit on the sequential lock, that is, it must require that the protected shared resources do not contain pointers. The write execution unit may invalidate the pointer, but if the read execution unit is about to access the pointer, it will cause oops.
In the Linux kernel. The read execution unit is designed as follows.
1) read start
Unsigned read_seqbegin (const seqlock_t * S1 );
Read_seqbegin_irqsave (lock, flag); [read_seqbegin_irqsave (lock, flag) = local_irq_save () + read_seqbegin ();]
2) rereading
Int read_seqretry (const seqlock_t * S1, unsigned IV );
Read_seqretry_irqrestore (lock, IV, flag); [read_seqretry_irqrestore (lock, IV, flag) = read_seqretry () + local_irq_restore ();]
The read Execution Unit uses the sequence lock mode as follows:
Do {
Seqnum = read_seqbegin (& seqlock_a );
// Read operationCodeBlock
...
} While (read_seqretry (& seqlock_a, seqnum ));
In the Linux kernel. The write execution unit is designed as follows.
1) obtain the sequence lock
Void write_seqlock (seqlock_t * S1 );
Int write _ tryseqlock (seqlock_t * S1 );
Write_seqlock_irqsave (lock, flags); [= local_irq_save () + write_seqlock ()]
Write_seqlock_irq (Lock); [= local_irq_disable () + write_seqlock ()]
Write_seqlock_bh (Lock); [= local_bh_disable () + write_seqlock ()]
2) release the sequence lock
Void write_sequnlock (seqlock_t * S1 );
Write_sequnlock_irqrestore (lock, flag); [= write_sequnlock () + local_irq_restore ()]
Write_sequnlock_irq (Lock); [= write_sequnlock () + local_irq_enable ()]
Write_sequnlock_bh (Lock); [write_sequnlock () + local_bh_enable ()]
The write Execution Unit uses the sequence lock mode as follows:
Write_seqlock (& seqlock_a );
... // Write operation code
Write_sequnlock (& seqlock_a );
Output Table 6: RCU (read-copy-Update)
For the shared data structure protected by RCU, you do not need to obtain any locks to access it. However, when accessing it, the writer first backs up a copy and then modifies the copy, modify the copy, and use a callback mechanism to re-point the original data pointer to the new data at the right time. This is when all CPUs that reference the data exit the operation on the shared data.
1) read lock. 2) unlock the read. The read mode using RCU is as follows:
Rcu_read_lock (); rcu_read_unlock (); rcu_read_lock ()
Rcu_read_lock_bh (); rcu_read_unlock_bh ();... // Read the critical section
Rcu_read_unlock ()
3) RCU-related writer functions include:
Struct rcu_head {
Struct rcu_head * Next; // The next RCU
Void (* func) (struct rcu_head * head); // processing function after obtaining the Competition Condition
};
Synchronize_rcu (void); // blocks the reader until all the readers have completed the read-end critical section. The writer can continue the next step.
Synchronize_sched (); // wait until all CPUs are in the preemption status to ensure that all interrupts (not including soft interrupts) are processed.
Void call_rcu (struct rcu_head * head, void (* func) (void * Arg), void Arg); // The writer is not blocked and can be used in the interrupt context or Soft Interrupt,
The write process using synchronize_rcu is as follows:
Define_spinlock (foo_spinlock );
Int a_new;
Spin_lock (& foo_spinlock );
// A_new =;
// Write a_new;
Synchronize_rcu ();
// A = a_new;
Spin_unlock (& foo_spinlock );
// The write process using call_rcu is as follows:
Struct protectrcu
{
Int protect;
Struct rcu_head RCU;
};
Struct protectrcu * global_pr;
// Usually used to release old data
Void callback_function (struct rcu_head * r)
{
Struct protectrcu * t;
T = container_of (R, struct protectrcu, RCU );
Kfree (t );
}
Void write_process ()
{
Struct protectrcu * t, * old;
T = kmalloc (sizeof (* t), gfp_kernel); // create a copy
Spin_lock (& foo_spinlock );
T-> protect = xx;
Old = global_pr;
Global_pr = T; // replace with a copy
Spin_unlock (& foo_spinlock );
Call_rcu (old-> RCU, callback_function );
}