学号后三位:426 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
1.进程的创建
除了0号进程(系统创建的)之外,linux系统中都是由其他进程创建的。创建新进程的进程,即调用fork函数的进程为父进程,新建的进程为子进程。
fork创建进程分为三种情况:
1)对于父进程,fork函数返回新建子进程的pid;
2)对于子进程,fork函数返回 0;
3)如果出错, fork 函数返回 -1。
PID进程的结构体部分:
struct task_struct{
pid_t pid; //进程id
uid_t uid,euid;
gid_t gid,egid;
volatile long state; //进程状态,0 running(运行/就绪);1/2 均等待态,分别响应/不响应异步信号;4 僵尸态,Linux特有,为生命周期已终止,但PCB未释放;8 暂停态,可被恢复
int exit_state; //退出的状态
unsigned int rt_priority; //调度优先级
unsigned int policy; //调度策略
struct list_head tasks;
struct task_struct *real_parent;
struct task_struct *parent;
struct list_head children,sibling;
struct fs_struct *fs; //进程与文件系统管理,进程工作的目录与根目录
struct files_struct *files; //进程对所有打开文件的组织,存储指向文件的句柄们
struct mm_struct *mm; //内存管理组织,存储了进程在用户空间不同的地址空间,可能存的数据,可能代码段
struct signal_struct *signal; //进程间通信机制--信号
struct sighand_struct *sighand; //指向进程
cputime_t utime, stime; //进程在用户态、内核态下所经历的节拍数
struct timespec start_time; //进程创建时间
struct timespec real_start_time; //包括睡眠时间的创建时间
}
2.运行一个案例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h>int main(void) { pid_t pid ;pid = fork();if(pid < 0){ printf("fail to fork\n"); exit(1); }if(pid == 0){printf("this is the child,pid is : %u\n",getpid());exit(0); }if(pid > 0){printf("this is the parent\n");exit(0); } return 0; }
3.gdb分析:
依次执行:
cd menu
gcc linktable.c menu.c test.c -lpthread -o init -m32 -static
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
qemu-system-i386 -kernel '/home/xu/mykernel/linux-5.0.2/arch/x86/boot/bzImage' -initrd /home/xu/mykernel/rootfs.img -S -s -append nokaslr
开启另一终端,启用gdb调试
gdb vmlinux
target remote:1234b sys_cloneb dup_task_structb do_forkb copy_processb copy_threadb ret_from_for
进程的建立经历了:sys_clone->do_fork->copy_process->copy_thread->ret_form_fork
创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。 每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。 fork执行完毕后,出现两个进程,进程1的变量为count=0,fpid!=0(父进程)。进程2的变量为count=0,fpid=0(子进程),这两个进程的变量都是独立的,存在不同的地址中,不是共用的,这点要注意。可以说,我们就是通过fpid来识别和操作父子进程的。 还有人可能疑惑为什么不是从#include处开始复制代码的,这是因为fork是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0;fork只拷贝下一个要执行的代码到新的进程。