leevis.com
leevis.com copied to clipboard
Blog
### 概述 微软早期的操作系统是DOS,磁盘操作系统。可见磁盘管理在操作系统中的地位。 而linux中一切兼文件,抽象出的虚拟文件系统更强大。而我一只想搞清楚一切兼文件的真正的意义,一切兼文件是如何实现的,一切兼文件是如何抽象出来的。 ### 代码分析 在main.c文件中,初始化后切换到用户态后,`fork`出第一个进程先调用了`init`函数,该函数调用了`setup`函数初始化文件文件系统挂载根目录。 `setup`函数是用户态函数,真正的实现是内核kernel/blk_drv/genhd.c文件中的`sys_setup`函数,在该函数中调用了fs/super.c文件中的`mount_root`函数挂载根目录。 ```c // 支持的文件系统 static struct file_system_type file_systems[] = { {minix_read_super,"minix"}, {ext_read_super,"ext"}, {msdos_read_super,"msdos"}, {proc_read_super,"proc"}, {NULL,NULL} }; void mount_root(void) { int i; struct file_system_type...
### 概述 在linux系统上执行一个程序通常是先调用`fork`函数复制父进程空间,然后调用`execve`函数执行磁盘上的可执行文件。 例如,在linux-0.11启动时的一段代码: ```c if (!(pid=fork())) { close(0); if (open("/etc/rc",O_RDONLY,0)) _exit(1); execve("/bin/sh",argv_rc,envp_rc); _exit(2); } ``` 在unistd.h文件中execve函数声明如下,带了3个参数。 ```c int execve(const char * filename, char ** argv, char ** envp); ```...
### 概述 linux中一切兼文件,本文分析的就是存在块设备,准确的说是磁盘中的文件打开过程,也就是`open`函数的实现。 ### 代码分析 上一篇中就说明了文件系统结构。磁盘块2是超级块,存放了保存了i 节点个数、逻辑块个数、i节点位图所占用的数据块个数、逻辑块位图所占用的数据块个数、第一个数据逻辑块等等。具体参考fs.h中定义的`d_super_block`结构体。 磁盘上一个文件或目录,对应一个i节点和1个或多个数据块,而目录的数据块保存的就是目录下文件和对应的i节点号,参考fs.h定义的`dir_entry` 结构体。 在任务1中调用的初始化`init`函数,调用了 `setup((void *) &drive_info);` 函数,该函数调用了 `mount_root`函数挂载根文件系统。 挂载要做的一个工作就是把磁盘超级块读到内存中 super_block[NR_SUPER] 数组中。 初始化工作完成后,我们从`open`函数跟踪一次文件打开,因为`open`是用户态的系统调用,因此对应内核函数是`sys_open`。 先看下进程打开一个文件对应的结构体 fs.h ```c struct file { unsigned short f_mode; // 文件操作模式...
### 概述 磁盘设备速度和cpu存在着巨大差异,为了提升性能在内存开辟了一块空间作为cpu和磁盘块设备的桥梁,称为磁盘缓冲区。 ### 代码分析 从代码的角度分析一次带缓冲的磁盘操作。涉及到的linux-0.11代码文件有:fs.h、 buffer.c、 blk.h、 hd.c、 ll_rw_blk.c 要操作硬盘需要先了解一点硬盘逻辑结构或者说是文件系统结构。 文件系统由6部分组成,引导块|超级块|i节点位图|逻辑块位图|i 节点|数据区逻辑块 引导块:计算机加电BIOS自动会读入的代码和数据。 超级块:文件系统信息,i 节点数、逻辑块数、i 节点位图所占块、逻辑块位图所在块等 i节点位图:标志i节点是否使用。 逻辑块位图:标志逻辑块位图是否使用。 i 节点:磁盘上文件或目录索引节点。 逻辑块:存放文件或目录数据。 用户上层看到的是目录和文件,实际上读取目录文件是需要经过一系列转化定位到逻辑块的。 转换和定位的过程后面再起一篇来说。先看读写逻辑块`bread`函数。 buffer.c ```c struct buffer_head * bread(int...
### 概述 内核代码申请某个资源而被其他任务占用时,就会把自己设置为不能被打断的睡眠状态(TASK_UNINTERRUPTIBLE),直到占有该资源的任务主动释放,释放后需要唤醒因为等待该资源而睡眠的任务。 而资源少任务又多,可能存在多个任务等待资源而睡眠,因此就需要一个等待队列保存这些任务。 ### 代码分析 我们用高速缓冲区 buffer.c 中的代码举例。 高速缓冲区是在内存中开辟了一块内存,作为块设备也就是磁盘 和 内核程序的一个桥梁,也就是说 内核读磁盘一定要经过高速缓冲,而高速缓冲作为一个缓冲一定比磁盘小,所以就有可能存在所有缓冲块都被占用而运行的任务分不到的情况。此时,就需要调用内核函数`sleep_on`把自己设置为不可中断的睡眠状态让出cpu,让其他任务执行。 buffer.c 文件 ```c // 定义了一个全局静态的buffer等待队列头指针,注意只是一个头指针,指向的是任务结构体。 // 全局变量本来就是在代码段,所以static修饰的主要作用就是本文件可见。 static struct task_struct * buffer_wait = NULL; // 获取一个缓冲块 #define...
### 概览 作为http服务需要优化的系统参数。 ### 优化 + 文件句柄 ``` # vim /etc/security/limits.conf * soft nofile 655350 * hard nofile 655350 ``` + 最大文件数 ``` echo 2861022 > /proc/sys/fs/file-max ``` + TCP参数调优...
### 安装bochs 1. 安装bochs的图形界面: `brew install sdl`. 2. 从 https://sourceforge.net/projects/bochs/files/bochs/ 地址选择一个版本的源码下载。 3. 运行configure生成makefile,并安装。如果编译过成有错误,需要修复一下。 ``` ./configure --enable-ne2000 \ --enable-all-optimizations \ --enable-cpu-level=6 \ --enable-x86-64 \ --enable-vmx=2 \ --enable-pci \ --enable-usb \ --enable-usb-ohci...
### 概述 `fork`系统调用产生一个子进程,返回2次。父进程返回子进程的进程ID,子进程则返回0. 出错则返回-1. 例如:nginx调用fork创建worker进程。 ```c switch (pid) { case -1: return NGX_INVALID_PID; case 0: proc(cycle, data); // worker进程执行函数 break; default: // 父进程 break; } ... ``` ### fork内核代码分析 ```c...
### 简介 有一些场景需要用到c内嵌汇编。 例如,操控一些硬件,nginx在读取cpu信息就是用的内嵌汇编。 再例如,为了更好的性能表现。下面例子计算字符串长度。 语法: ``` __asm__( "汇编语句" :输出寄存器 :输入寄存器 :会被修改的寄存器 ) ``` ### 代码例子 ```c #include int slen(const char *s) { register int __res __asm__("cx"); __asm__("cld; repne; scasb\n\t"...
### 前言 最近,又再重复着看nginx的代码。越看越激动,设计的如此精妙。代码写的也非常的好。 nginx是个非常强大的web服务器、反向代理服务器。他的强大之处离不开他的配置文件。那么配置文件是如何解析的呢?又是通过什么数据结构存放的呢? ### 解析流程 首先,c函数从`main`开始执行,在`main`函数调用了`ngx_init_cycle`函数。在该函数中初始化了一个`conf_ctx`指针数组用来存放各个模块的配置文件结构体指针,随后又调用了所有`NGX_CORE_MODULE`模块的`create_conf`创建核心模块配置结构体。最后通过调用两个方法来解析命令行配置和文件配置指令。这两个函数分别是:`ngx_conf_param`和 `ngx_conf_parse`。前面是解析命令行配置参数,后面是解析文件配置参数。前面的函数最终还是调用了后面的,那我们直接看后面的函数,如果传入配置文件结构体指针不为空,那么打开配置文件读取配置文件指令。最后调用`ngx_conf_handler`解析配置指令,该方法才是解析配置文件最核心的方法,会根据配置指令遍历所有模块找到能解析该指令的方法,找到后调用对应模块的set方法。 ### 解析细节说明 上述从整体流程介绍了一下解析配置文件的过程。本节通过具体的函数说明一下。 ./core/nginx.c:main ``` c ...... //根据编译生成的模块数组初始化每个模块的序号index。同时把模块的个数赋值给ngx_max_module ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; }...