continue to revise gitbook links

This commit is contained in:
Dongliang Mu
2024-05-05 10:28:48 +08:00
parent 94d3410447
commit 73bb068aee
7 changed files with 43 additions and 45 deletions

View File

@@ -4,17 +4,16 @@
引言
--------------------------------------------------------------------------------
这是本章的第四部分 [chapter](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/index.html) ,本章描述了内核中的同步原语,且在之前的部分我们介绍完了 [自旋锁](https://en.wikipedia.org/wiki/Spinlock) 和 [信号量](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) 两种不同的同步原语。我们将在这个章节持续学习 [同步原语](https://en.wikipedia.org/wiki/Synchronization_%28computer_science%29),并考虑另一简称 [互斥锁 (mutex)](https://en.wikipedia.org/wiki/Mutual_exclusion) 的同步原语,全名 `MUTual EXclusion`
这是本章的第四部分 [chapter](/SyncPrim/index.html) ,本章描述了内核中的同步原语,且在之前的部分我们介绍完了 [自旋锁](https://en.wikipedia.org/wiki/Spinlock) 和 [信号量](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) 两种不同的同步原语。我们将在这个章节持续学习 [同步原语](https://en.wikipedia.org/wiki/Synchronization_%28computer_science%29),并考虑另一简称 [互斥锁 (mutex)](https://en.wikipedia.org/wiki/Mutual_exclusion) 的同步原语,全名 `MUTual EXclusion`
与 [本书](https://xinqiu.gitbooks.io/linux-insides-cn/content) 前面所有章节一样我们将先尝试从理论面来探究此同步原语在此基础上再探究Linux内核所提供用来操作 `互斥锁` 的 [API](https://en.wikipedia.org/wiki/Application_programming_interface)。
与 [本书](/) 前面所有章节一样我们将先尝试从理论面来探究此同步原语在此基础上再探究Linux内核所提供用来操作 `互斥锁` 的 [API](https://en.wikipedia.org/wiki/Application_programming_interface)。
让我们开始吧。
`互斥锁` 的概念
--------------------------------------------------------------------------------
从前一 [部分](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/linux-sync-3.html),我们已经很熟悉同步原语 [信号量](https://en.wikipedia.org/wiki/Semaphore_%28programming%29)。其表示为:
从前一 [部分](/SyncPrim/linux-sync-3.html),我们已经很熟悉同步原语 [信号量](https://en.wikipedia.org/wiki/Semaphore_%28programming%29)。其表示为:
```C
struct semaphore {
@@ -78,7 +77,7 @@ struct mutex_waiter {
};
```
此结构定义在[include/linux/mutex.h](https://github.com/torvalds/linux/blob/master/include/linux/mutex.h) 头文件且使用上可能会被睡眠。在研究Linux内核提供用来操作 `互斥锁` 的 [API](https://en.wikipedia.org/wiki/Application_programming_interface) 前,让我们先研究 `mutex_waiter` 结构。如果你有阅读此章节的 [前一部分](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/linux-sync-3.html),你可以能会注意到 `mutex_waiter` 结构与 [kernel/locking/semaphore.c](https://github.com/torvalds/linux/blob/master/kernel/locking/semaphore.c) 源代码中的 `semaphore_waiter` 结构相似:
此结构定义在[include/linux/mutex.h](https://github.com/torvalds/linux/blob/master/include/linux/mutex.h) 头文件且使用上可能会被睡眠。在研究Linux内核提供用来操作 `互斥锁` 的 [API](https://en.wikipedia.org/wiki/Application_programming_interface) 前,让我们先研究 `mutex_waiter` 结构。如果你有阅读此章节的 [前一部分](/SyncPrim/linux-sync-3.md),你可以能会注意到 `mutex_waiter` 结构与 [kernel/locking/semaphore.c](https://github.com/torvalds/linux/blob/master/kernel/locking/semaphore.c) 源代码中的 `semaphore_waiter` 结构相似:
```C
struct semaphore_waiter {
@@ -115,7 +114,7 @@ struct semaphore_waiter {
}
```
这个宏被定义在 [相同的](https://github.com/torvalds/linux/blob/master/include/linux/mutex.h) 头文件,并且我们可以了解到它初始化了 `mutex` 解构体中的字段。`count` 被初始化为 `1` ,这代表该互斥锁状态为 `无锁``wait_lock` [自旋锁](https://en.wikipedia.org/wiki/Spinlock) 被初始化为无锁状态,而最后的栏位 `wait_list` 被初始化为空的 [双向列表](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-1.html)。
这个宏被定义在 [相同的](https://github.com/torvalds/linux/blob/master/include/linux/mutex.h) 头文件,并且我们可以了解到它初始化了 `mutex` 解构体中的字段。`count` 被初始化为 `1` ,这代表该互斥锁状态为 `无锁``wait_lock` [自旋锁](https://en.wikipedia.org/wiki/Spinlock) 被初始化为无锁状态,而最后的栏位 `wait_list` 被初始化为空的 [双向列表](/DataStructures/linux-datastructures-1.md)。
第二种做法允许我们动态初始化一个 `互斥锁`。为此我们需要调用在 [kernel/locking/mutex.c](https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c) 源码文件的 `__mutex_init` 函数。事实上,大家很少直接调用 `__mutex_init` 函数。取而代之,我们使用下面的 `mutex_init` :
@@ -160,7 +159,7 @@ static inline bool osq_is_locked(struct optimistic_spin_queue *lock)
}
```
`__mutex_init` 函数的结尾阶段,我们可以看到它调用了 `debug_mutex_init` 函数,不过就如同我在此 [章节](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/) 前面提到的那样,我们并不会在此章节讨论调试相关的内容。
`__mutex_init` 函数的结尾阶段,我们可以看到它调用了 `debug_mutex_init` 函数,不过就如同我在此 [章节](/SyncPrim/) 前面提到的那样,我们并不会在此章节讨论调试相关的内容。
`互斥锁` 结构被初始化后,我们可以继续研究 `互斥锁` 同步原语的 `上锁``解锁` API。`mutex_lock``mutex_unlock` 函数的实现位于 [kernel/locking/mutex.c](https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c) 源码文件。首先,让我们从 `mutex_lock` 的实现开始吧。代码如下:
@@ -177,7 +176,7 @@ void __sched mutex_lock(struct mutex *lock)
`might_sleep` 宏之后,我们可以看到 `__mutex_fastpath_lock` 函数被调用。此函数是体系结构相关的,并且因为我们此书探讨的是 [x86_64](https://en.wikipedia.org/wiki/X86-64) 体系结构, \ `__mutex_fastpath_lock` 的实现部分位于 [arch/x86/include/asm/mutex_64.h](https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/mutex_64.h) 头文件。正如我们从`__mutex_fastpath_lock` 函数名称可以理解的那样,此函数将尝试通过 fast path 试图获取一个锁,或者换句话说此函数试图递减一个给定互斥锁的 `count` 字段。
`__mutex_fastpath_lock` 函数的实现由两部分组成。第一部分是 [内联汇编](https://xinqiu.gitbooks.io/linux-insides-cn/content/Theory/linux-theory-3.html) 。让我们看看:
`__mutex_fastpath_lock` 函数的实现由两部分组成。第一部分是 [内联汇编](/Theory/linux-theory-3.md) 。让我们看看:
```C
asm_volatile_goto(LOCK_PREFIX " decl %0\n"
@@ -403,7 +402,7 @@ if (!list_empty(&lock->wait_list)) {
* `mutex_lock_killable`;
* `mutex_trylock`.
以及对应相同前缀的 `unlock` 函数. 我们就不在此解释这些 `API` 了, 因为他们跟 `信号量` 所提供的 `API` 类似。你可以通过阅读 [前一部分](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/linux-sync-3.html) 来了解更多。
以及对应相同前缀的 `unlock` 函数. 我们就不在此解释这些 `API` 了, 因为他们跟 `信号量` 所提供的 `API` 类似。你可以通过阅读 [前一部分](/SyncPrim/linux-sync-3.md) 来了解更多。
总结
--------------------------------------------------------------------------------
@@ -427,12 +426,12 @@ if (!list_empty(&lock->wait_list)) {
* [lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
* [Atomic](https://en.wikipedia.org/wiki/Linearizability)
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
* [Doubly linked list](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-1.html)
* [Doubly linked list](/DataStructures/linux-datastructures-1.md)
* [x86_64](https://en.wikipedia.org/wiki/X86-64)
* [Inline assembly](https://xinqiu.gitbooks.io/linux-insides-cn/content/Theory/linux-theory-3.html)
* [Inline assembly](/Theory/linux-theory-3.md)
* [Memory barrier](https://en.wikipedia.org/wiki/Memory_barrier)
* [Lock instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
* [JNS instruction](http://unixwiz.net/techtips/x86-jumps.html)
* [preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29)
* [Unix signals](https://en.wikipedia.org/wiki/Unix_signal)
* [Previous part](https://xinqiu.gitbooks.io/linux-insides-cn/content/SyncPrim/linux-sync-3.html)
* [Previous part](/SyncPrim/linux-sync-3.md)

View File

@@ -4,9 +4,9 @@ Synchronization primitives in the Linux kernel. Part 5.
Introduction
--------------------------------------------------------------------------------
This is the fifth part of the [chapter](https://0xax.gitbooks.io/linux-insides/content/SyncPrim/index.html) which describes synchronization primitives in the Linux kernel and in the previous parts we finished to consider different types [spinlocks](https://en.wikipedia.org/wiki/Spinlock), [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) and [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) synchronization primitives. We will continue to learn [synchronization primitives](https://en.wikipedia.org/wiki/Synchronization_%28computer_science%29) in this part and start to consider special type of synchronization primitives - [readerswriter lock](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock).
This is the fifth part of the [chapter](/SyncPrim/) which describes synchronization primitives in the Linux kernel and in the previous parts we finished to consider different types [spinlocks](https://en.wikipedia.org/wiki/Spinlock), [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) and [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) synchronization primitives. We will continue to learn [synchronization primitives](https://en.wikipedia.org/wiki/Synchronization_%28computer_science%29) in this part and start to consider special type of synchronization primitives - [readerswriter lock](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock).
The first synchronization primitive of this type will be already familiar for us - [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29). As in all previous parts of this [book](https://0xax.gitbooks.io/linux-insides/content), before we will consider implementation of the `reader/writer semaphores` in the Linux kernel, we will start from the theoretical side and will try to understand what is the difference between `reader/writer semaphores` and `normal semaphores`.
The first synchronization primitive of this type will be already familiar for us - [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29). As in all previous parts of this [book](/), before we will consider implementation of the `reader/writer semaphores` in the Linux kernel, we will start from the theoretical side and will try to understand what is the difference between `reader/writer semaphores` and `normal semaphores`.
So, let's start.
@@ -15,7 +15,7 @@ Reader/Writer semaphore
Actually there are two types of operations may be performed on the data. We may read data and make changes in data. Two fundamental operations - `read` and `write`. Usually (but not always), `read` operation is performed more often than `write` operation. In this case, it would be logical to we may lock data in such way, that some processes may read locked data in one time, on condition that no one will not change the data. The [readers/writer lock](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) allows us to get this lock.
When a process which wants to write something into data, all other `writer` and `reader` processes will be blocked until the process which acquired a lock, will not release it. When a process reads data, other processes which want to read the same data too, will not be locked and will be able to do this. As you may guess, implementation of the `reader/writer semaphore` is based on the implementation of the `normal semaphore`. We already familiar with the [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) synchronization primitive from the third [part]((https://0xax.gitbooks.io/linux-insides/content/SyncPrim/sync-4.html) of this chapter. From the theoretical side everything looks pretty simple. Let's look how `reader/writer semaphore` is represented in the Linux kernel.
When a process which wants to write something into data, all other `writer` and `reader` processes will be blocked until the process which acquired a lock, will not release it. When a process reads data, other processes which want to read the same data too, will not be locked and will be able to do this. As you may guess, implementation of the `reader/writer semaphore` is based on the implementation of the `normal semaphore`. We already familiar with the [semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) synchronization primitive from the third [part](/SyncPrim/linux-sync-3.md) of this chapter. From the theoretical side everything looks pretty simple. Let's look how `reader/writer semaphore` is represented in the Linux kernel.
The `semaphore` is represented by the:
@@ -422,12 +422,12 @@ Links
* [Semaphore](https://en.wikipedia.org/wiki/Semaphore_%28programming%29)
* [Mutex](https://en.wikipedia.org/wiki/Mutual_exclusion)
* [x86_64 architecture](https://en.wikipedia.org/wiki/X86-64)
* [Doubly linked list](https://0xax.gitbooks.io/linux-insides/content/DataStructures/dlist.html)
* [Doubly linked list](/DataStructures/linux-datastructures-1.md)
* [MCS lock](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf)
* [API](https://en.wikipedia.org/wiki/Application_programming_interface)
* [Linux kernel lock validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt)
* [Atomic operations](https://en.wikipedia.org/wiki/Linearizability)
* [Inline assembly](https://0xax.gitbooks.io/linux-insides/content/Theory/asm.html)
* [Inline assembly](/Theory/linux-theory-3.md)
* [XADD instruction](http://x86.renejeschke.de/html/file_module_x86_id_327.html)
* [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html)
* [Previous part](/SyncPrim/linux-sync-4.md)