From 597129cf44b0c20f56d9184a2548f76aa7f09292 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Thu, 15 Mar 2018 19:49:38 -0400 Subject: [PATCH] fix wrong urls --- Initialization/linux-initialization-1.md | 2 +- Initialization/linux-initialization-4.md | 4 ++-- Initialization/linux-initialization-6.md | 2 +- Initialization/linux-initialization-7.md | 14 +++++++------- Initialization/linux-initialization-8.md | 10 +++++----- Initialization/linux-initialization-9.md | 8 ++++---- Interrupts/linux-interrupts-1.md | 2 +- Interrupts/linux-interrupts-10.md | 6 +++--- Interrupts/linux-interrupts-9.md | 6 +++--- MM/linux-mm-3.md | 6 +++--- SyncPrim/linux-sync-2.md | 4 ++-- SyncPrim/linux-sync-3.md | 8 ++++---- SysCall/linux-syscall-2.md | 4 ++-- SysCall/linux-syscall-3.md | 4 ++-- SysCall/linux-syscall-4.md | 4 ++-- Timers/linux-timers-3.md | 8 ++++---- Timers/linux-timers-4.md | 8 ++++---- Timers/linux-timers-5.md | 4 ++-- 18 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Initialization/linux-initialization-1.md b/Initialization/linux-initialization-1.md index 9e155de..997e290 100644 --- a/Initialization/linux-initialization-1.md +++ b/Initialization/linux-initialization-1.md @@ -491,7 +491,7 @@ INIT_PER_CPU(gdt_page); `INIT_PER_CPU` 扩展后也将得到 `init_per_cpu__gdt_page` 并将它的值设置为相对于 `__per_cpu_load` 的偏移量。这样,我们就得到了新GDT的正确的基地址。 -per-CPU变量是2.6内核中的特性。顾名思义,当我们创建一个 `per-CPU` 变量时,每个CPU都会拥有一份它自己的拷贝,在这里我们创建的是 `gdt_page` per-CPU变量。这种类型的变量有很多有点,比如由于每个CPU都只访问自己的变量而不需要锁等。因此在多处理器的情况下,每一个处理器核心都将拥有一份自己的 `GDT` 表,其中的每一项都代表了一块内存,这块内存可以由在这个核心上运行的线程访问。这里 [Theory/per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 有关于 `per-CPU` 变量的更详细的介绍。 +per-CPU变量是2.6内核中的特性。顾名思义,当我们创建一个 `per-CPU` 变量时,每个CPU都会拥有一份它自己的拷贝,在这里我们创建的是 `gdt_page` per-CPU变量。这种类型的变量有很多有点,比如由于每个CPU都只访问自己的变量而不需要锁等。因此在多处理器的情况下,每一个处理器核心都将拥有一份自己的 `GDT` 表,其中的每一项都代表了一块内存,这块内存可以由在这个核心上运行的线程访问。这里 [Concepts/per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 有关于 `per-CPU` 变量的更详细的介绍。 在加载好了新的全局描述附表之后,跟之前一样我们重新加载一下各个段: diff --git a/Initialization/linux-initialization-4.md b/Initialization/linux-initialization-4.md index b2bdc86..f120150 100644 --- a/Initialization/linux-initialization-4.md +++ b/Initialization/linux-initialization-4.md @@ -208,7 +208,7 @@ int cpu = smp_processor_id(); #define raw_smp_processor_id() (this_cpu_read(cpu_number)) ``` -`this_cpu_read` 函数与其它很多函数一样如(`this_cpu_write`, `this_cpu_add` 等等...) 被定义在[include/linux/percpu-defs.h](https://github.com/torvalds/linux/blob/master/include/linux/percpu-defs.h) 此部分函数主要为对 `this_cpu` 进行操作. 这些操作提供不同的对每cpu[per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Theory/per-cpu.html) 变量相关访问方式. 譬如让我们来看看这个函数 `this_cpu_read`: +`this_cpu_read` 函数与其它很多函数一样如(`this_cpu_write`, `this_cpu_add` 等等...) 被定义在[include/linux/percpu-defs.h](https://github.com/torvalds/linux/blob/master/include/linux/percpu-defs.h) 此部分函数主要为对 `this_cpu` 进行操作. 这些操作提供不同的对每cpu[per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 变量相关访问方式. 譬如让我们来看看这个函数 `this_cpu_read`: ``` __pcpu_size_call_return(this_cpu_read_, pcp) @@ -311,7 +311,7 @@ static inline int __check_is_bitmap(const unsigned long *bitmap) 原来此函数始终返回1,事实上我们需要这样的函数才达到我们的目的: 它在编译时给定一个`bitmap`,换句话将就是检查`bitmap`的类型是否是`unsigned long *`,因此我们仅仅通过`to_cpumask`宏指令将类型为`unsigned long`的数组转化为`struct cpumask *`。现在我们可以调用`cpumask_set_cpu` 函数,这个函数仅仅是一个 `set_bit`给CPU掩码的功能函数。所有的这些`set_cpu_*`函数的原理都是一样的。 -如果你还不确定`set_cpu_*`这些函数的操作并且不能理解 `cpumask`的概念,不要担心。你可以通过读取这些章节[cpumask](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) or [documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt).来继续了解和学习这些函数的原理。 +如果你还不确定`set_cpu_*`这些函数的操作并且不能理解 `cpumask`的概念,不要担心。你可以通过读取这些章节[cpumask](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) or [documentation](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt).来继续了解和学习这些函数的原理。 现在我们已经激活第一个CPU,我们继续接着start_kernel函数往下走,下面的函数是`page_address_init`,但是此函数不执行任何操作,因为只有当所有内存不能直接映射的时候才会执行。 diff --git a/Initialization/linux-initialization-6.md b/Initialization/linux-initialization-6.md index b951b74..c5bf0e3 100644 --- a/Initialization/linux-initialization-6.md +++ b/Initialization/linux-initialization-6.md @@ -128,7 +128,7 @@ int __init acpi_mps_check(void) } ``` -It checks the built-in `MPS` or [MultiProcessor Specification](http://en.wikipedia.org/wiki/MultiProcessor_Specification) table. If `CONFIG_X86_LOCAL_APIC` is set and `CONFIG_x86_MPPAARSE` is not set, `acpi_mps_check` prints warning message if the one of the command line options: `acpi=off`, `acpi=noirq` or `pci=noacpi` passed to the kernel. If `acpi_mps_check` returns `1` it means that we disable local [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) and clear `X86_FEATURE_APIC` bit in the of the current CPU with the `setup_clear_cpu_cap` macro. (more about CPU mask you can read in the [CPU masks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html)). +It checks the built-in `MPS` or [MultiProcessor Specification](http://en.wikipedia.org/wiki/MultiProcessor_Specification) table. If `CONFIG_X86_LOCAL_APIC` is set and `CONFIG_x86_MPPAARSE` is not set, `acpi_mps_check` prints warning message if the one of the command line options: `acpi=off`, `acpi=noirq` or `pci=noacpi` passed to the kernel. If `acpi_mps_check` returns `1` it means that we disable local [APIC](http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) and clear `X86_FEATURE_APIC` bit in the of the current CPU with the `setup_clear_cpu_cap` macro. (more about CPU mask you can read in the [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html)). Early PCI dump -------------------------------------------------------------------------------- diff --git a/Initialization/linux-initialization-7.md b/Initialization/linux-initialization-7.md index 1fd8d9c..7a00188 100644 --- a/Initialization/linux-initialization-7.md +++ b/Initialization/linux-initialization-7.md @@ -4,7 +4,7 @@ Kernel initialization. Part 7. The End of the architecture-specific initialization, almost... ================================================================================ -This is the seventh part of the Linux Kernel initialization process which covers insides of the `setup_arch` function from the [arch/x86/kernel/setup.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/setup.c#L861). As you can know from the previous [parts](http://0xax.gitbooks.io/linux-insides/content/Initialization/index.html), the `setup_arch` function does some architecture-specific (in our case it is [x86_64](http://en.wikipedia.org/wiki/X86-64)) initialization stuff like reserving memory for kernel code/data/bss, early scanning of the [Desktop Management Interface](http://en.wikipedia.org/wiki/Desktop_Management_Interface), early dump of the [PCI](http://en.wikipedia.org/wiki/PCI) device and many many more. If you have read the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/%20linux-initialization-6.html), you can remember that we've finished it at the `setup_real_mode` function. In the next step, as we set limit of the [memblock](http://xinqiu.gitbooks.io/linux-insides-cn/content/MM/linux-mm-1.html) to the all mapped pages, we can see the call of the `setup_log_buf` function from the [kernel/printk/printk.c](https://github.com/torvalds/linux/blob/master/kernel/printk/printk.c). +This is the seventh part of the Linux Kernel initialization process which covers insides of the `setup_arch` function from the [arch/x86/kernel/setup.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/setup.c#L861). As you can know from the previous [parts](http://0xax.gitbooks.io/linux-insides/content/Initialization/index.html), the `setup_arch` function does some architecture-specific (in our case it is [x86_64](http://en.wikipedia.org/wiki/X86-64)) initialization stuff like reserving memory for kernel code/data/bss, early scanning of the [Desktop Management Interface](http://en.wikipedia.org/wiki/Desktop_Management_Interface), early dump of the [PCI](http://en.wikipedia.org/wiki/PCI) device and many many more. If you have read the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-6.html), you can remember that we've finished it at the `setup_real_mode` function. In the next step, as we set limit of the [memblock](http://xinqiu.gitbooks.io/linux-insides-cn/content/MM/linux-mm-1.html) to the all mapped pages, we can see the call of the `setup_log_buf` function from the [kernel/printk/printk.c](https://github.com/torvalds/linux/blob/master/kernel/printk/printk.c). The `setup_log_buf` function setups kernel cyclic buffer and its length depends on the `CONFIG_LOG_BUF_SHIFT` configuration option. As we can read from the documentation of the `CONFIG_LOG_BUF_SHIFT` it can be between `12` and `21`. In the insides, buffer defined as array of chars: @@ -98,7 +98,7 @@ We can see `io_delay` command line parameter setup with the `early_param` macro early_param("io_delay", io_delay_param); ``` -More about `early_param` you can read in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/%20linux-initialization-6.html). So the `io_delay_param` function which setups `io_delay_override` variable will be called in the [do_early_param](https://github.com/torvalds/linux/blob/master/init/main.c#L413) function. `io_delay_param` function gets the argument of the `io_delay` kernel command line parameter and sets `io_delay_type` depends on it: +More about `early_param` you can read in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-6.html). So the `io_delay_param` function which setups `io_delay_override` variable will be called in the [do_early_param](https://github.com/torvalds/linux/blob/master/init/main.c#L413) function. `io_delay_param` function gets the argument of the `io_delay` kernel command line parameter and sets `io_delay_type` depends on it: ```C static int __init io_delay_param(char *s) @@ -301,14 +301,14 @@ Now `vsyscall` area is in the `fix-mapped` area. That's all about `map_vsyscall` Getting the SMP configuration -------------------------------------------------------------------------------- -You may remember how we made a search of the [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing) configuration in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/%20linux-initialization-6.html). Now we need to get the `SMP` configuration if we found it. For this we check `smp_found_config` variable which we set in the `smp_scan_config` function (read about it the previous part) and call the `get_smp_config` function: +You may remember how we made a search of the [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing) configuration in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-6.html). Now we need to get the `SMP` configuration if we found it. For this we check `smp_found_config` variable which we set in the `smp_scan_config` function (read about it the previous part) and call the `get_smp_config` function: ```C if (smp_found_config) get_smp_config(); ``` -The `get_smp_config` expands to the `x86_init.mpparse.default_get_smp_config` function which is defined in the [arch/x86/kernel/mpparse.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/mpparse.c). This function defines a pointer to the multiprocessor floating pointer structure - `mpf_intel` (you can read about it in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/%20linux-initialization-6.html)) and does some checks: +The `get_smp_config` expands to the `x86_init.mpparse.default_get_smp_config` function which is defined in the [arch/x86/kernel/mpparse.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/mpparse.c). This function defines a pointer to the multiprocessor floating pointer structure - `mpf_intel` (you can read about it in the previous [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-6.html)) and does some checks: ```C struct mpf_intel *mpf = mpf_found; @@ -320,7 +320,7 @@ if (acpi_lapic && early) return; ``` -Here we can see that multiprocessor configuration was found in the `smp_scan_config` function or just return from the function if not. The next check is `acpi_lapic` and `early`. And as we did this checks, we start to read the `SMP` configuration. As we finished reading it, the next step is - `prefill_possible_map` function which makes preliminary filling of the possible CPU's `cpumask` (more about it you can read in the [Introduction to the cpumasks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html)). +Here we can see that multiprocessor configuration was found in the `smp_scan_config` function or just return from the function if not. The next check is `acpi_lapic` and `early`. And as we did this checks, we start to read the `SMP` configuration. As we finished reading it, the next step is - `prefill_possible_map` function which makes preliminary filling of the possible CPU's `cpumask` (more about it you can read in the [Introduction to the cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html)). The rest of the setup_arch -------------------------------------------------------------------------------- @@ -334,7 +334,7 @@ That's all, and now we can back to the `start_kernel` from the `setup_arch`. Back to the main.c ================================================================================ -As I wrote above, we have finished with the `setup_arch` function and now we can back to the `start_kernel` function from the [init/main.c](https://github.com/torvalds/linux/blob/master/init/main.c). As you may remember or saw yourself, `start_kernel` function as big as the `setup_arch`. So the couple of the next part will be dedicated to learning of this function. So, let's continue with it. After the `setup_arch` we can see the call of the `mm_init_cpumask` function. This function sets the [cpumask](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) pointer to the memory descriptor `cpumask`. We can look on its implementation: +As I wrote above, we have finished with the `setup_arch` function and now we can back to the `start_kernel` function from the [init/main.c](https://github.com/torvalds/linux/blob/master/init/main.c). As you may remember or saw yourself, `start_kernel` function as big as the `setup_arch`. So the couple of the next part will be dedicated to learning of this function. So, let's continue with it. After the `setup_arch` we can see the call of the `mm_init_cpumask` function. This function sets the [cpumask](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) pointer to the memory descriptor `cpumask`. We can look on its implementation: ```C static inline void mm_init_cpumask(struct mm_struct *mm) @@ -379,7 +379,7 @@ static void __init setup_command_line(char *command_line) Here we can see that we allocate space for the three buffers which will contain kernel command line for the different purposes (read above). And as we allocated space, we store `boot_command_line` in the `saved_command_line` and `command_line` (kernel command line from the `setup_arch`) to the `static_command_line`. -The next function after the `setup_command_line` is the `setup_nr_cpu_ids`. This function setting `nr_cpu_ids` (number of CPUs) according to the last bit in the `cpu_possible_mask` (more about it you can read in the chapter describes [cpumasks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) concept). Let's look on its implementation: +The next function after the `setup_command_line` is the `setup_nr_cpu_ids`. This function setting `nr_cpu_ids` (number of CPUs) according to the last bit in the `cpu_possible_mask` (more about it you can read in the chapter describes [cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) concept). Let's look on its implementation: ```C void __init setup_nr_cpu_ids(void) diff --git a/Initialization/linux-initialization-8.md b/Initialization/linux-initialization-8.md index 34bdce7..2785e82 100644 --- a/Initialization/linux-initialization-8.md +++ b/Initialization/linux-initialization-8.md @@ -4,7 +4,7 @@ Kernel initialization. Part 8. Scheduler initialization ================================================================================ -This is the eighth [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/index.html) of the Linux kernel initialization process and we stopped on the `setup_nr_cpu_ids` function in the [previous](https://github.com/MintCN/linux-insides-zh/blob/master/Initialization/linux-initialization-7.md) part. The main point of the current part is [scheduler](http://en.wikipedia.org/wiki/Scheduling_%28computing%29) initialization. But before we will start to learn initialization process of the scheduler, we need to do some stuff. The next step in the [init/main.c](https://github.com/torvalds/linux/blob/master/init/main.c) is the `setup_per_cpu_areas` function. This function setups areas for the `percpu` variables, more about it you can read in the special part about the [Per-CPU variables](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html). After `percpu` areas is up and running, the next step is the `smp_prepare_boot_cpu` function. This function does some preparations for the [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing): +This is the eighth [part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/index.html) of the Linux kernel initialization process and we stopped on the `setup_nr_cpu_ids` function in the [previous](https://github.com/MintCN/linux-insides-zh/blob/master/Initialization/linux-initialization-7.md) part. The main point of the current part is [scheduler](http://en.wikipedia.org/wiki/Scheduling_%28computing%29) initialization. But before we will start to learn initialization process of the scheduler, we need to do some stuff. The next step in the [init/main.c](https://github.com/torvalds/linux/blob/master/init/main.c) is the `setup_per_cpu_areas` function. This function setups areas for the `percpu` variables, more about it you can read in the special part about the [Per-CPU variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html). After `percpu` areas is up and running, the next step is the `smp_prepare_boot_cpu` function. This function does some preparations for the [SMP](http://en.wikipedia.org/wiki/Symmetric_multiprocessing): ```C static inline void smp_prepare_boot_cpu(void) @@ -86,7 +86,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { ... ``` -more about `percpu` variables you can read in the [Per-CPU variables](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) part. As we got address and size of the `GDT` descriptor we reload `GDT` with the `load_gdt` which just execute `lgdt` instruct and load `percpu_segment` with the following function: +more about `percpu` variables you can read in the [Per-CPU variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) part. As we got address and size of the `GDT` descriptor we reload `GDT` with the `load_gdt` which just execute `lgdt` instruct and load `percpu_segment` with the following function: ```C void load_percpu_segment(int cpu) { @@ -205,7 +205,7 @@ pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18, ``` The number of elements of the `pid_hash` depends on the `RAM` configuration, but it can be between `2^4` and `2^12`. The `pidhash_init` computes the size -and allocates the required storage (which is `hlist` in our case - the same as [doubly linked list](http://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/dlist.html), but contains one pointer instead on the [struct hlist_head](https://github.com/torvalds/linux/blob/master/include/linux/types.h)]. The `alloc_large_system_hash` function allocates a large system hash table with `memblock_virt_alloc_nopanic` if we pass `HASH_EARLY` flag (as it in our case) or with `__vmalloc` if we did no pass this flag. +and allocates the required storage (which is `hlist` in our case - the same as [doubly linked list](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-1.html), but contains one pointer instead on the [struct hlist_head](https://github.com/torvalds/linux/blob/master/include/linux/types.h)]. The `alloc_large_system_hash` function allocates a large system hash table with `memblock_virt_alloc_nopanic` if we pass `HASH_EARLY` flag (as it in our case) or with `__vmalloc` if we did no pass this flag. The result we can see in the `dmesg` output: @@ -290,7 +290,7 @@ The root task group is the task group which belongs to every task in system. As DECLARE_PER_CPU(cpumask_var_t, load_balance_mask); ``` -Here `cpumask_var_t` is the `cpumask_t` with one difference: `cpumask_var_t` is allocated only `nr_cpu_ids` bits when the `cpumask_t` always has `NR_CPUS` bits (more about `cpumask` you can read in the [CPU masks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) part). As you can see: +Here `cpumask_var_t` is the `cpumask_t` with one difference: `cpumask_var_t` is allocated only `nr_cpu_ids` bits when the `cpumask_t` always has `NR_CPUS` bits (more about `cpumask` you can read in the [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) part). As you can see: ```C #ifdef CONFIG_CPUMASK_OFFSTACK @@ -461,7 +461,7 @@ If you have any questions or suggestions write me a comment or ping me at [twitt Links -------------------------------------------------------------------------------- -* [CPU masks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) +* [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) * [high-resolution kernel timer](https://www.kernel.org/doc/Documentation/timers/hrtimers.txt) * [spinlock](http://en.wikipedia.org/wiki/Spinlock) * [Run queue](http://en.wikipedia.org/wiki/Run_queue) diff --git a/Initialization/linux-initialization-9.md b/Initialization/linux-initialization-9.md index 16bd824..f312fa5 100644 --- a/Initialization/linux-initialization-9.md +++ b/Initialization/linux-initialization-9.md @@ -38,7 +38,7 @@ In the first implementation of the `preempt_disable` we increment this `__preemp #define preempt_count_add(val) __preempt_count_add(val) ``` -where `preempt_count_add` calls the `raw_cpu_add_4` macro which adds `1` to the given `percpu` variable (`__preempt_count`) in our case (more about `precpu` variables you can read in the part about [Per-CPU variables](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html)). Ok, we increased `__preempt_count` and the next step we can see the call of the `barrier` macro in the both macros. The `barrier` macro inserts an optimization barrier. In the processors with `x86_64` architecture independent memory access operations can be performed in any order. That's why we need the opportunity to point compiler and processor on compliance of order. This mechanism is memory barrier. Let's consider a simple example: +where `preempt_count_add` calls the `raw_cpu_add_4` macro which adds `1` to the given `percpu` variable (`__preempt_count`) in our case (more about `precpu` variables you can read in the part about [Per-CPU variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html)). Ok, we increased `__preempt_count` and the next step we can see the call of the `barrier` macro in the both macros. The `barrier` macro inserts an optimization barrier. In the processors with `x86_64` architecture independent memory access operations can be performed in any order. That's why we need the opportunity to point compiler and processor on compliance of order. This mechanism is memory barrier. Let's consider a simple example: ```C preempt_disable(); @@ -127,7 +127,7 @@ The next step is [RCU](http://en.wikipedia.org/wiki/Read-copy-update) initializa In the first case `rcu_init` will be in the [kernel/rcu/tiny.c](https://github.com/torvalds/linux/blob/master/kernel/rcu/tiny.c) and in the second case it will be defined in the [kernel/rcu/tree.c](https://github.com/torvalds/linux/blob/master/kernel/rcu/tree.c). We will see the implementation of the `tree rcu`, but first of all about the `RCU` in general. -`RCU` or read-copy update is a scalable high-performance synchronization mechanism implemented in the Linux kernel. On the early stage the linux kernel provided support and environment for the concurrently running applications, but all execution was serialized in the kernel using a single global lock. In our days linux kernel has no single global lock, but provides different mechanisms including [lock-free data structures](http://en.wikipedia.org/wiki/Concurrent_data_structure), [percpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) data structures and other. One of these mechanisms is - the `read-copy update`. The `RCU` technique is designed for rarely-modified data structures. The idea of the `RCU` is simple. For example we have a rarely-modified data structure. If somebody wants to change this data structure, we make a copy of this data structure and make all changes in the copy. In the same time all other users of the data structure use old version of it. Next, we need to choose safe moment when original version of the data structure will have no users and update it with the modified copy. +`RCU` or read-copy update is a scalable high-performance synchronization mechanism implemented in the Linux kernel. On the early stage the linux kernel provided support and environment for the concurrently running applications, but all execution was serialized in the kernel using a single global lock. In our days linux kernel has no single global lock, but provides different mechanisms including [lock-free data structures](http://en.wikipedia.org/wiki/Concurrent_data_structure), [percpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) data structures and other. One of these mechanisms is - the `read-copy update`. The `RCU` technique is designed for rarely-modified data structures. The idea of the `RCU` is simple. For example we have a rarely-modified data structure. If somebody wants to change this data structure, we make a copy of this data structure and make all changes in the copy. In the same time all other users of the data structure use old version of it. Next, we need to choose safe moment when original version of the data structure will have no users and update it with the modified copy. Of course this description of the `RCU` is very simplified. To understand some details about `RCU`, first of all we need to learn some terminology. Data readers in the `RCU` executed in the [critical section](http://en.wikipedia.org/wiki/Critical_section). Every time when data reader get to the critical section, it calls the `rcu_read_lock`, and `rcu_read_unlock` on exit from the critical section. If the thread is not in the critical section, it will be in state which called - `quiescent state`. The moment when every thread is in the `quiescent state` called - `grace period`. If a thread wants to remove an element from the data structure, this occurs in two steps. First step is `removal` - atomically removes element from the data structure, but does not release the physical memory. After this thread-writer announces and waits until it is finished. From this moment, the removed element is available to the thread-readers. After the `grace period` finished, the second step of the element removal will be started, it just removes the element from the physical memory. @@ -378,7 +378,7 @@ Ok, we already passed the main theme of this part which is `RCU` initialization, After we initialized `RCU`, the next step which you can see in the [init/main.c](https://github.com/torvalds/linux/blob/master/init/main.c) is the - `trace_init` function. As you can understand from its name, this function initialize [tracing](http://en.wikipedia.org/wiki/Tracing_%28software%29) subsystem. You can read more about linux kernel trace system - [here](http://elinux.org/Kernel_Trace_Systems). -After the `trace_init`, we can see the call of the `radix_tree_init`. If you are familiar with the different data structures, you can understand from the name of this function that it initializes kernel implementation of the [Radix tree](http://en.wikipedia.org/wiki/Radix_tree). This function is defined in the [lib/radix-tree.c](https://github.com/torvalds/linux/blob/master/lib/radix-tree.c) and you can read more about it in the part about [Radix tree](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/radix-tree.html). +After the `trace_init`, we can see the call of the `radix_tree_init`. If you are familiar with the different data structures, you can understand from the name of this function that it initializes kernel implementation of the [Radix tree](http://en.wikipedia.org/wiki/Radix_tree). This function is defined in the [lib/radix-tree.c](https://github.com/torvalds/linux/blob/master/lib/radix-tree.c) and you can read more about it in the part about [Radix tree](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-2.html). In the next step we can see the functions which are related to the `interrupts handling` subsystem, they are: @@ -423,7 +423,7 @@ Links * [integer ID management](https://lwn.net/Articles/103209/) * [Documentation/memory-barriers.txt](https://www.kernel.org/doc/Documentation/memory-barriers.txt) * [Runtime locking correctness validator](https://www.kernel.org/doc/Documentation/locking/lockdep-design.txt) -* [Per-CPU variables](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [Per-CPU variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [Linux kernel memory management](http://0xax.gitbooks.io/linux-insides/content/MM/index.html) * [slab](http://en.wikipedia.org/wiki/Slab_allocation) * [i2c](http://en.wikipedia.org/wiki/I%C2%B2C) diff --git a/Interrupts/linux-interrupts-1.md b/Interrupts/linux-interrupts-1.md index afbdfc0..2e2ed8a 100644 --- a/Interrupts/linux-interrupts-1.md +++ b/Interrupts/linux-interrupts-1.md @@ -306,7 +306,7 @@ union irq_stack_union { 第一个 `irq_stack` 域是一个 16KB 的数组。然后你可以看到 `irq_stack_union` 联合包含了一个结构体,这个结构体有两个域: -* `gs_base` - 总是指向 `irqstack` 联合底部的 `gs` 寄存器。在 `x86_64` 中, per-cpu(更多关于 `per-cpu` 变量的信息可以阅读特定的[章节](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html)) 和 stack canary 共享 `gs` 寄存器。所有的 per-cpu 标志初始值为零,并且 `gs` 指向 per-cpu 区域的开始。你已经知道[段内存模式](http://en.wikipedia.org/wiki/Memory_segmentation)已经废除很长时间了,但是我们可以使用[特殊模块寄存器(Model specific registers)](http://en.wikipedia.org/wiki/Model-specific_register)给这两个段寄存器 - `fs` 和 `gs` 设置基址,并且这些寄存器仍然可以被用作地址寄存器。如果你记得 Linux 内核初始程序的第一[部分](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-1.html),你会记起我们设置了 `gs` 寄存器: +* `gs_base` - 总是指向 `irqstack` 联合底部的 `gs` 寄存器。在 `x86_64` 中, per-cpu(更多关于 `per-cpu` 变量的信息可以阅读特定的[章节](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html)) 和 stack canary 共享 `gs` 寄存器。所有的 per-cpu 标志初始值为零,并且 `gs` 指向 per-cpu 区域的开始。你已经知道[段内存模式](http://en.wikipedia.org/wiki/Memory_segmentation)已经废除很长时间了,但是我们可以使用[特殊模块寄存器(Model specific registers)](http://en.wikipedia.org/wiki/Model-specific_register)给这两个段寄存器 - `fs` 和 `gs` 设置基址,并且这些寄存器仍然可以被用作地址寄存器。如果你记得 Linux 内核初始程序的第一[部分](http://xinqiu.gitbooks.io/linux-insides-cn/content/Initialization/linux-initialization-1.html),你会记起我们设置了 `gs` 寄存器: ```assembly movl $MSR_GS_BASE,%ecx diff --git a/Interrupts/linux-interrupts-10.md b/Interrupts/linux-interrupts-10.md index b629d62..f49bbe3 100644 --- a/Interrupts/linux-interrupts-10.md +++ b/Interrupts/linux-interrupts-10.md @@ -342,7 +342,7 @@ common_interrupt: interrupt do_IRQ ``` -`interrupt` 宏定义在同一个源文件中。它把[通用](https://en.wikipedia.org/wiki/Processor_register)寄存器的值保存在栈中。如果需要,它还会通过 `SWAPGS` 汇编指令在内核中改变用户空间 `gs` 寄存器。它会增加 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 的 `irq_count` 变量,来表明我们处于中断状态,然后调用 `do_IRQ` 函数。该函数定义于 [arch/x86/kernel/irq.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/irq.c) 源文件中,作用是处理我们的设备中断。让我们一起考察这个函数。`do_IRQ` 函数接受一个参数 - `pt_regs` 结构体,它存放着用户空间寄存器的值: +`interrupt` 宏定义在同一个源文件中。它把[通用](https://en.wikipedia.org/wiki/Processor_register)寄存器的值保存在栈中。如果需要,它还会通过 `SWAPGS` 汇编指令在内核中改变用户空间 `gs` 寄存器。它会增加 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 的 `irq_count` 变量,来表明我们处于中断状态,然后调用 `do_IRQ` 函数。该函数定义于 [arch/x86/kernel/irq.c](https://github.com/torvalds/linux/blob/master/arch/x86/kernel/irq.c) 源文件中,作用是处理我们的设备中断。让我们一起考察这个函数。`do_IRQ` 函数接受一个参数 - `pt_regs` 结构体,它存放着用户空间寄存器的值: ```C __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) @@ -409,7 +409,7 @@ return 1; 退出中断 --------------------- -好了,中断处理程序执行完毕,我们必须从中断中返回。在 `do_IRQ` 函数将工作处理完毕后,我们将回到 [arch/x86/entry/entry_64.S](https://github.com/torvalds/linux/blob/master/arch/x86/entry_entry_64.S) 汇编代码的 `ret_from_intr` 标签处。首先,我们通过 `DISABLE_INTERRUPTS` 宏禁止中断,这个宏被扩展成 `cli` 指令,将 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 的 `irq_count` 变量值减 1。记住,当我们处于中断上下文的时候,这个变量的值是 `1`: +好了,中断处理程序执行完毕,我们必须从中断中返回。在 `do_IRQ` 函数将工作处理完毕后,我们将回到 [arch/x86/entry/entry_64.S](https://github.com/torvalds/linux/blob/master/arch/x86/entry_entry_64.S) 汇编代码的 `ret_from_intr` 标签处。首先,我们通过 `DISABLE_INTERRUPTS` 宏禁止中断,这个宏被扩展成 `cli` 指令,将 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 的 `irq_count` 变量值减 1。记住,当我们处于中断上下文的时候,这个变量的值是 `1`: ```assembly DISABLE_INTERRUPTS(CLBR_NONE) @@ -465,7 +465,7 @@ native_irq_return_iret: * [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) * [GNU 汇编器](https://en.wikipedia.org/wiki/GNU_Assembler) * [处理器寄存器](https://en.wikipedia.org/wiki/Processor_register) -* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [pid](https://en.wikipedia.org/wiki/Process_identifier) * [设备树](https://en.wikipedia.org/wiki/Device_tree) * [系统调用](https://en.wikipedia.org/wiki/System_call) diff --git a/Interrupts/linux-interrupts-9.md b/Interrupts/linux-interrupts-9.md index 0dba45f..b476c6b 100644 --- a/Interrupts/linux-interrupts-9.md +++ b/Interrupts/linux-interrupts-9.md @@ -226,7 +226,7 @@ void __init softirq_init(void) } ``` -可以看到在函数开头定义了一个名为 cpu 的 integer 类型变量。接下来他会作为参数传递给宏 `for_each_possible_cpu` 来获得系统中所有的处理器。如果 `possible_cpu` 对你来说是一个新的术语,你可以阅读 [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) 章节来了解更多知识。简单的说,`possible_cpu` 是系统运行期间插入的处理器集合。所有的 `possible processor` 存储在 `cpu_possible_bits` 位图中,你可以在 [kernel/cpu.c](https://github.com/torvalds/linux/blob/master/kernel/cpu.c) 中找到他的定义: +可以看到在函数开头定义了一个名为 cpu 的 integer 类型变量。接下来他会作为参数传递给宏 `for_each_possible_cpu` 来获得系统中所有的处理器。如果 `possible_cpu` 对你来说是一个新的术语,你可以阅读 [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) 章节来了解更多知识。简单的说,`possible_cpu` 是系统运行期间插入的处理器集合。所有的 `possible processor` 存储在 `cpu_possible_bits` 位图中,你可以在 [kernel/cpu.c](https://github.com/torvalds/linux/blob/master/kernel/cpu.c) 中找到他的定义: ```C static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; @@ -520,7 +520,7 @@ insert_work(pwq, work, worklist, work_flags); * [initcall](http://www.compsoc.man.ac.uk/~moz/kernelnewbies/documents/initcall/index.html) * [IF](https://en.wikipedia.org/wiki/Interrupt_flag) * [eflags](https://en.wikipedia.org/wiki/FLAGS_register) -* [CPU masks](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) -* [per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [CPU masks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) +* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [Workqueue](https://github.com/torvalds/linux/blob/master/Documentation/workqueue.txt) * [Previous part](http://xinqiu.gitbooks.io/linux-insides-cn/content/Interrupts/linux-interrupts-8.html) diff --git a/MM/linux-mm-3.md b/MM/linux-mm-3.md index dc1d608..73b01fe 100644 --- a/MM/linux-mm-3.md +++ b/MM/linux-mm-3.md @@ -296,7 +296,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, } ``` -`kmemcheck_active` 函数获取 `kmemcheck_context` [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 结构体,并返回该结构体成员 `balance` 和0的比较结果: +`kmemcheck_active` 函数获取 `kmemcheck_context` [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 结构体,并返回该结构体成员 `balance` 和0的比较结果: ``` bool kmemcheck_active(struct pt_regs *regs) @@ -423,10 +423,10 @@ Links * [kmemcheck documentation](https://www.kernel.org/doc/Documentation/kmemcheck.txt) * [valgrind](https://en.wikipedia.org/wiki/Valgrind) * [page fault](https://en.wikipedia.org/wiki/Page_fault) -* [initcalls](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/initcall.html) +* [initcalls](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-3.html) * [opcode](https://en.wikipedia.org/wiki/Opcode) * [translation lookaside buffer](https://en.wikipedia.org/wiki/Translation_lookaside_buffer) -* [per-cpu variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [flags register](https://en.wikipedia.org/wiki/FLAGS_register) * [tasklet](https://xinqiu.gitbooks.io/linux-insides-cn/content/Interrupts/linux-interrupts-9.html) * [Paging](https://xinqiu.gitbooks.io/linux-insides-cn/content/Theory/linux-theory-1.html) diff --git a/SyncPrim/linux-sync-2.md b/SyncPrim/linux-sync-2.md index b4651d4..e696cf4 100644 --- a/SyncPrim/linux-sync-2.md +++ b/SyncPrim/linux-sync-2.md @@ -100,7 +100,7 @@ int unlock(lock) 这一部分的主旨是 `队列自旋锁`。这个方法能够帮助解决上述的两个问题。`队列自旋锁`允许每个处理器对自旋过程使用他自己的内存地址。通过学习名为 [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf) 锁的这种基于队列自旋锁的实现,能够最好理解基于队列自旋锁的基本原则。在了解`队列自旋锁`的实现之前,我们先尝试理解什么是 `MCS` 锁。 -`MCS`锁的基本理念就在上一段已经写到了,一个线程在本地变量上自旋然后每个系统的处理器自己拥有这些变量的拷贝。换句话说这个概念建立在 Linux 内核中的 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 变量概念之上。 +`MCS`锁的基本理念就在上一段已经写到了,一个线程在本地变量上自旋然后每个系统的处理器自己拥有这些变量的拷贝。换句话说这个概念建立在 Linux 内核中的 [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 变量概念之上。 当第一个线程想要获取锁,线程在`队列`中注册了自身,或者换句话说,因为线程现在是闲置的,线程要加入特殊`队列`并且获取锁。当第二个线程想要在第一个线程释放锁之前获取相同锁,这个线程就会把他自身的所变量的拷贝加入到这个特殊`队列`中。这个例子中第一个线程会包含一个 `next` 字段指向第二个线程。从这一时刻,第二个线程会等待直到第一个线程释放它的锁并且关于这个事件通知给 `next` 线程。第一个线程从`队列`中删除而第二个线程持有该锁。 @@ -473,7 +473,7 @@ smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK)); * [API](https://en.wikipedia.org/wiki/Application_programming_interface) * [Test and Set](https://en.wikipedia.org/wiki/Test-and-set) * [MCS](http://www.cs.rochester.edu/~scott/papers/1991_TOCS_synch.pdf) -* [per-cpu variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu variables](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [atomic instruction](https://en.wikipedia.org/wiki/Linearizability) * [CMPXCHG instruction](http://x86.renejeschke.de/html/file_module_x86_id_41.html) * [LOCK instruction](http://x86.renejeschke.de/html/file_module_x86_id_159.html) diff --git a/SyncPrim/linux-sync-3.md b/SyncPrim/linux-sync-3.md index 7336c7a..55c23f7 100644 --- a/SyncPrim/linux-sync-3.md +++ b/SyncPrim/linux-sync-3.md @@ -76,7 +76,7 @@ struct semaphore { #define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } } ``` - `信号量` 的最后两个域 `count` 和 `wait_list` 是通过现有资源的数量和空 [链表](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/dlist.html)来初始化。 + `信号量` 的最后两个域 `count` 和 `wait_list` 是通过现有资源的数量和空 [链表](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-1.html)来初始化。 第二种初始化 `信号量` 的方式是将 `信号量` 和现有资源数目传送给 `sema_init` 函数。 这个函数是在 [include/linux/semaphore.h](https://github.com/torvalds/linux/blob/master/include/linux/semaphore.h) 头文件中定义的。 ```C @@ -180,7 +180,7 @@ struct semaphore_waiter waiter; #define current get_current() ``` -`get_current` 函数返回 `current_task` [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 变量的值。 +`get_current` 函数返回 `current_task` [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 变量的值。 ```C @@ -339,10 +339,10 @@ static noinline void __sched __up(struct semaphore *sem) * [preemption](https://en.wikipedia.org/wiki/Preemption_%28computing%29) * [deadlocks](https://en.wikipedia.org/wiki/Deadlock) * [scheduler](https://en.wikipedia.org/wiki/Scheduling_%28computing%29) -* [Doubly linked list in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/dlist.html) +* [Doubly linked list in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/DataStructures/linux-datastructures-1.html) * [jiffies](https://xinqiu.gitbooks.io/linux-insides-cn/content/Timers/linux-timers-1.html) * [interrupts](https://en.wikipedia.org/wiki/Interrupt) -* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [bitmask](https://en.wikipedia.org/wiki/Mask_%28computing%29) * [SIGKILL](https://en.wikipedia.org/wiki/Unix_signal#SIGKILL) * [errno](https://en.wikipedia.org/wiki/Errno.h) diff --git a/SysCall/linux-syscall-2.md b/SysCall/linux-syscall-2.md index e56ff62..54c3bc3 100644 --- a/SysCall/linux-syscall-2.md +++ b/SysCall/linux-syscall-2.md @@ -210,7 +210,7 @@ SWAPGS_UNSAFE_STACK #define SWAPGS_UNSAFE_STACK swapgs ``` -宏将交换 GS 段选择符及 `MSR_KERNEL_GS_BASE ` 特殊模式寄存器中的值。换句话说,将其入内核堆栈 。之后使老的堆栈指针指向 `rsp_scratch` [per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) 变量设置堆栈指针指向当前处理器的栈顶: +宏将交换 GS 段选择符及 `MSR_KERNEL_GS_BASE ` 特殊模式寄存器中的值。换句话说,将其入内核堆栈 。之后使老的堆栈指针指向 `rsp_scratch` [per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) 变量设置堆栈指针指向当前处理器的栈顶: ```assembly movq %rsp, PER_CPU_VAR(rsp_scratch) @@ -401,7 +401,7 @@ Links * [instruction pointer](https://en.wikipedia.org/wiki/Program_counter) * [flags register](https://en.wikipedia.org/wiki/FLAGS_register) * [Global Descriptor Table](https://en.wikipedia.org/wiki/Global_Descriptor_Table) -* [per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu](http://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [general purpose registers](https://en.wikipedia.org/wiki/Processor_register) * [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) * [x86_64 C ABI](http://www.x86-64.org/documentation/abi.pdf) diff --git a/SysCall/linux-syscall-3.md b/SysCall/linux-syscall-3.md index 63d7b52..3429f1a 100644 --- a/SysCall/linux-syscall-3.md +++ b/SysCall/linux-syscall-3.md @@ -252,7 +252,7 @@ Here we can see that [uname](https://en.wikipedia.org/wiki/Uname) util was linke * `libc.so.6`; * `ld-linux-x86-64.so.2`. -The first provides `vDSO` functionality, the second is `C` [standard library](https://en.wikipedia.org/wiki/C_standard_library) and the third is the program interpreter (more about this you can read in the part that describes [linkers](http://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linkers.html)). So, the `vDSO` solves limitations of the `vsyscall`. Implementation of the `vDSO` is similar to `vsyscall`. +The first provides `vDSO` functionality, the second is `C` [standard library](https://en.wikipedia.org/wiki/C_standard_library) and the third is the program interpreter (more about this you can read in the part that describes [linkers](https://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linux-misc-3.html)). So, the `vDSO` solves limitations of the `vsyscall`. Implementation of the `vDSO` is similar to `vsyscall`. Initialization of the `vDSO` occurs in the `init_vdso` function that defined in the [arch/x86/entry/vdso/vma.c](https://github.com/torvalds/linux/blob/master/arch/x86/entry/vdso/vma.c) source code file. This function starts from the initialization of the `vDSO` images for 32-bits and 64-bits depends on the `CONFIG_X86_X32_ABI` kernel configuration option: @@ -399,5 +399,5 @@ Links * [instruction pointer](https://en.wikipedia.org/wiki/Program_counter) * [stack pointer](https://en.wikipedia.org/wiki/Stack_register) * [uname](https://en.wikipedia.org/wiki/Uname) -* [Linkers](http://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linkers.html) +* [Linkers](https://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linux-misc-3.html) * [Previous part](http://xinqiu.gitbooks.io/linux-insides-cn/content/SysCall/linux-syscall-2.html) diff --git a/SysCall/linux-syscall-4.md b/SysCall/linux-syscall-4.md index aa57414..9627660 100644 --- a/SysCall/linux-syscall-4.md +++ b/SysCall/linux-syscall-4.md @@ -334,7 +334,7 @@ if (!elf_phdata) goto out; ``` -that describes [segments](https://en.wikipedia.org/wiki/Memory_segmentation). Read the `program interpreter` and libraries that linked with the our executable binary file from disk and load it to memory. The `program interpreter` specified in the `.interp` section of the executable file and as you can read in the part that describes [Linkers](http://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linkers.html) it is - `/lib64/ld-linux-x86-64.so.2` for the `x86_64`. It setups the stack and map `elf` binary into the correct location in memory. It maps the [bss](https://en.wikipedia.org/wiki/.bss) and the [brk](http://man7.org/linux/man-pages/man2/sbrk.2.html) sections and does many many other different things to prepare executable file to execute. +that describes [segments](https://en.wikipedia.org/wiki/Memory_segmentation). Read the `program interpreter` and libraries that linked with the our executable binary file from disk and load it to memory. The `program interpreter` specified in the `.interp` section of the executable file and as you can read in the part that describes [Linkers](https://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linux-misc-3.html) it is - `/lib64/ld-linux-x86-64.so.2` for the `x86_64`. It setups the stack and map `elf` binary into the correct location in memory. It maps the [bss](https://en.wikipedia.org/wiki/.bss) and the [brk](http://man7.org/linux/man-pages/man2/sbrk.2.html) sections and does many many other different things to prepare executable file to execute. In the end of the execution of the `load_elf_binary` we call the `start_thread` function and pass three arguments to it: @@ -424,7 +424,7 @@ Links * [Alpha](https://en.wikipedia.org/wiki/DEC_Alpha) * [FDPIC](http://elinux.org/UClinux_Shared_Library#FDPIC_ELF) * [segments](https://en.wikipedia.org/wiki/Memory_segmentation) -* [Linkers](http://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linkers.html) +* [Linkers](https://xinqiu.gitbooks.io/linux-insides-cn/content/Misc/linux-misc-3.html) * [Processor register](https://en.wikipedia.org/wiki/Processor_register) * [instruction pointer](https://en.wikipedia.org/wiki/Program_counter) * [Previous part](http://xinqiu.gitbooks.io/linux-insides-cn/content/SysCall/linux-syscall-3.html) diff --git a/Timers/linux-timers-3.md b/Timers/linux-timers-3.md index 5fe4bda..5162911 100644 --- a/Timers/linux-timers-3.md +++ b/Timers/linux-timers-3.md @@ -102,7 +102,7 @@ void __init tick_broadcast_init(void) } ``` -As we can see, the `tick_broadcast_init` function allocates different [cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) with the help of the `zalloc_cpumask_var` function. The `zalloc_cpumask_var` function defined in the [lib/cpumask.c](https://github.com/torvalds/linux/blob/master/lib/cpumask.c) source code file and expands to the call of the following function: +As we can see, the `tick_broadcast_init` function allocates different [cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) with the help of the `zalloc_cpumask_var` function. The `zalloc_cpumask_var` function defined in the [lib/cpumask.c](https://github.com/torvalds/linux/blob/master/lib/cpumask.c) source code file and expands to the call of the following function: ```C bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) @@ -407,7 +407,7 @@ for_each_cpu(cpu, tick_nohz_full_mask) context_tracking_cpu_set(cpu); ``` -The `context_tracking_cpu_set` function defined in the [kernel/context_tracking.c](https://github.com/torvalds/linux/blob/master/kernel/context_tracking.c) source code file and main point of this function is to set the `context_tracking.active` [percpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) variable to `true`. When the `active` field will be set to `true` for the certain processor, all [context switches](https://en.wikipedia.org/wiki/Context_switch) will be ignored by the Linux kernel context tracking subsystem for this processor. +The `context_tracking_cpu_set` function defined in the [kernel/context_tracking.c](https://github.com/torvalds/linux/blob/master/kernel/context_tracking.c) source code file and main point of this function is to set the `context_tracking.active` [percpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) variable to `true`. When the `active` field will be set to `true` for the certain processor, all [context switches](https://en.wikipedia.org/wiki/Context_switch) will be ignored by the Linux kernel context tracking subsystem for this processor. That's all. This is the end of the `tick_nohz_init` function. After this `NO_HZ` related data structures will be initialzed. We didn't see API of the `NO_HZ` mode, but will see it soon. @@ -433,12 +433,12 @@ Links * [CPU idle](https://en.wikipedia.org/wiki/Idle_%28CPU%29) * [power management](https://en.wikipedia.org/wiki/Power_management) * [NO_HZ documentation](https://github.com/torvalds/linux/blob/master/Documentation/timers/NO_HZ.txt) -* [cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) +* [cpumasks](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) * [high precision event timer](https://en.wikipedia.org/wiki/High_Precision_Event_Timer) * [irq](https://en.wikipedia.org/wiki/Interrupt_request_%28PC_architecture%29) * [IPI](https://en.wikipedia.org/wiki/Inter-processor_interrupt) * [CPUID](https://en.wikipedia.org/wiki/CPUID) * [APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) -* [percpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [percpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [context switches](https://en.wikipedia.org/wiki/Context_switch) * [Previous part](https://xinqiu.gitbooks.io/linux-insides-cn/content/Timers/linux-timers-2.html) diff --git a/Timers/linux-timers-4.md b/Timers/linux-timers-4.md index b9a9291..1f48288 100644 --- a/Timers/linux-timers-4.md +++ b/Timers/linux-timers-4.md @@ -75,7 +75,7 @@ static void __init init_timer_cpus(void) } ``` -If you do not know or do not remember what is it a `possible` cpu, you can read the special [part](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) of this book which describes `cpumask` concept in the Linux kernel. In short words, a `possible` processor is a processor which can be plugged in anytime during the life of the system. +If you do not know or do not remember what is it a `possible` cpu, you can read the special [part](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) of this book which describes `cpumask` concept in the Linux kernel. In short words, a `possible` processor is a processor which can be plugged in anytime during the life of the system. The `init_timer_cpu` function does main work for us, namely it executes initialization of the `tvec_base` structure for each processor. This structure defined in the [kernel/time/timer.c](https://github.com/torvalds/linux/blob/master/kernel/time/timer.c) source code file and stores data related to a `dynamic` timer for a certain processor. Let's look on the definition of this structure: @@ -136,7 +136,7 @@ static void __init init_timer_cpu(int cpu) } ``` -The `tvec_bases` represents [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) variable which represents main data structure for a dynamic timer for a given processor. This `per-cpu` variable defined in the same source code file: +The `tvec_bases` represents [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) variable which represents main data structure for a dynamic timer for a given processor. This `per-cpu` variable defined in the same source code file: ```C static DEFINE_PER_CPU(struct tvec_base, tvec_bases); @@ -418,10 +418,10 @@ Links * [IP](https://en.wikipedia.org/wiki/Internet_Protocol) * [netfilter](https://en.wikipedia.org/wiki/Netfilter) * [network](https://en.wikipedia.org/wiki/Computer_network) -* [cpumask](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) +* [cpumask](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) * [interrupt](https://en.wikipedia.org/wiki/Interrupt) * [jiffies](https://xinqiu.gitbooks.io/linux-insides-cn/content/Timers/linux-timers-1.html) -* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/per-cpu.html) +* [per-cpu](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-1.html) * [spinlock](https://en.wikipedia.org/wiki/Spinlock) * [procfs](https://en.wikipedia.org/wiki/Procfs) * [previous part](https://xinqiu.gitbooks.io/linux-insides-cn/content/Timers/linux-timers-3.html) diff --git a/Timers/linux-timers-5.md b/Timers/linux-timers-5.md index dba31e8..533fb7c 100644 --- a/Timers/linux-timers-5.md +++ b/Timers/linux-timers-5.md @@ -130,7 +130,7 @@ The next two fields `shift` and `mult` are familiar to us. They will be used to #define cpumask_of(cpu) (get_cpu_mask(cpu)) ``` -Where the `get_cpu_mask` returns the cpumask containing just a given `cpu` number. More about `cpumasks` concept you may read in the [CPU masks in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) part. In the last four lines of code we set callbacks for the clock event device suspend/resume, device shutdown and update of the clock event device state. +Where the `get_cpu_mask` returns the cpumask containing just a given `cpu` number. More about `cpumasks` concept you may read in the [CPU masks in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) part. In the last four lines of code we set callbacks for the clock event device suspend/resume, device shutdown and update of the clock event device state. After we finished with the initialization of the `at91sam926x` periodic timer, we can register it by the call of the following functions: @@ -409,7 +409,7 @@ Links * [local APIC](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller) * [C3 state](https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Device_states) * [Periodic Interval Timer (PIT) for at91sam926x](http://www.atmel.com/Images/doc6062.pdf) -* [CPU masks in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/cpumask.html) +* [CPU masks in the Linux kernel](https://xinqiu.gitbooks.io/linux-insides-cn/content/Concepts/linux-cpu-2.html) * [deadlock](https://en.wikipedia.org/wiki/Deadlock) * [CPU hotplug](https://www.kernel.org/doc/Documentation/cpu-hotplug.txt) * [previous part](https://xinqiu.gitbooks.io/linux-insides-cn/content/Timers/linux-timers-3.html)