From ebf58dca0fb8c8197c19b717003fad5929309b33 Mon Sep 17 00:00:00 2001 From: gatieme Date: Wed, 31 Aug 2016 20:23:57 +0800 Subject: [PATCH] ... --- .../02-memory/05-slaballocator/README.md | 94 ++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/study/kernel/02-memory/05-slaballocator/README.md b/study/kernel/02-memory/05-slaballocator/README.md index d56e75a..295cd53 100644 --- a/study/kernel/02-memory/05-slaballocator/README.md +++ b/study/kernel/02-memory/05-slaballocator/README.md @@ -921,10 +921,100 @@ out_unlock: EXPORT_SYMBOL(kmem_cache_destroy); ``` -##4.7 +##4.7 slab分配器的使用实例 ------- -我们来讲解一个slab分配器使用的鲜活的例子. 这个例子创建了task_struct结构, 取自kernel/fork.c +我们来讲解一个slab分配器使用的鲜活的例子. 这个例子创建了task_struct结构, 取自`kernel/fork.c` + +首先, 内核用一个全局变量存放指向`task_struct`高速缓存的指针`task_struct_cachep`. 定义在[`kernel/fork.c, line 1733`](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L1733) + + +```cpp +#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR +static struct kmem_cache *task_struct_cachep; + +static inline struct task_struct *alloc_task_struct_node(int node) +{ + return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node); +} + +static inline void free_task_struct(struct task_struct *tsk) +{ + kmem_cache_free(task_struct_cachep, tsk); +} +#endif +``` + +在内核的初始化期间, 在定义`kernel/fork.c`的fork_init中会创建高速缓存, 参见[`kernel/fork.c?v=4.7, line 312·](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L312) + +```cpp +void __init fork_init(void) +{ +#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR + +#ifndef ARCH_MIN_TASKALIGN + #define ARCH_MIN_TASKALIGN L1_CACHE_BYTES +#endif + + /* create a slab on which task_structs can be allocated */ + task_struct_cachep = kmem_cache_create("task_struct", + arch_task_struct_size, ARCH_MIN_TASKALIGN, + SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, NULL); +#endif + /* ...... */ +} +``` + +这样就创建了一个名为`task_struct`的高速缓存, 其中存放的就是类型为`struct task_struct`的对象. 该对象创建后存放在slab中偏移量为`ARCH_MIN_TASKALIGN`个字节的地方. `ARCH_MIN_TASKALIGN`的预定值与[体系结构相关](http://lxr.free-electrons.com/ident?i=L1_CACHE_BYTES), 通常将它定义为`L1_CACHE_BYTES`, 即L1高速缓存的字节大小. 没有构造函数或析构函数. 注意不同检查返回值是否为失败标记`NULL`. 因为`SLAB_PANIC`已经被设置了. 如果分配失败, `slab`分配器就调用`panic()`函数. 如果没有提供`SLAB_PANIC`标志, 就必须自己检查返回值. `SLAB_PANIC`标志用在这儿是因为这是系统操作必不可少的高速缓存(没有进程描述符, 机器自然不能正常运行). + +每当进程调用`fork`函数时, 一定会创建一个新的进程描述符. 这是在`dup_task_struct`中通过`alloc_task_struct_node`完成的, 而前者则会被_do_fork函数调用, 参见[kernel/fork.c?v=4.7, line 351](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L351) + +```cpp +static struct task_struct *dup_task_struct(struct task_struct *orig, int node) +{ + struct task_struct *tsk; + /* ...... */ + tsk = alloc_task_struct_node(node); + if (!tsk) + return NULL; + /* ...... */ +} +``` + +同样进程执行完后, 如果没有子进程在等待的话, 它的进程描述符就会被释放, 并返回个`task_structcachep`的`slab`高速缓存. 这是在`free_task_struct`中通过`kmem_cache_free`完成的. + + +`alloc_task_struct_node`和`free_task_struct`函数分别用来分配和释放进程描述符 + + +| 函数 | 功能 | 定义 | 调用流程 | +|:-----:|:-----:|:-----:|:---------:| +| alloc_task_struct_node | 从task_struct_cachep slab高速缓存中分配一个进程描述符 | [kernel/fork.c?v=4.7, line 140](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L140) | [_do_fork](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L1762)
[copy_process](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L1339)
[dup_task_struct](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L355)
[alloc_task_struct_node](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L142) | +| free_task_struct | 释放进程描述符, 并返回给从task_struct_cachep slab高速缓存 | [kernel/fork.c?v=4.7, line 145](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L145) | [free_task](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L240)
[free_task_struct](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L145) + + +这两个函数定义在[kernel/fork.c?v=4.7, line 140](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.7#L140) + + +```cpp +#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR +static struct kmem_cache *task_struct_cachep; + +static inline struct task_struct *alloc_task_struct_node(int node) +{ + return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node); +} + +static inline void free_task_struct(struct task_struct *tsk) +{ + kmem_cache_free(task_struct_cachep, tsk); +} +#endif +``` + +由于进程描述符是内核的核心组成部分, 时刻都要用到, 因此`task_struct_cachep`高速缓存绝不会被撤销掉. 即使真能撤销, 我们也要铜鼓下列函数阻止其被撤销. + +