2.2 内核源码树
arch 特定体系结构的源码 block Crypto API crypto 内核源码文档 drivers 设备驱动程序 firmware fs VFS和各种文件系统 include 内核头文件 init 内核引导和初始化 ipc 进程间通信代码 kernel 像调度程序这样的核心子系统 lib 通用内核函数 Makefile Makefile.common mm 内存管理子系统和VM Module.symvers net 网络子系统 samples scripts 编译内核所用的脚本 security Linux安全模块 sound 语音子系统 System.map tools usr 早期用户空间代码 virt2.3 编译内核
配置内核(不同的选项) make config make menuconfig make xconfig make gconfig 创建默认配置 make defconfig make oldconfig 编译 make 记录编译信息 make >../log.txt 互略编译信息 make >/dev/null 衍生多个编译作业 make -j? 如双核处理器上,每个处理器衍生两个作业 make -j4安装内核
把arch/i386/boot/bzImage拷贝到/boot 依照vmlinuz-version来命名 编辑/boot/grub/grub.conf文件,为新内核建立新的启动项 使用LILO的系统则编辑/etc/lilo.conf,然后运行lilo安装模块
make modules_install2.4 内核开发的特点
1.没有libc库 大部分常用的C库函数在内核中都已经得到了实现 2.GNU C 内联函数 把对时间要求比较高而本身长度又比较短的函数定义成内联函数 static inline void test(unsigned long tail_size) 内联函数必须在使用前就定义好,一般在头文件或者文件头中定义内联函数 内联汇编 分支声明(为了优化) likely() unlikely() if(unlikely(foo){ /*****/ }if (likely(foo)){
/****/ }3.没有内存保护机制
4.不要轻易在内核中使用浮点数 5.内核空间具有容积小而固定的栈 6.同步和并发 7.可移植性三.进程管理
进程是处于执行期的程序以及它所包含的资源的总称 3.1进程描述符及任务结构 内核把进程存放在任务队列中 任务队列是各双向循环链表,链表中的每一项都是类型为task_struct,成为进程描述符的结构 定义在<linux/sched.h>文件中 进程描述符中包含一个具体进程的所有信息 task_struct在32位机器上有1.7k字节 其中包含的数据能完整的描述一个正在执行的程序 (打开的文件,进程的地址空间,挂起的信号,进程的状态还有其他更多信息) 3.1.1分配进程描述符 通过slab分配器分配task_struct结构 3.1.2进程描述符的存放 内核通过一个唯一的进程标识值或PID类标识每个进程 PID最大默认值为32768(short int的最大值) 也可以修改/proc/sys/kernle/pid_max来提高上限 3.1.3进程状态 进程描述符中的state域描述了进程的当前状态,系统中每个进程都必须处于五种状态中的一种 TASK_RUNNING(运行) TASK_INTERRUPTIBLE(可中断) TASK_UNINTERRUPTIBLE(不可中断) TASK_ZOMBIE(僵死) TASK_STOPPED(停止)3.1.4 设置当前进程状态
set_task_state(task,state); /将任务task的状态设置为state/ set_current_state(state) <=> set_stask_state(current,state)3.1.5进程上下文
3.1.6进程家族树 所有的进程都是PID为1的init进程的后台 内核在系统启动的最后阶段启动init进程 该进程读取系统的初始化脚本并执行其他的相关程序进程间的关系存放在进程描述符中
每个tack_struct都包含一个指向其父进程task_struct,叫做parent的指针 获取其父进程的进程描述符: struct task_struct my_parent = ourrent->parent; 访问子进程: struct task_struct task; struct list_head *list;list_for_each(list,$current->children){
task = list_entry(list,sruct task_struct,sibling); /* task 现在指向当前的某个子进程*/ }struct task_struct task; for (task =current;task != $init_task; task= task->parent) / task 现在指向init */
}
五.系统调用
5.1 API.POSIX.C 5.2 系统调用(系统调用号) 5.3 系统调用处理程序 int $0x80(十进制128) system_call() 第128号异常处理程序 系统调用号通过eax寄存器传递给内核 call *sys_call_table(,%eax,4) 系统调用表的表项是以32位类型存放的,所以内核需要将给定的系统调用号乘以4,然后查询 参数传递:ebx,ecx,edx,esi和edi按照顺序存放前五个参数 5.4 系统调用的实现 5.5 系统调用上下文 entry.s(系统调用表)六.中断和中断处理程序
IRQ:中断请求 ISR:中断服务例程6.3 注册中断处理程序
int request_irq(unsigned int irq, irqreturn_t(handler)(int,void ,struct pt_regs ), unsighed long irqflags, const char devname, void *dev_id)参数说明:
irq:要分配的中断号 handler:指针,指向处理这个中断的世纪中断处理程序。 handler函数的原型是特定的,接受三个参数,并有一个类型为irqresutn_t的返回值。 irqflags:可以为0,也可以为下列标志的位掩码 SA_INTERRUPT:表示给定的中断处理程序是一个快速中断处理程序 SA_SAMPLE_RANDOM: SA_SHIRQ: devname:与中断相关的ASCII文本表示法. dev_id:request_irq()成功执行会返回0.