张晓攀+原创作品转载请注明出处+《Linux内核分析》MOOC课程https://mooc.study.163.com/course/1000029000
实验六——分析Linux内核创建一个新进程的过程
一、实验过程
1.将github上的menu项目克隆下来
git clone https://github.com/mengning/menu.git
2.进入内核系统
更新test.c :mv test_fork.c test.c
运行脚本,自动编译和自动生成根文件系统,同时启动,输入fork命令:make rootfs
3.gdb调试
-
关闭QEMU窗口,在命令行中输入命令:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
-
另开一个shell窗口,依次输入指令进入调试:
gdb
,file linux-3.18.6/vmlinux
,target remote:1234
-
设置断点
二、实验总结
在Linux内核中,创建一个新进程主要依赖于fork()
、clone()
等系统调用,最终由内核中的do_fork()
函数完成。简要流程如下:
1. 用户态的系统调用
- 用户进程调用
fork()
、vfork()
或clone()
等接口。 - 这些接口会触发进入内核态,通过系统调用号定位到相应的内核函数,例如
sys_clone
。
2. 进入do_fork()
do_fork()
是创建新进程的核心内核函数,它接收用户态的参数并进行处理。- 主要完成以下任务:
- 检查参数:确保
clone_flags
等参数有效。 - 分配
task_struct
:为新进程分配内存,并初始化其任务描述符task_struct
,其中包含进程的关键信息,如PID、优先级、调度策略等。 - 复制父进程资源:
- 虚拟内存:使用
copy_mm()
复制父进程的内存描述符。 - 文件描述符:通过
copy_files()
复制文件描述符表。 - 信号处理:通过
copy_sighand()
复制信号处理机制。
- 虚拟内存:使用
- 检查参数:确保
- 根据
clone_flags
决定是否与父进程共享某些资源(如地址空间、文件描述符表等)。
3. 分配PID
- 内核通过
alloc_pid()
函数为新进程分配一个唯一的进程标识符(PID)。
4. 设置调度信息
- 调用
wake_up_new_task()
,将新进程加入可运行队列,并设置其初始状态为TASK_RUNNING
或TASK_INTERRUPTIBLE
。
5. 返回到用户态
- 新进程的
task_struct
初始化完毕后,父子进程分别返回到用户态。 - 对于父进程,
fork()
返回新进程的PID;对于子进程,fork()
返回0。
6. 执行新任务
- 如果新进程需要执行不同的程序,可以调用
execve()
加载新程序。 - 如果是
vfork()
或某些clone()
调用,父进程可能会等待子进程执行完成后才继续运行。