39
社区成员




目录
task_struct具有非常庞大的数据结构,400多行代码。包括对进程链表的管理,控制台,文件系统描述,文件描述符,内存管理描述,信号描述等,其结构示意图如下图所示:
当使用fork()创建一个新的进程时,进程的状态是TASK_RUNNING(就绪态),新进程被调度运行时,就切换到TASK_RUNNING(运行态)。对于一个正在运行的进程,调用用户库函数exit()会陷入内核执行该内核函数do_exit(),也就是终止进程,就会进入TASK_ZOMBIE状态(僵尸进程)。一个正在运行的进程在等待特定的事件和资源时会进入阻塞态。阻塞态也分两种:TASK_INTERRUPTIBLE和TASK_UNINTERRUPTLBLE。TASK_INTERRUPTIBLE可以被信号和wake_up唤醒的,当信号到来时,进程会被设置为TASK_RUNNING(就绪态),而TASK_UNINTERRUPTLBLE只能被wake-up()唤醒。
cd LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
mv test_fork.c test.c
make rootfs
测试folk
通过增加-s -S启动参数打开调试模式:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
打开gdb进行调试:
gdb
file linux-3.18.6/vmlinux
target remote:1234
设置断点:
b sys_clone
b do_fork
b dup_task_struct
b copy_process
b copy_thread
b ret_from_fork
执行fork命令,停在了断点SyS_clone处,单步执行,定在了断点do_fork处;之后就是依次设置的断点
创建一个新进程在内核中的执行过程大致如下:
使用系统调用Sys_clone(或fork,vfork)系统调用创建一个新进程。这些系统调用会通过调用do_fork函数来实现进程的创建。Linux通过复制父进程的进程控制块(PCB)中的task_struct结构来创建一个新进程,并为新进程分配一个新的内核堆栈。需要修改复制过来的进程数据,例如进程ID(pid)、进程链表等。这一步通过执行copy_process和copy_thread函数来完成。设置新进程的内核栈顶,即p->thread.sp = (unsigned long) childregs。这个值表示当调度到子进程时,使用的内核栈的顶部位置。设置子进程的第一条指令地址,即p->thread.ip = (unsigned long) ret_from_fork。这个地址表示当调度到子进程时,执行的第一条指令。