Linux (kernel analysis): 30 --- kernel synchronization of (spin locks (spin lock), read - write spin locks (spin wrlock))

A spin lock Overview

  • If each critical area can be as simple as increasing the variable just fine, but the reality is always cruel. The real world, the critical area can even span multiple functions. For example, we often encounter this situation: come out data from a data structure, subjected to format conversion and resolution, and finally the addition of it to another data structure. The entire process must be performed atoms, before the data is updated, not have other code to read the data. Clearly, the simple atomic operations can not do anything, which requires the use of more complex synchronization methods - locks to protect
  • Linux kernel is the most common lock spinlock (Spin Lock) . Spin lock can only be a maximum of executable thread holds:
    • If a thread of execution trying to get a hold has been (so-called contention) spin lock , then the thread will always be busy circulating a rotation lock waiting for a re-usable
    • If not lock contention , lock requests execution thread can get it immediately to continue
  • At any time, the spin lock can prevent more than one thread of execution while entering the critical section . The same lock may be used in a plurality of positions, e.g., for a given access to all data can be protected and synchronization

Non-spin and spin

  • Spin locks:
    • A spin lock contention is such that its thread requested spin (in particular waste processor time) while waiting for a lock to become available , this behavior is spin lock point. So spin lock should not be held for a long time . In fact, this is what the original intention of using spin locks: Lightweight were locked in a short period
  • Non-spin lock:
    • You can also take another way to deal with the fight against lock: make a request thread to sleep, then wake it up again until the lock is available. Processor cycle so you do not have to wait, you can go to execute other code
    • This will also bring some overhead - There are two distinct context switches , blocked thread to swap out and surrendered, compared with a few lines of code to achieve spin lock, of course, have more context switches code. Thus, the time is preferably less than holding a spin lock time-consuming to complete a context switch twice . Of course, most of us will not waste time-consuming to measure the context switch, so we let time holding a spin lock should be as short as possible on it
  • The following pages we will discuss the most signal, he provided the above second lock mechanism that makes the event of contention, the waiting thread can be put to sleep, rather than rotating

Second, the method of spin lock

  • Closely related to the implementation and architecture spin lock, code is often achieved by compiling . These architectures with codes related definitions in the file <asm / spinlock.h>, the actual need to use the interfaces defined in the file <linux / spinlock.h> in
  • The basic form using a spin lock is as follows:

  • Since the spin lock at the same time held up by a thread of execution, so a time only one thread at the critical area , which provides concurrent access to protection mechanisms needed to prevent a multi-processor machines. Note that on a single processor machine, compile time and will not join the spin lock . It is only as a set switch whether kernel preemption mechanism is enabled. If you disable kernel preemption, then the spin lock at compile time will be completely removed out of the kernel

Warning: spin locks are not recursive

  • Linux kernel implements spin locks are not recursive, to achieve this differs from the spin locks in other operating systems. So if you're trying to get a lock you are holding, you have to spin, waiting for you to release the lock. But you're in a busy waiting spin, so you never have a chance to release the lock, then you are yourself locked up. Careful spin locks

A spin lock in the interrupt handler

  • You can use the spin lock (semaphore can not be used here, because they lead to sleep) in the interrupt handler. In the use of a spin lock interrupt handler, be sure to get in before the lock, first disable local interrupts (on the current processor interrupt request), otherwise, the interrupt handler will interrupt the kernel code is holding a lock, there may try to compete with this has been held spin lock. As a result, the interrupt handler will spin waiting for the lock to become available, but the lock holder can not run before the interrupt handler is finished. This is what we mentioned earlier in the content request double deadlock. Note that need to close the only interruption on the current processor. If an interrupt occurs on different processors, even if the interrupt handler in the same spin lock, it will not interfere with the final release lock lock holder (on different processors)
  • Interrupt provided by the kernel at the same time the lock request interface, easy to use, as follows:
    • spin_lock_irqsave (): This function saves the current state of the interrupt, and disable local interrupts, and then go get the specified lock
    • spin_unlock_irqrestore (): the specified lock is unlocked, and then let the interrupted restore to the state before locking
    • So even if the interrupt was initially forbidden, the code does not activate them by mistake, on the contrary, we will continue to let them ban
    • flags variable value passed by the look like, since some parts of these locking functions are achieved by way of the macro

  • On a single processor system, although the lock mechanism discarded at compile time, but still need to close the example above interrupt, the interrupt handler to prohibit access to shared data. Locking and unlocking, respectively, can be disabled and enabled kernel preemption

What lock?

  • When using the lock must be the right remedy, it should be targeted. To know the need to protect data rather than code . Although the examples in this chapter speak of the importance of the critical areas are protected, but the real fact is the protection of critical data area, not the code
  • Principle: the code for the lock will make the program difficult to understand, and easily lead to competitive conditions, the correct approach should be on the data rather than the code lock
  • Since the code is not locked, it must use special locks to protect their shared data. For example, "struct foo locked by the loo_lock". Whenever you need access to shared data, it must first ensure that data is secure. And to ensure data security often means before the data operation, first occupied the right lock, then release it to complete the operation
  • If you can identify interrupted before locking is activated, there is no need to resume the previous state after the unlock. You can activate the interrupt unconditionally when unlocked. In this case, use ppin_lock_irq () and spin_unlock_irq () would be better

  • Since the kernel becomes large and complex, therefore, on the implementation of the road kernel interrupt you in the end is not hard to figure out is active on the current call point. Precisely because of this, we do not promote the use of spin_lock_irq () method. If you must use it, you should determine the original interrupt will be active, otherwise interrupt when other people expect when we got there in an inactive state is active, can be very unhappy

