the memory barrier, read-write spin lock and sequential lock of the lock mechanism in Linux kernelIn the previous blog post, I discussed the related content of atomic manipulation and spin locks, and this post will continue the discussion of locking mechanisms, including memory barriers, read and write spin locks, and sequential lock related content. The following is the first discussion of memory barrier related content. Three, memory barrier
I wonder if the reader remembers a memory barrier function when I discuss the prohibition or enable of spin lock. OK, Next, I'll discuss the specifics of the memory barrier. We first look at its concept, memorybarrier refers to the compiler and the processor to optimize the code (read and write instructions to reorder ), resulting in the memory of the write operation is not timely response to the read operation (the lock mechanism can not guarantee the timing is correct). May read a bit around the mouth, it doesn't matter, we continue to discuss, after the content, the reader will come back to read when the deep experience. Defined in the arch\x86\include\asm\system.h. First, for the barrier function (that is, the one you saw earlier in the Spin lock section), it focuses on the compiler's optimization barrier, but it does not prevent the timing of the CPU reflow instruction. Because of problems such as the timing of the rearrangement of the CPU, it is not enough to have only one barrier, so the kernel also provides several mechanisms, such as the part of the function shown in 3.1.
Figure 3.1 Memory barrier function interface in the kernel
In response to the above, it is worth mentioning that the use of these memory barriers is equivalent to disabling the processor or compiler provided by the optimization mechanism, obviously such a result will inevitably affect the performance of the program.
So how can these functions do what is mentioned in the above comments? Let's look at how they are implemented. The core of the implementation is to rely on the following directive:① Lock Instruction (mentioned in the first part);② lfence directive: Stop the relevant pipeline until the lfence the memory to read the operation of the instructions are complete;③ Sfence instruction: Stop the relevant pipeline until the sfence to write the memory before the instruction is complete,④ mfence instruction: Stop the relevant pipeline until the mfence before the memory read and write instructions to complete the operation. After understanding their core instructions, look at their source code implementations in the kernel, asshown in 3.2.
Figure 3.2 Core of the kernel barrier function of the source code
Figure 3.2 shows only a subset of functions, but the implementation of functions such as SMP_RMB () is more complex and adds some protection code specific to the SMP system, but it calls these functions such as RMB () at all. At this point, the contents of the Memory barrier section is discussed here, although the content is less, but its importance can not be neglected, at the same time, if the reader back to see, to understand the concept of memory barrier, whether there will be a new harvest.
Four, read-write spin lock
Next, we discuss the implementation principle of read-write spin lock, which is actually an upgraded version of spin lock. Again, let's look at what it can do: write-only: at most one write process, and read: You can have multiple read-write units at the same time. But reading and writing cannot be done at the same time. It is defined under Include\linux\rwlock.h, and it provides a function form similar to a spin lock, replacing only "Spin_" with " read_" or "Write_". Includes Read_lock (lock) and Read_unlock (lock),Write_lock (lock), and Write_unlock (lock). Let's take a look at how it should be used. And the use of it is actually very simple,4.1, very good understanding, that is, in the critical area before and after the addition of the lock function can be, here is not elaborate.
Figure 4.1 Example of use of a read-write spin lock
Then we'll discuss its implementation core. In fact, its implementation is very simple to discuss, just a bit around. The implementation process is almost identical to the Spin_lock, except that the last call to the architecture-related function is arch_read_lock instead of Arch_spin_lock (Spin lock Arch_spin_ Lock finally calls __ticket_spin_lock ()) and so on.
The following analysis of its source code implementation. If there is a process nowP1 A read-write spin lock is applied to the operating system and a read-write lock variable is setA has been defined, and its initial value isRw_lock_unlocked (0x01000000). Coordination diagram4.2, figure4.3 The source content shown, if this processP1 applies the read lock operation to it, theRead_lock () to read-write lock variablesA minus1, if you subtracta value result is negative, it means that there is already a process in the system (set to write_lock () lock, the system will continue to wait p2 the release of the write lock, the continuous waiting process of the source code implementation p1 read lock application succeeds, if p1 in the process of using read lock, there is another process p3 request a write-lock operation. At this time write_lock () to read-write lock variable a minus 0x01000000 and judged that if the result is nonzero, then the lock variable a has been write_lock () function locked or locked with read_lock () function, then jump to diagram a by process p1 released.
Figure 4.2 Kernel Source code of the read lock function 4.3 write lock function Kernel source code
The corresponding unlocking function is given below. as shown in 4.4.
Figure 4.4 Unlocking the kernel source of the function
The
can see the implementation of the unlock function in fact simple add 1 and minus 1 operation. The following focus on the lock function in the two application lock failure when the two link function, 4.5, figure As shown in 4.6. The use of pure assembly implementation, as shown in Figure 4.6 Shows the source content implementation mechanism is actually the same, so here only focus analysis diagram 4.5 source code. Figure 4.5 source code to understand, figure 4.6 source code nature is not a problem.
In the analysis of the source code, may be readers of the source code, such as the rep directive has some doubts. In fact, therep repeats the string operation until the contents of the CX register are 0. The combined instructions are limited, only MOVS,stos,LODs,ins and outs, such as Rep STOSB; and rep; NOP is a mixed instruction that is translated into the pause command. A semicolon in this non-commented, at/tindicates a valid delimiter for the instruction. The pause instruction provides a hint to the processor that the code sequence that the processor executes is a spin-wait state, and the processor avoids memory sequence collisions based on this hint (Intel manual Description ).
WhenAfter the Read_lock () function requests a read lock failure, firstRW variable Plus1 (Note:What RDI actually stands for isRW, they are passed through registers, without1 agoThe value of RW is-1). Immediately after executing cmpl directive rdi value 0, so with the immediate number 1 to compare. If not equal, then continue to jump to "1" flag to continue the loop comparison until equal, because when equal, the system performs a read lock release function, will rw variable plus read_ Unlock () function implementation (Figure rdi variables are also required before exiting __read_lock_failed functions. Span lang= "en-us" xml:lang= "en-US" >rw variable minus 1, indicating that another process requested a read lock to succeed, thus guaranteeing the correctness of subsequent requests to read and write the lock process. At this point, the __read_lock_failed function source analysis completed, as for __ Writed_lock_failed is a similar idea, and the reader can understand it by analogy and reasoning.
Figure 4.5 Jump function in read-lock function Figure 4.6 jump function in write-lock function
At this point, the content of the read-write spin lock is basically discussed. At this time, if the reader back to see, to understand the function of read-write spin lock, whether there are more new harvest it.
Five, sequential lock
Then I will discuss the contents of sequential lock. It is defined as follows: The read execution unit is not blocked by the write unit, allowing read and write simultaneous, but the write unit is still mutually exclusive. But simply by definition, it's easy to see a problem: what happens during a read operation, when a write occurs? Do not worry, the kernel must take this into account, the solution is: Read the execution unit to re-read the data to ensure that the resulting data is complete. However, it is important to note that the protected resource cannot contain pointers, otherwise there may be problems when rereading (such as a pointer being released ). Sequential locks are defined and implemented in the Include\linux\seqlock.h file. First look at its structure implementation, shown in5.1.
Figure 5.1 Structure definition of sequential lock
Pay particular attention to the sequence variable in the structure, which is the core content of the sequential lock, which will explain the reason later. Then let's discuss its use example,shown in 5.2. The Do-while loop in the example realizes that the problem mentioned at the beginning of this section is that if a write operation occurs during a read operation, the key to the realization of stress is the effective use of the sequence variable.
Figure 5.2 Example of using sequential locks
Let's look at the source code implementation of the sequential lock,5.3, figure 5.4, figure 5.5 shows. First, for the write operation function, as shown in Figure 5.3, you can see that it is actually the use of spin lock is the protection of the sequence variable, the process in the application of the write lock, simply the value of the sequence variable is increased 1, which is particularly similar to the one we started with about spin locks (readers can look back).
Figure 5.3 The kernel source code of the write operation function
For the read operation function, as shown in Figure 5.4, figure 5.5. You can see that when you apply for a read lock, you first save the current order, that is, the value of the sequence variable (which is already in the Do-while Loop), and then make a judgment in the read_seqretry function, Detects if the current read lock variable has changed, if it changes (call write lock function,the value of the sequence variable is increased by 1), then reread, positive 5.2 gives the example of the general, if not changed, the application read lock is successful. As for the source of the unlikely () function, which is the kernel provides a function of the variable detection, its detection speed than the general if-else faster, as to why fast, will be a more complex content, interested can see the relevant aspects of information, here no longer elaborate.
Figure 5.4 The kernel source of the read operation
Figure 5.5 The kernel source of the read operation
By reading the source code, it is possible to see that it allows simultaneous reading and writing, but the write unit is still mutually exclusive. In fact, you can look back to the previous example of the sequence of locks will understand more thoroughly.
Due to the limitations of the article, this blog post to this end, will give the "big talk Linux kernel lock mechanism of the signal volume, read and write semaphore", interested readers can continue to read the latter post. Due to the author's level limit, there are inevitably mistakes in the blog, readers are welcome to point out that we discuss each other and common progress.