linux作业六——进程的描述和进程的创建

时间:2023-03-08 21:22:29

进程的描述和进程的创建

一、进程描述符task_struct

  为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。

代码关键点:

  1.Struct list_head task进程链表,双向循环链表链接。

  2.Struct mm_struct *mm,*active_mm进程地址空间,内存管理

  3.每个进程都有自己独立的4G进程地址空间。

  4.Struct thread Struct thread当前任务相关的CPU代码

  5.Struct fs_Struct *fs文件系统数据结构

  6.Struct files_struct *files打开的文件描述符列表

  7.struct signal_stract *signal信号处理

二、进程的创建

  一号进程是所有用户态进程的祖先,二号进程是所有内核线程的祖先。

  fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;

1.fork 系统调用,用户态用于创建一个子进程。(部分代码如下)

  if (pid < 0)   出错处理

  10     {

  11         /* error occurred */

  12         fprintf(stderr,"Fork Failed!");

  13         exit(-1);

  14     }

  15     else if (pid == 0)

  16     {

  17         /* child process */  子进程   pid=0时 if和else都会执行  fork系统调用在父进程和子进程各返回一次

  18         printf("This is Child Process!\n");

  19     }

  20     else

  21     {

  22         /* parent process  */

  23         printf("This is Parent Process!\n");

  24         /* parent will wait for the child to complete*/

  25         wait(NULL);

  26         printf("Child Complete!\n");

  27     }

2.对代码的理解

  函数对else和else if都会执行,也就是说在fork之后变成两个进程,子进程中pid返回值是0,父进程中pid的返回值是子进程的ID,fork系统调用在子进程和父进程中各返回一次。

创建一个进程是通过复制当前进程来实现的。大致分为三个步骤:

  1.复制PCB(copy process)

  2.修改PCB

  3.分配新的内核堆栈(部分数据拷贝父进程以便返回)

  *childregs = *current_pt_regs(); //复制内核堆栈

  childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!

  p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶

  p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

linux作业六——进程的描述和进程的创建

3.子进程从哪里开始执行

  Childregs 调度到子进程的内核堆栈

  Ret_from_fork调度到子进程的第一条指令地址

     ↓

  Syscall_exit

     ↓

  Restore_all正常返回到用户态

三、实验

linux作业六——进程的描述和进程的创建

更新到最新版本后开始进行跟踪调试:

linux作业六——进程的描述和进程的创建

这里注意:执行一个fork,会发现只输出一个fork的命令描述,后面并没有执行,因为它停在了sys_clone这个位置。

20135123 秦兆琪