Debugging spin locks

  • Configuration options CONFIG_DEBUG_SPINLOCK to use spin lock adding a number of debugging code detection means. For example, this option is activated, the kernel will check whether the uninitialized lock, is it necessary to perform the unlocking operation of the lock when not locked. When testing the code, you should always activate this option. If you need further debugging full lock, should also open the option CONFIG_DEBUG_LOCK_ALLOC

Third, other operations for a spin lock

  • You can use spin_lock_init () method to initialize the spin lock dynamically created (At this point you have only one type of pointer spinlock_t, it is not an entity)
  • spin_try_lock () trying to get a particular spin lock, if the lock has been contention, then the method returns a non-zero value immediately, without waiting for the spin lock is released; if successful in obtaining the spin lock, the function returns 0. Similarly, spin_is_locked () method is used to check whether a particular lock is currently occupied, if already occupied, returns non-zero; otherwise zero. The determination method only, not actual occupancy
  • The following figure shows a complete list of standard spin-lock operation

Fourth, and lower spin locks

  • I mentioned in the previous article, when used in conjunction with the lower half, care must be taken to use the lock mechanism. Function spin_lock_bh () used to obtain the specified lock, and it will prohibit the implementation of all the lower half. Corresponding spin_unlock_bh () function performs the reverse operation
  • Due to the lower half of the code can seize the context of the process, so that when the lower part of the process and context sharing data , sharing data must be protected in the process context, it is necessary to lock in the lower half, and will prohibit execution . Similarly, since the interrupt handler can preempt the lower half, so if the interrupt handler and a lower share data, then you must also disable interrupts at the same time get the right lock
  • Recall that similar tasklet can not run simultaneously, so for sharing data in the same tasklet do not need protection . But when data is shared by two different kinds of tasklet, we need to get a regular spin lock before accessing data in the lower half. There is no need prohibits the lower half, because on the same processor there will never be another case of seizure of tasklet
  • For the soft interrupt, whether or not the same type, if the data is soft interrupt sharing, then it must be protected lock . This is because, even if the same type of two soft interrupt can be run simultaneously on multiple processors in a system. However, a soft cut off on the same processor does not preempt another soft interrupt, therefore, there is no need to ban the lower half

Fifth, the read-write spinlock

  • Sometimes, the lock can be clearly divided into use to read and write two scenes. For example, a list of possible but also necessary to update retrieval. When the update (writing) chain, can not have other code concurrently write or read data list from the list, the write operation requires totally exclusive. On the other hand, when to retrieve (read) list, as long as the program does not list other write on the line. As long as there is no write operation, multiple concurrent read operations are safe. Task list access pattern is very similar to this case, it is protected by a read-write spin lock
  • Read / write method used is similar to an ordinary spin lock spin lock, which is initialized by the following method:

  • Then, using the following function in the code reader of the branch:

  • Finally, use the following function in your code branch writer in:

  • Typically, read and write locks will dry completely separated bit code branch, as in the example shown in FIG.
  • Note, you can not put a read lock "upgrade" to write locks. For example, consider the following code:

  • The implementation of these two functions will lead to a deadlock, because a write lock will continue to spin, waiting for all readers to release the lock, including its own. So when do need to write, to write lock on the request at the beginning. If you can not read and write clearly separated, then the use of general spin lock on the line, do not use read-write spin locks
  • Readers can obtain more safely with a read lock, in fact, even a thread recursively get the same read lock is safe. This feature makes the read-write spinlock truly become a useful and commonly used optimization methods. If you only read the interrupt handler without a write operation, then you can mix "interrupt disable" lock, use read_lock () instead read_lock_irqsave () read protection. However, you still need to use write_lock_irqsave () Disable interrupt write operation, otherwise, interruption in the read operation is likely to lock in write lock
  • Index lists all read and write operations for a spin lock

  • When using Linux read-write spin locks, the last point to consider is that the lock mechanism to take care to read than to write a little more care. When the lock is held read and write operations can only wait for exclusive access, however, the reader it can continue successfully for holding the lock. The writer spins wait until the lock is released all readers can not get a lock. Therefore, a large number of readers must make the pending write who is hungry, when you design your own lock must remember this - there are times when such behavior is beneficial, sometimes it will bring disaster
  • 自旋锁提供了一种快速简单的锁实现方法。如果加锁时间不长并且代码不会睡眠(比如中断处理程序),利用自旋锁是最佳选择。如果加锁时间可能很长或者代码在持有锁时有可能睡眠, 那么最好使用信号量来完成加锁功能
发布了1360 篇原创文章 · 获赞 909 · 访问量 26万+

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104083379