In a long time, probably 2009, wrote an article on the Linux RCU lock "RCU lock in the evolution of the Linux kernel", and now I admit that while I understand the RCU lock, but I do not have the ability to use a very simple description of the implementation of Linux to show it, Saying goes you can give others a very concise description in your own way, you are really proficient in it, otherwise, it is the same as reciting. In other words, if you are interviewed, in a short time by mouth to the interviewer, and he also can understand, that he really understand, this time, will not give you the opportunity to analyze the source code, it is impossible to let you recite the source code.
After more than five years, and recently encountered this topic, I can not boast of their RCU lock is how proficient, but at least, compared with 2009, I did progress, so in this typhoon raging the next day, I try to describe in my own way a Linux RCU lock implementation, 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: If you do not know RCU lock is what, please Baidu, this article no longer repeat the concept, but this is tantamount to saying, if I myself forget the RCU one day, I can not expect to get any help from this article, I always do, is not it? Ability in forgetting not remember, get its righteousness and forget its shape.
Features of the RCU feature RCU lock include
Read sign If a reader attempts to occupy a RCU lock, it does not have to pay any price, only need to set a flag, let the outside world know that there is reader in Occupy this RCU lock, multiple reader can jointly hold a RCU lock.
Copy-on-write if there is a write attempt to update the data protected by the RCU lock, then it will first look at the read flag of the RCU lock, and if there is a flag indicating that there is at least one reader holding the RCU lock, it needs to make a copy of the original data, Write this copy and save the updated copy somewhere, waiting for the opportunity to update the original data with that copy.
Update timing This is the time to update the original data with a copy, how this point of time determines the RCU lock implementation of the algorithm core, it can directly determine all the 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 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 prohibit the Linux kernel from introducing the 2.6 kernel, in the first version, it used a preemption prohibition to flag the reader holding the RCU lock, which means that the task switch cannot occur during the period ( Refers to the sched entity switch represented by task_struct). So the sign that all reader has released the RCU lock is that the task is switched, so it's easy to update the original data with a copy when the task is switched.
All write writes a copy of itself on a list, touches the list when the task switches, and if the list is not empty, iterates through each element and update the original data.
Evaluation [This part is not related to the implementation, pure and on, can be ignored] this is the first version of the original implementation, it is reasonable to leave no matter, indeed, it can work. But:
A. Whether this implementation will affect the scheduling subsystem delay
B. If preemption is disabled, the preemption granularity becomes coarse and the interactivity is affected
C. What is the impact on task load balancing between CPUs?
We find that because the implementation of RCU is not achieved by its own mechanism, it inevitably affects the core mechanisms of the system, such as scheduling, load balancing, which means that it can not be long-term, and can not undergo complex evolution, because with its gradual evolution in this path, the impact of the system core mechanism will be more and more, so , it must be stripped from the system level. Indeed, it does so, and 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 purely natural idea is to use the counter, each RCU hold a reader counter, once the reader came to hold the lock, only need an atomic operation, the counter is added 1, writer writes the data, found that the counter is not 0 means to need make a Copy-the second feature is copied (cow-copy on write). Now the question is the third factor, how does writer know that all the Reade have been released by the lock??
The purely natural idea is that when a reader releases a lock, the counter is reduced by 1, and when the counter becomes 0 again, this is the time when the copy updates the original data. This is true, but according to the distribution of the lock and unlock, they should be equal, which means that the value of the counter fluctuates from one expectation to the next, to 0 of the hope and its faint, and therefore requires the introduction of another parameter, 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 that can be done?). ), task always knows whether it is new reader or old reader.
At this point, you can clearly define the behavior of 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 the old reader counter will always be decremented and not incremented, and new reader will not only increment and decrement, so that the timing of the choice of update is also very clear, that is, the old reader counter becomes 0, this moment, It is time to overwrite all copies with the original data.
Now summarize all the three elements:
Read Flag New reader counter for the RCU lock plus 1
Copy-on-write if the old reader counter for the RCU lock is not 0, a write-time copy is performed.
Update every time the unlock operation, the reader counter of this task (or new reader, or old reader) is reduced by 1, and once the RCU lock's old reader counter becomes 0, all update operations are performed.
Evaluation [This part is not related to the implementation, pure and on, can be ignored] hold RCU lock reader, can sleep, can be preempted, can be dispatched to other CPUs, is completely closed, and other mechanisms of the system independent. However, I have been thinking of a better realization, only because the madman does not give force!!
3.RCU Tree Implementation (really No 2 good) today there is no time to go out. Follow-up supplement.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Linux kernel rcu (Read Copy Update) lock analysis