mirror of
https://github.com/MintCN/linux-insides-zh.git
synced 2026-04-25 19:20:28 +08:00
@@ -3,13 +3,15 @@ Linux内核中的数据结构
|
||||
|
||||
基数树
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
As you already know linux kernel provides many different libraries and functions which implement different data structures and algorithms. In this part we will consider one of these data structures - [Radix tree](http://en.wikipedia.org/wiki/Radix_tree). There are two files which are related to `radix tree` implementation and API in the linux kernel:
|
||||
正如你所知道的 Linux 内核通过许多不同库以及函数提供各种数据结构以及算法实现。
|
||||
这个部分我们将介绍其中一个数据结构 [Radix tree](http://en.wikipedia.org/wiki/Radix_tree)。Linux 内核中有两个文件与 `radix tree` 的实现和API相关:
|
||||
|
||||
* [include/linux/radix-tree.h](https://github.com/torvalds/linux/blob/master/include/linux/radix-tree.h)
|
||||
* [lib/radix-tree.c](https://github.com/torvalds/linux/blob/master/lib/radix-tree.c)
|
||||
|
||||
Lets talk about what a `radix tree` is. Radix tree is a `compressed trie` where a [trie](http://en.wikipedia.org/wiki/Trie) is a data structure which implements an interface of an associative array and allows to store values as `key-value`. The keys are usually strings, but any data type can be used. A trie is different from an `n-tree` because of its nodes. Nodes of a trie do not store keys; instead, a node of a trie stores single character labels. The key which is related to a given node is derived by traversing from the root of the tree to this node. For example:
|
||||
首先说明一下什么是 `radix tree` 。Radix tree 是一种 `压缩 trie`,其中 [trie](http://en.wikipedia.org/wiki/Trie) 是一种通过保存关联数组(associative array)来提供 `关键字-值(key-value)` 存储与查找的数据结构。通常关键字是字符串,不过也可以是其他数据类型。
|
||||
|
||||
trie 结构的节点与 `n-tree` 不同,其节点中并不存储关键字,取而代之的是存储单个字符标签。关键字查找时,通过从树的根开始遍历关键字相关的所有字符标签节点,直至到达最终的叶子节点。下面是个例子:
|
||||
|
||||
|
||||
```
|
||||
@@ -41,9 +43,9 @@ Lets talk about what a `radix tree` is. Radix tree is a `compressed trie` where
|
||||
+-----------+
|
||||
```
|
||||
|
||||
So in this example, we can see the `trie` with keys, `go` and `cat`. A compressed trie or `radix tree` differs from a `trie` in that all intermediates nodes which have only one child are removed.
|
||||
这个例子中,我们可以看到 `trie` 所存储的关键字信息 `go` 与 `cat`,压缩 trie 或 `radix tree` 与 `trie` 所不同的是,所有只存在单个孩子的中间节点将被压缩。
|
||||
|
||||
Radix tree in linux kernel is the data structure which maps values to the integer key. It is represented by the following structures from the file [include/linux/radix-tree.h](https://github.com/torvalds/linux/blob/master/include/linux/radix-tree.h):
|
||||
Linux 内核中的 Radix 树将值映射为整型关键字,Radix 的数据结构定义在 [include/linux/radix-tree.h](https://github.com/torvalds/linux/blob/master/include/linux/radix-tree.h) 文件中 :
|
||||
|
||||
```C
|
||||
struct radix_tree_root {
|
||||
@@ -53,17 +55,18 @@ struct radix_tree_root {
|
||||
};
|
||||
```
|
||||
|
||||
This structure presents the root of a radix tree and contains three fields:
|
||||
上面这个是 radix 树的 root 节点的结构体,它包括三个成员:
|
||||
|
||||
* `height` - height of the tree;
|
||||
* `gfp_mask` - tells how memory allocations are to be performed;
|
||||
* `rnode` - pointer to the child node.
|
||||
* `height` - 从叶节点向上计算出的树高度。
|
||||
* `gfp_mask` - 内存分配标识。
|
||||
* `rnode` - 子节点指针。
|
||||
|
||||
The first structure we will discuss is `gfp_mask`:
|
||||
这里我们先讨论的结构体成员是 `gfp_mask` :
|
||||
|
||||
Low-level kernel memory allocation functions take a set of flags as - `gfp_mask`, which describes how that allocation is to be performed. These `GFP_` flags which control the allocation process can have following values: (`GF_NOIO` flag) means sleep and wait for memory, (`__GFP_HIGHMEM` flag) means high memory can be used, (`GFP_ATOMIC` flag) means the allocation process has high-priority and can't sleep etc.
|
||||
Linux 底层的内存申请接口需要提供一类标识(flag) - `gfp_mask` ,用于描述内存申请的行为。这个以 `GFP_` 前缀开头的内存申请控制标识主要包括,`GFP_NOIO` 禁止所有IO操作但允许睡眠等待内存,`__GFP_HIGHMEM` 允许申请内核的高端内存,`GFP_ATOMIC` 高优先级申请内存且操作不允许被睡眠。
|
||||
|
||||
The next structure is `rnode`:
|
||||
|
||||
接下来说的结构体成员是`rnode`:
|
||||
|
||||
```C
|
||||
struct radix_tree_node {
|
||||
@@ -83,29 +86,32 @@ struct radix_tree_node {
|
||||
};
|
||||
```
|
||||
|
||||
This structure contains information about the offset in a parent and height from the bottom, count of the child nodes and fields for accessing and freeing a node. The fields are described below:
|
||||
这个结构体中包括这几个内容,节点与父节点的偏移以及到树底端的高度,子节点的个数,节点的存储数据域,具体描述如下:
|
||||
|
||||
* `path` - offset in parent & height from the bottom;
|
||||
* `count` - count of the child nodes;
|
||||
* `parent` - pointer to the parent node;
|
||||
* `private_data` - used by the user of a tree;
|
||||
* `rcu_head` - used for freeing a node;
|
||||
* `private_list` - used by the user of a tree;
|
||||
* `path` - 从叶节点
|
||||
* `count` - 子节点的个数。
|
||||
* `parent` - 父节点的指针。
|
||||
* `private_data` - 存储数据内容缓冲区。
|
||||
* `rcu_head` - 用于节点释放的RCU链表。
|
||||
* `private_list` - 存储数据。
|
||||
|
||||
The two last fields of the `radix_tree_node` - `tags` and `slots` are important and interesting. Every node can contains a set of slots which are store pointers to the data. Empty slots in the linux kernel radix tree implementation store `NULL`. Radix trees in the linux kernel also supports tags which are associated with the `tags` fields in the `radix_tree_node` structure. Tags allow individual bits to be set on records which are stored in the radix tree.
|
||||
结构体 `radix_tree_node` 的最后两个成员 `tags` 与 `slots` 是非常重要且需要特别注意的。每个 Radix 树节点都可以包括一个指向存储数据指针的 slots 集合,空闲 slots 的指针指向 NULL。 Linux 内核的 Radix 树结构体中还包含用于记录节点存储状态的标签 `tags` 成员,标签通过位设置指示 Radix 树的数据存储状态。
|
||||
|
||||
Now that we know about radix tree structure, it is time to look on its API.
|
||||
至此,我们了解到 radix 树的结构,接下来看一下 radix 树所提供的 API。
|
||||
|
||||
Linux kernel radix tree API
|
||||
|
||||
Linux 内核基数树 API
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
We start from the data structure intialization. There are two ways to initialize new radix tree. The first is to use `RADIX_TREE` macro:
|
||||
我们从数据结构的初始化开始看,radix 树支持两种方式初始化。
|
||||
|
||||
第一个是使用宏 `RADIX_TREE` :
|
||||
|
||||
```C
|
||||
RADIX_TREE(name, gfp_mask);
|
||||
````
|
||||
|
||||
As you can see we pass the `name` parameter, so with the `RADIX_TREE` macro we can define and initialize radix tree with the given name. Implementation of the `RADIX_TREE` is easy:
|
||||
正如你看到,只需要提供 `name` 参数,就能够使用 `RADIX_TREE` 宏完成 radix 的定义以及初始化,`RADIX_TREE` 宏的实现非常简单:
|
||||
|
||||
```C
|
||||
#define RADIX_TREE(name, mask) \
|
||||
@@ -118,16 +124,14 @@ As you can see we pass the `name` parameter, so with the `RADIX_TREE` macro we c
|
||||
}
|
||||
```
|
||||
|
||||
At the beginning of the `RADIX_TREE` macro we define instance of the `radix_tree_root` structure with the given name and call `RADIX_TREE_INIT` macro with the given mask. The `RADIX_TREE_INIT` macro just initializes `radix_tree_root` structure with the default values and the given mask.
|
||||
|
||||
The second way is to define `radix_tree_root` structure by hand and pass it with mask to the `INIT_RADIX_TREE` macro:
|
||||
|
||||
`RADIX_TREE` 宏首先使用 `name` 定义了一个 `radix_tree_root` 实例并用 `RADIX_TREE_INIT` 宏带参数 `mask` 进行初始化。宏 `RADIX_TREE_INIT` 将 `radix_tree_root` 初始化为默认属性并将 gfp_mask 初始化为入参 `mask` 。
|
||||
第二种方式是手工定义 `radix_tree_root` 变量,之后再使用 `mask` 调用 `INIT_RADIX_TREE` 宏对变量进行初始化。
|
||||
```C
|
||||
struct radix_tree_root my_radix_tree;
|
||||
INIT_RADIX_TREE(my_tree, gfp_mask_for_my_radix_tree);
|
||||
```
|
||||
|
||||
where:
|
||||
`INIT_RADIX_TREE` 宏定义:
|
||||
|
||||
```C
|
||||
#define INIT_RADIX_TREE(root, mask) \
|
||||
@@ -137,34 +141,36 @@ do { \
|
||||
(root)->rnode = NULL; \
|
||||
} while (0)
|
||||
```
|
||||
宏 `INIT_RADIX_TREE` 所初始化的属性与 `RADIX_TREE_INIT` 一致
|
||||
|
||||
makes the same initialziation with default values as it does `RADIX_TREE_INIT` macro.
|
||||
|
||||
The next are two functions for the inserting and deleting records to/from a radix tree:
|
||||
接下来是 radix 树的节点插入以及删除,这两个函数:
|
||||
|
||||
* `radix_tree_insert`;
|
||||
* `radix_tree_delete`.
|
||||
|
||||
The first `radix_tree_insert` function takes three parameters:
|
||||
第一个函数 `radix_tree_insert` 需要三个入参:
|
||||
|
||||
* root of a radix tree;
|
||||
* index key;
|
||||
* data to insert;
|
||||
* radix 树 root 节点结构
|
||||
* 索引关键字
|
||||
* 需要插入存储的数据
|
||||
|
||||
The `radix_tree_delete` function takes the same set of parameters as the `radix_tree_insert`, but without data.
|
||||
第二个函数 `radix_tree_delete` 除了不需要存储数据参数外,其他与 `radix_tree_insert` 一致。
|
||||
|
||||
The search in a radix tree implemented in two ways:
|
||||
radix 树的查找实现有以下几个函数:The search in a radix tree implemented in two ways:
|
||||
|
||||
* `radix_tree_lookup`;
|
||||
* `radix_tree_gang_lookup`;
|
||||
* `radix_tree_lookup_slot`.
|
||||
|
||||
The first `radix_tree_lookup` function takes two parameters:
|
||||
第一个函数 `radix_tree_lookup` 需要两个参数:
|
||||
|
||||
* root of a radix tree;
|
||||
* index key;
|
||||
* radix 树 root 节点结构
|
||||
* 索引关键字
|
||||
|
||||
This function tries to find the given key in the tree and return the record associated with this key. The second `radix_tree_gang_lookup` function have the following signature
|
||||
这个函数通过给定的关键字查找 radix 树,并返关键字所对应的结点。
|
||||
|
||||
第二个函数 `radix_tree_gang_lookup` 具有以下特征:
|
||||
|
||||
```C
|
||||
unsigned int radix_tree_gang_lookup(struct radix_tree_root *root,
|
||||
@@ -173,12 +179,15 @@ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root,
|
||||
unsigned int max_items);
|
||||
```
|
||||
|
||||
and returns number of records, sorted by the keys, starting from the first index. Number of the returned records will be not greater than `max_items` value.
|
||||
函数返回查找到记录的条目数,并根据关键字进行排序,返回的总结点数不超过入参 `max_items` 的大小。
|
||||
|
||||
And the last `radix_tree_lookup_slot` function will return the slot which will contain the data.
|
||||
最后一个函数 `radix_tree_lookup_slot` 返回结点 slot 中所存储的数据。
|
||||
|
||||
Links
|
||||
|
||||
链接
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
* [Radix tree](http://en.wikipedia.org/wiki/Radix_tree)
|
||||
* [Trie](http://en.wikipedia.org/wiki/Trie)
|
||||
|
||||
|
||||
|
||||
71
README.md
71
README.md
@@ -1,4 +1,4 @@
|
||||
linux-insides
|
||||
Linux Insides
|
||||
===============
|
||||
|
||||
一系列关于Linux内核和其内在机理的帖子。
|
||||
@@ -7,19 +7,62 @@ linux-insides
|
||||
|
||||
**问题/建议**: 通过在twitter上[@0xAX](https://twitter.com/0xAX),直接添加[issue](https://github.com/0xAX/linux-internals/issues/new)或者直接给我发[邮件](mailto:anotherworldofworld@gmail.com),请自由地向我提出任何问题或者建议。
|
||||
|
||||
LICENSE
|
||||
-------------
|
||||
|
||||
##翻译进度
|
||||
|
||||
| 章节|译者|翻译进度|
|
||||
| ------------- |:-------------:| -----:|
|
||||
|Booting||正在进行|
|
||||
|├1.1|[@xinqiu](https://github.com/xinqiu)|正在进行|
|
||||
|├1.2||未开始|
|
||||
|├1.3||未开始|
|
||||
|├1.4||未开始|
|
||||
|└1.5||未开始|
|
||||
|Initialization||未开始|
|
||||
|Interrupts||未开始|
|
||||
|System calls||未开始|
|
||||
|Timers and time management||未开始|
|
||||
|Memory management||未开始|
|
||||
|Concepts||未开始|
|
||||
|DataStructures||正在进行|
|
||||
|├9.1|[@mudongliang](https://github.com/mudongliang)|正在进行|
|
||||
|└9.2|[Alick Guo](https://github.com/a1ickgu0)|正在进行|
|
||||
|Theory||正在进行|
|
||||
|├10.1|[@mudongliang](https://github.com/mudongliang)|正在进行|
|
||||
|└10.2|[@mudongliang](https://github.com/mudongliang)|已完成|
|
||||
|Misc||正在进行|
|
||||
|├12.1|[@oska874](https://github.com/oska874)|已完成|
|
||||
|├12.2||未开始|
|
||||
|└12.3||未开始|
|
||||
|
||||
##翻译认领规则
|
||||
|
||||
为了避免多个译者同时翻译相同章节的情况出现, 请按照以下规则认领自己要翻译的章节:
|
||||
|
||||
* 开一个 issue ,告诉大家你想翻译哪一章或者哪一节,并且确保 issue 页面里面没有其他人在翻译相同的章节。
|
||||
* 开始翻译你认领的章节。
|
||||
* 完成翻译之后,关闭 issue 。
|
||||
|
||||
翻译前建议看 `TRANSLATION_NOTES.md` 翻译约定,有任何问题或建议也请开 issue 讨论。
|
||||
|
||||
|
||||
|
||||
##作者
|
||||
|
||||
[@0xAX](https://twitter.com/0xAX)
|
||||
|
||||
|
||||
##贡献者
|
||||
|
||||
[@xinqiu](https://github.com/xinqiu)
|
||||
|
||||
[@oska874](https://github.com/oska874)
|
||||
|
||||
[@mudongliang](https://github.com/mudongliang)
|
||||
|
||||
[@Alick Guo](https://github.com/a1ickgu0)
|
||||
|
||||
##LICENSE
|
||||
|
||||
Licensed [BY-NC-SA Creative Commons](http://creativecommons.org/licenses/by-nc-sa/4.0/).
|
||||
|
||||
作者
|
||||
---------------
|
||||
[@0xAX](https://twitter.com/0xAX)
|
||||
|
||||
译者
|
||||
---------------
|
||||
[@xinqiu](http://xinqiu.me)
|
||||
|
||||
[@oska874](ezio_zhang@outlook.com)
|
||||
|
||||
[@mudongliang](https://github.com/mudongliang)
|
||||
|
||||
49
TRANSLATION_NOTES.md
Normal file
49
TRANSLATION_NOTES.md
Normal file
@@ -0,0 +1,49 @@
|
||||
#翻译约定
|
||||
|
||||
## 基本要求
|
||||
|
||||
* 准确表述原文的意思;
|
||||
* 中文应该意思清晰且符合中文表达习惯;
|
||||
* 原文如果表达不清晰,中文应该意译,并且应根据上下文和注释进行推断并填补相应的信息;
|
||||
* 情况 `3` 不能太多;
|
||||
* 对同样短语的翻译,前后必须一致;
|
||||
* 在没有其它影响的情况下,英文“you”统一翻译为“你”。如果原文中“you”的出现过于频繁,可以在译文中适当减少“你”,或将部分“你”用“我们”替代,但应考虑如下原则:
|
||||
|
||||
* 保证句子主语明确、主谓一致。
|
||||
* “你”与“我们”的表述不必严格统一,优先考虑行文的流畅。
|
||||
* 某些可以根据上下文确定主语的场景,可以省略“你”或“我们”,但不宜滥用。
|
||||
|
||||
* 不要使用机器翻译的成果来提交,也就是说您可以使用 `Google Translate` 来帮助您理解内容,但是不能不经考虑就把其自动翻译的结果放在翻译里;
|
||||
|
||||
## 格式要求
|
||||
|
||||
### 标点的使用
|
||||
|
||||
一般的原则是:除了小括号、省略号和破折号保留不变以外,都应该使用中文(全角)标点符号。英文标点符号后方常常跟随有一个半角空格,请在翻译成中文标点符号时将其去除。另外,标点两侧不应有空格,输出、引用除外。
|
||||
|
||||
### 关于空格
|
||||
|
||||
为了美观,通常建议在中文与英文、中文与阿拉伯数字、英文与阿拉伯数字之间加入一个半角空格。如果英文、数字的前后是标点,则不需再添加空格。例如:
|
||||
|
||||
英文:Installing driver for %1
|
||||
中文:正在安装 %1 的驱动程序
|
||||
|
||||
英文:
|
||||
Parameter start_num specifies the character at which to start the search.
|
||||
The first character is character number 1. If start_num is omitted, it is
|
||||
assumed to be 1.
|
||||
中文:
|
||||
参数 start_num 指定开始搜索的字符位置。第一个字符序号为 1。如果省略 "
|
||||
"start_num,默认它为 1。"
|
||||
|
||||
不过,有时候有例如:“2013年6月5日”的视觉效果就比“2013 年 6 月 5 日”好。
|
||||
|
||||
### 其他
|
||||
|
||||
* 所有的英文人名统一不译,保留原文。
|
||||
* 章节标题只能出现中文字样;如有必要说明术语原文,在正文中第一次出现处注明,不应重复。
|
||||
|
||||
#参见
|
||||
- [Ubuntu 简体中文小组工作指南](http://wiki.ubuntu.org.cn/Ubuntu_%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%E5%B0%8F%E7%BB%84%E5%B7%A5%E4%BD%9C%E6%8C%87%E5%8D%97)
|
||||
- [Markdown基础](https://help.github.com/articles/markdown-basics/)
|
||||
- [Markdown 语法说明 (简体中文版)](http://wowubuntu.com/markdown/index.html)
|
||||
Reference in New Issue
Block a user