Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

学号后三位: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:1234
 b sys_clone
 b dup_task_struct
 b do_fork
 b copy_process
 b copy_thread
 b 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只拷贝下一个要执行的代码到新的进程。

posted @ 2019-03-26 10:22  matrinMorning  阅读(313)  评论(0编辑  收藏  举报