At a very early time, probably in the 2009. Wrote an article on the Linux RCU lock "RCU lock in the evolution of the Linux kernel", I now admit. At that time I understand the RCU lock, but I do not have the ability to use a very easy description of the implementation of Linux to show out, saying goes you can give others in your own way very concise description of the narrative clearly, you are truly proficient in it. Otherwise, it is tantamount to reciting. In other words, suppose you are being interviewed. In a short period of time by Mouth said to the interviewer, and he also can listen to understand, that he really understand, this time, will not give you the opportunity to analyze the source, it is impossible to let you recite the source code.
After more than five years, recently encountered this topic, I can not claim to RCU lock is how proficient, but at least, compared with 2009, I did make progress, so in this typhoon raging the next day, I tried to describe in my own way the Linux RCU lock a way to achieve, as the " RCU lock in the evolution of the Linux kernel adds to this article. This article is not worthy of the map, no code, just text.
Disclaimer: Suppose you don't yet know what a RCU lock is. Please self-Baidu, this article no longer repeat the concept. But this is tantamount to saying, suppose I myself forget RCU one day. I can't expect to get any help from this article either. I always do, don't I? Ability in forgetting not to remember. To be righteous and forget its shape.
RCU features RCU lock features contain
Read flags Suppose a reader attempts to occupy a RCU lock, it is not necessary to pay no matter what the price, just need to set a flag, let the outside world know that there is reader in the capture of the RCU lock. Multiple reader can hold a RCU lock together.
Copy-on-write if there is a write attempt to update the data protected by the RCU lock, it first looks at the read flag of the RCU lock, assuming that there is at least one reader holding the RCU lock. It needs to make a copy of the original data, write the copy and save the updated copy somewhere, waiting for the opportunity to update the original data with that copy.
Update Timing is the time to update the original data with a copy. How this point of time is determined is the RCU lock implementation of the algorithm core, it directly can determine the entire data structure. To be exact, writer must waitting for all readers leaving to update the original data, and the question is, how does it know that all of the reader is gone?
Several implementations of the Linux kernel for RCU locks 1. Original implementation-The concept of RCU lock was introduced by using preemption to disable the Linux kernel from the 2.6 kernel. In the first version number, it took advantage of a preemption ban to flag the reader holding a RCU lock, which means that a task switch cannot occur during the period (referring to the Sched entity switchover task_struct represents).
Then all reader has released the RCU lock logo is. Task is switched, so it is very easy to update the original data with a copy when the task is switched.
All write will hang a copy of itself on a list and touch the list when the task switches, assuming that the list is non-empty, then iterate through each element. Update the original data.
Evaluation [This part is independent of the implementation, pure and can be ignored] this is the first version of the original implementation. Whether it is reasonable or not. Do. It can work. But:
A. Whether the implementation of this will affect the delay of the scheduling subsystem
B. Because preemption is disabled, the preemption granularity is coarse and the interactivity is affected
C. What is the impact on task load balancing between CPUs?
We find that because this implementation of RCU is not achieved by its own mechanism, it inevitably affects the core mechanism of the system. such as scheduling, load balancing, and so on, which means that it cannot last. Nor can it undergo complex evolution. Because with its gradual evolution on this road, the impact on the system core mechanism will be more and more large, therefore, it must be stripped from the system level. Indeed, it does the same. This is the second generation of RCU implementations-can preempt RCU locks.
2. New implementation-The use of the stage counter requires a more efficient way to sign that reader has held the lock-the first element read flag, and this sign to be as accurate as possible, and can not use the system core mechanism, to make a completely closed closed loop, not dependent on the outside of course will not affect the outside.
The natural idea is to use the counter, each RCU hold a reader counter, once the reader came to hold the lock. Just need an atomic operation, the counter will be added 1, when writer writes the data. The discovery counter is not 0, which means make a copy-copy of the second feature (Cow-copy on write).
Now the question is the third factor, how does writer know that all the Reade have already released the lock??
The purely natural idea is that when a reader releases a lock, the counter is reduced by 1. When the counter becomes 0 again. This is the time when the replica updates the original data.
This is true, but according to the distribution of lock and unlock, they should be equal, which means that the value of the counter fluctuates from one expectation to the next, to a 0 hope and a faint, so there is a need to introduce a reference, the stage.
Split the unique RCU counter into two counters: old readers and new readers.
In the beginning, choose a certain moment, the RCU lock current counter (known as the original counter) value copied a copy into the old readers, counter clear 0, the original counter is called New readers. At the end of the copy, the new readers counter is the 0,old readers counter for the current number of reader holding locks. And the lock-in task (that is, task_struct) is associated with the RCU lock (is it not a task_struct field to fix it?). )。 Task always knows whether you are new reader or old reader.
At this point, you can understand the behavior of defining lock and Unlock:
lock--set its own task to new reader and add 1 to the RCU New reader counter.
unlock--gets its own task, which is new reader or Old reader, minus 1 of its reader counter.
At this point, it is very clear that. Old reader counters will always be decremented and not incremented, and new reader will not only increment but also decrement. In this way, the time to choose Update is also very clear, that is, the old reader counter becomes 0, at this moment, it is time to overwrite all copies of the original data.
Now summarize all of the three elements:
Read Flag New reader counter for the RCU lock plus 1
Write-time copy assumes that the old reader counter for the RCU lock is not 0, then the write-time copy is run.
Update time each time the unlock operation, the reader counter for this task (or new reader. or old reader) minus 1. Once the RCU lock's old reader counter becomes 0. All update operations are run.
Evaluation [This part is not related to the implementation, but on a purely metaphysical.] Able to ignore] reader that holds RCU lock. Able to sleep and be able to be preempted. The ability to dispatch to other CPUs is completely closed, regardless of the other mechanisms of the system.
However. I have been thinking of a better realization, just because the madman does not give strength.
3.RCU Tree Implementation (really No 2 good) today there is no time to go out. Perhaps added.
A brief analysis of the Linux kernel RCU (Read Copy Update) lock