Linux read/write spin lock

Source: Internet
Author: User

This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/yunsongice/archive/2010/05/18/5605264.aspx

The read/write spin lock is also introduced to protect the shared data structure under the SMP system. It is introduced to increase the concurrency of the kernel. As long as the kernel control path does not modify the data structure, the read/write spin lock allows multiple kernel control paths to read the same data structure at the same time. If a kernel control path wants to write this structure, it must first obtain the write lock of the read/write lock, and the write lock is authorized to exclusively access this resource. This design aims to improve the system performance by allowing concurrent reads to the data structure.
Each read/write spin lock is a rwlock_t structure:
Typedef struct {
Raw_rwlock_t raw_lock;
# If defined (CONFIG_PREEMPT) & defined (CONFIG_SMP)
Unsigned int break_lock;
# Endif
# Ifdef CONFIG_DEBUG_SPINLOCK
Unsigned int magic, owner_cpu;
Void * owner;
# Endif
# Ifdef CONFIG_DEBUG_LOCK_ALLOC
Struct lockdep_map dep_map;
# Endif
} Rwlock_t;
Typedef struct {
Volatile unsigned int lock;
} Raw_rwlock_t;
The lock field is a 32-bit field, which is divided into two different parts:
(1) A 24-bit counter indicates the number of kernel control paths for concurrent read operations on the protected data structure. The binary complement code of this counter is stored in the 0 ~ of this field ~ 23 bits.
(2) "Unlocked" flag field. This bit is set when there is no kernel control path for reading or writing. Otherwise, the value is 0. The "Unlocked" mark is stored at the 24th-bit lock field.
Note: If the spin lock is empty (the "Unlocked" flag is set and no reader is available), the value of the lock field is 0x01000000; if the writer has obtained the spin lock (the "Unlocked" mark is 0 and no reader), the value of the lock field is 0x00000000; if one, two, or more processes obtain the spin lock due to read operations, the value of the lock field is Ox00ffffff, Ox00fffffe, and so on ("Unlocked" indicates that 0 indicates the write lock, processes that write the data structure are not allowed. The binary complement of the number of readers is between 0 and ~ If the value is 0, a write process operates on the data structure ). Like the spinlock_t structure, the rwlock_t structure also includes the break_lock field.
The rwlock_init macro initializes the lock field of the read/write spin lock to 0x01000000 ("unlocked"), and initializes break_lock to 0. The algorithm is similar to spin_lock_init. The way in which a process acquires a read/write spin lock is not only whether the kernel preemptible option is set, but also related to read or write operations. The former algorithm is almost the same as the spin lock mechanism. Next we will focus on the latter:

1. Read to obtain and release a lock.

The read_lock macro acts on the read/write spin lock address * lock, which is very similar to the spin_lock macro described in the previous blog. If the kernel preemptible option is selected during kernel compilation, the read_lock macro performs operations similar to that of the spin_lock (). There is only one difference: the macro executes the _ raw_read_trylock () function to effectively obtain the read/write spin lock in step 1.
Void _ lockfunc _ read_lock (rwlock_t * lock)
{
Preempt_disable ();
Rwlock_acquire_read (& lock-> dep_map, 0, 0, _ RET_IP _);
LOCK_CONTENDED (lock, _ raw_read_trylock, _ raw_read_lock );
}
Rwlock_acquire_read is an empty function when the debug spin lock operation is not defined. So the practical function of _ read_lock is _ raw_read_trylock:
# Define _ raw_read_trylock (rwlock) _ raw_read_trylock (& (rwlock)-> raw_lock)
Static inline int _ raw_read_trylock (raw_rwlock_t * lock)
{
Atomic_t * count = (atomic_t *) lock;
Atomic_dec (count );
If (atomic_read (count)> = 0)
Return 1;
Atomic_inc (count );
Return 0;
}

The lock field of the read/write lock counter is accessed through atomic operations. Note that, despite this, the operations performed by the entire function on the counter are not Atomic. The main purpose of atomic operations is to disable kernel preemption. For example, the value of a counter may change before the if statement is used to test the counter value and 1 is returned. However, the function works normally: in fact, the function returns 1 only when the counter value is not 0 or negative before the decline, because the counter is equal to 0x0000000, it indicates that no process occupies the lock, and Ox00ffffff indicates that there is a reader. 0x00000000 indicates that there is a writer (because only one writer may exist ).

If the kernel preemption option is not selected during kernel compilation, the read_lock macro generates the following assembly language code:
Movl $ rwlp-> lock, % eax
Lock; subl $1, (% eax)
Jns 1f
Call _ read_lock_failed
1:
Here, __read_lock_failed () is the following assembly language function:
_ Read_lock_failed:
Lock; incl (% eax)
1: pause
Cmpl $1, (% eax)
Js 1b
Lock; decl (% eax)
Js _ read_lock_failed
Ret

The read_lock macro reduces the spin lock value by 1, thereby increasing the number of readers. If the descending operation produces a non-negative value, the spin lock is obtained; otherwise, the operation fails. We can see that the value of the lock field is reduced from Ox00ffffff to 0x00000000, so it is almost difficult to call the _ read_lock_failed () function. This function increases the lock field atomically to cancel the decreasing operation performed by the read_lock macro, And Then loops until the lock field changes to a positive number (greater than or equal to 0 ). Next, __read_lock_failed () tries to get the spin lock again (just after the cmpl command, another kernel control path may be write to get the spin lock ).

Releasing the read spin lock is quite simple, because the read_unlock macro simply needs to use the assembly language command to simply add the lock field counter:
Lock; incl rwlp-> lock
To reduce the reader's count, and then call preempt_enable () to re-enable kernel preemption.

2. Obtain or release a lock for the write operation.

The write_lock macro implementation method is similar to that of spin_lock () and read_lock. For example, if kernel preemption is supported, this function disables kernel preemption and immediately acquires the lock by calling _ raw_write_trylock. If the function returns 0, the lock is occupied. Therefore, the macro re-enables kernel preemption as described in the previous blog and starts a busy wait loop.
# Define write_lock (lock) _ write_lock (lock)
Void _ lockfunc _ write_lock (rwlock_t * lock)
{
Preempt_disable ();
Rwlock_acquire (& lock-> dep_map, 0, 0, _ RET_IP _);
LOCK_CONTENDED (lock, _ raw_write_trylock, _ raw_write_lock );
}

The _ raw_write_trylock () function is described as follows:
Int _ raw_write_trylock (rwlock_t * lock)
{
Atomic_t * count = (atomic_t *) lock-> lock;
If (atomic_sub_and_test (0x01000000, count ))
Return 1;
Atomic_add (0x01000000, count );
Return 0;
}

Static _ inline _ int atomic_sub_and_test (int I, atomic_t * v)
{
Unsigned char c;

_ Asm _ volatile __(
LOCK "subl % 2, % 0; sete % 1"
: "= M" (v-> counter), "= qm" (c)
: "Ir" (I), "m" (v-> counter): "memory ");
Return c;
}
Function _ raw_write_trylock () calls tomic_sub_and_test (0x01000000, count) to subtract 0x01000000 from the read/write spin lock-> lock value, so as to clear the unlocked sign (see? Is exactly 24th digits ). If the minus operation produces a value of 0 (No reader), the lock is obtained and 1 is returned. Otherwise, the function will add 0x01000000 to the spin lock value to cancel the minus operation.

Releasing a write lock is also very simple, because the write_unlock macro only needs to use assembly language commands:
Lock; addl $0x01000000, rwlp
Set the "Unlocked" identifier in the lock field, and then call preempt_enable ().

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.