# 第十二部分：系统调用与内核源码阅读

## CMake 与系统调用

Cmake

System call 系统调用

C函数库为每个系统调用提供了一个同名函数。

调用函数的时候，如果有对应的系统调用，自动调用该系统调用。

从程序员使用角度看，系统调用与 C 库函数使用方法相似。从执行角度看，系统调用运行在核心态，库函数运行在用户态。printf 与 printk

系统调用引起状态切换，花销并不小。

调用返回时引起系统重新调度

整个系统调用的过程：

执行用户程序(如:fork)

根据 glibc 中的函数实现，取得系统调用号并执行 int $\$ 0 x80$ 产生中断。进行地址空间的转换和堆栈的切换，执行 SAVE_ALL。（进入内核模式）中断处理，根据系统调用表调用内核函数。

执行内核函数。

执行 RESTORE_ALL 并返回用户模式。

引发系统进程调度。

四个重要的宏

SAVE_ALL

保存用户模式的寄存器和堆栈信息,然后切换到内核模式

RESTORE_ALL

与 SAVE_ALL 相反

SWITH_KERNELSPACE

实现地址空间的转换

SWITH_USERSPACE

arch/i386/kernel/entry.S

系统调用表

arch/i386/kernel/entry.S

Fork（）

exec() #Load and overwrite current image with new one

with fork() together, it can execute a shell command.

Example

execl ( “/bin/ls”, “ls”, “-l”, (char *)0 );

Terminate current process

exit(0)

exit(n)

exit(-1)

int open(const char *pathname, int flags,[mode_t mode])

pathname－－字符指针，指向所要打开文件的路径名。可以是相对路径也可以是绝对路径。

flags－－是打开文件的方式，在头文件fcntl.h中定义几个常量：

O_RDONLY－－只读

O_WRONLY－－只写

O_TRUNC－－截断为 0 长度

O_CREAT－－如果文件不存在，创建新文件

O_EXCL－－互斥

O_RDWR－－读写

O_APPEND－－追加

mode－－可选参数，只有当 flags 参数为 O_CREAT 时该参数才有效，表示文件的默认权限。一般情况下不使用这个参数。

返回值就是文件描述符，一个整数；打开出错时，返回-1。

例：

fd $=$ open("file", O_RDWR | O_CREAT | O_TRUNC, 0644);

ssize_t read(int filedes, void *buffer, size_t n);

filedes－－文件描述符

buffer－－指向数组或结构的指针，读入的数据将填充到这里，一般就是数组本身的名字

n－－期望读入数据的字节数

返回值是读入数据的字节数，非负的整数；读入出错时，返回-1。

ssize_t write(int filedes, const void *buffer, size_t n);

filedes－－文件描述符

buffer－－指向数据缓冲区的指针

n－－要写入的数据的字节数

off_t lseek(int filedes, off_t offset, int start_flag);

filedes－－一个已经打开的文件描述符

offset－－表示新位置相对于起始位置的字节数

start_flag－－整型，决定起始位置

SEEK_SET offset 是从文件的起始位置算起，通常为 0

SEEK_CUR offset是相对文件读写的当前位置而言的，通常为1

SEEK_END offset 是相对文件尾而言，通常为 2

## 内核源码学习工具

在线查看Linux内核代码

http://https://elixir.bootlin.com/linux/latest/source

http://lxr.linux.no

下载某版本内核源码文件

Kernel.org

解压缩到本地文件系统目录

使用工具阅读源码

Source insight

## Vim + ctags

在 vim 中安装插件 ctags 后，就可以在终端方便地使用 vim 命令查看 Linux 源码内容了。

安装 ctags 插件

方法一：ctags 源码安装

方法二：安装工具 apt-get、yum、pacman 等

修改vim配置文件

编辑 vim 配置文件 sudo vim /etc/vim/vimrc

添加如下内容：

set tags=/home/stu01/src/linux-4.12/tags

set autochdir

利用 ctags 文件查看 Linux 源码信息

### 源码安装 ctags

·下载源码

```txt
http://prddownloads.sourceforge.net/ctags-5.8.tar.gz  
http://ctags.sourceforge.net/ 
```

·编译安装

./configure

make

sudo make install

![](bbbfc857a4773f70bf9965b2b61aff339af564b9c87abf928cd695b61ab720c7.jpg)

·生成索引

```txt
- sudo ctags -R * //在Linux源码目录中执行
```

·-R表示递归创建*表示所有文件  
·命令执行后生成一个tags目录

### 利用 ctags 文件查看 Linux 源码信息

· vim -t effective_prio

static int effective_prio(struct task_struct \*p)   
{ p->normal_prio $=$ normal_prio(p); /\* If we are RT tasks or we were boosted to RT priority, \* keep the priority unchanged. otherwise, update priority \* to the normal priority: /\* if (!rt_prio(p->prio)) return p->normal_prio; return p->prio;

-t之后是要显示的tag，包括变量名、数据结构名和函数名等。

Ctrl+]

当光标处于要查看的变量名、数据结构名、函数名处时，Ctrl+]可以跳转到相应的定义处

Ctrl+T

返回前一次的位置处

ta

在命令模式下使用，可以显示变量等的定义

:ta normal_prio // 显示 normal_prio()的源码

其他用法

man ctags

Vim 中 help ctags
