第一章 Linux内核简介
- Unix特点:
(1) Unix很简洁,仅仅提供几个几百个系统调用并且有一个非常明确的设计目的
(2) 在Unix中,所有的东西都被当作文件对待,通过一套相同的系统调用接口来进行:open(),read(),write(),lseek(),close()
(3) Unix的内核和相关的系统工具软件是用C语言编写而成
(4) Unix的进程创建非常迅速
(5) Unix系统具备清晰的层次化结构
- 操作系统和内核简介
(一) 内核被称作是管理者或者是操作系统的核心
(二) 在系统中运行的应用程序通过系统调用来与内核通信
(三) 处理器在任何指定时间点上的活动范围可以概括为下列三者之一:
(1) 运行于用户空间,执行用户进程
(2) 运行于内核空间,处于进程上下文,代表某个特定的进程执行
(3) 运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断
- Linux内核和传统UNIX内核特点的比较
(1) Linux支持动态加载内核模块
(2) Linux支持对称多处理(SMP)机制
(3) Linux内核可以抢占
(4) Linux内核并不区分线程和其他的一般进程
- Linux内核编程与用户空间内应用程序开发的差异
(1) Linux内核编成时不能访问C库
(2) Linux内核编程时必须使用GNU C
(3) Linux内核编程时缺乏像用户空间那样的内存保护机制
(4) Linux内核编程时浮点数很难使用
(5) 内核只有一个很小的定长堆栈
(6) 由于内核支持异步中断、抢占式和SMP,因此必须时刻注意同步和并发
(7) 要考虑可移植性的重要性
第二章 从内核出发
- 获取内核源码
(1) 使用Git
Git是分布式的
使用Git来获取最新提交到Linus版本树的一个副本:
下载后,更新分支到Linus的最新分支:
(2) 安装内核源代码
如果压缩形势是bzip2,则运行:
如果压缩形势是GNU的zip,则运行:
(3) 使用补丁
- 内核源码树
内核源码树由许多目录组成,而大多数目录又包含更多的子目录
- linux系统中允许同时存在的进程的最大数目为32767,这是因为PID的最大值默认设置为32767(short int短整型的最大值)。如果需要更多进程,系统管理员可以通过修改/proc/sys/kernel/pid_max来提高上限
- 内核把进程存放在叫做任务队列(task list)的双向循环链表中。链表中的每一项都是类型为task_struct,称为进程描述符的结构,该结构在32位机器上大约有1.7K字节。2.6内核通过slab分配器动态生成task_struct
- 进程描述符中的state域描述了进程当前的状态,该域的值必为下列五种状态之一
(1) TASK_RUNNING(运行) — 进程是可执行的;它或者正在执行,或者在运行队列中等待执行
(2) TASK_INTERRUPTIBLE(可中断) — 进程正在睡眠(也就是说它被阻塞),等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行。处于此状态的进程也会因为收到信号而被提前唤醒并投入运行
(3) TASK_UNINTERRUPTIBLE(不可中断) — 除了不会因为接收到信号而被唤醒从而投入运行,这个状态与可中断状态相同。这个状态通常在进程必须在等待时不受干扰或等待事件很快发生时出现
(4) TASK_ZOMBIE(僵死) — 该进程已经结束了,但是其父进程还没有调用wait4()系统调用。为了父进程能够获知它的消息,子进程的进程描述符仍然被保留着
(5) TASK_STOP PED(停止) — 进程停止执行。通常这种状态发生在接收到SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态
- 系统调用和异常处理程序是对内核明确定义的接口。进程只有通过这些接口才能陷入内核执行。Linux中所有的进程都是PID为1的init进程的后代。
- fork()通过拷贝当前进程创建一个子进程。Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。
- vfork()系统调用和fork()的功能相同,除了不拷贝父进程的页表项。子进程作为父进程的一个单独的线程在它的地址空间里运行,父进程被阻塞,直到子进程退出或执行exec()。子进程不能向地址空间写入。但由于其设计并不优良所以最好让它逐渐淡出。
- Linux通过clone()系统调用实现fork()。这个调用通过一系列参数标志来指明父、子进程需要共享的资源。如一个普通的fork()的实现是clone(SIGCHLD,0); vfork()是clone(CLONE_VFORK | CLONE_VM | SIGCHLD,0)