理解进程创建、可执行文件的加载和进程执行进程切换,重点理解分析fork、execve和进程切换

原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
学号 088


实验要求

  • 阅读理解task_struct数据结构http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h#1235;
  • 分析fork函数对应的内核处理过程do_fork,理解创建一个新进程如何创建和修改task_struct数据结构;
  • 使用gdb跟踪分析一个fork系统调用内核处理函数do_fork ,验证您对Linux系统创建一个新进程的理解,特别关注新进程是从哪里开始执行的?为什么从那里能顺利执行下去?即执行起点与内核堆栈如何保证一致。
  • 理解编译链接的过程和ELF可执行文件格式;
  • 编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接;
  • 使用gdb跟踪分析一个execve系统调用内核处理函数do_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解;
  • 特别关注新的可执行程序是从哪里开始执行的?为什么execve系统调用返回后新的可执行程序能顺利执行?对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
  • 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确;
  • 使用gdb跟踪分析一个schedule()函数 ,验证您对Linux系统进程调度与进程切换过程的理解;
  • 特别关注并仔细分析switch_to中的汇编代码,理解进程上下文的切换机制,以及与中断上下文切换的关系;

实验环境

  • Ubuntu18
  • 内核:Linux Kernel 5.0.1

实验内容

1. 阅读理解task_struct数据结构

task_struct代码:task_struct
由于task_struct代码过多,下面对其部分代码分析:

  • 支持对称多处理器方式(SMP)时的数据成员
    int processor;  //进程正在使用的CPU
    int last_processor;  //进程最后一次使用的CPU
    int lock_depth;  //上下文切换时系统内核锁的深度 
    unsigned short used_math;  //是否使用MPU
    char comm[16];  //进程正在运行的可执行文件的文件名
    int errno;  //最后一次出错的系统调用错误号,0表示无错误。系统调用返回时,全程量也拥有该错误。
    long debugreg[8];  //保存INTEL CPU调试寄存器的值,在ptrace系统调用中使用。
    
  • 信号处理
    unsigned long signal; //进程接收到的信号。每位表示一种信号,共32种。置位有效。
    unsigned long blocked;  //进程所能接受信号的位掩码。置位表示屏蔽,复位表示不屏蔽。
    struct signal_struct *sig;  //因为signal和blocked都是32位的变量,Linux最多只能接受32种信号。对每种信号,各进程可以由PCB的sig属性选择使用自定义的处理 函数,或是系统的缺省处理函数。
    
  • 进程队列指针
    struct task_struct *next_task,*prev_task; //所有进程(以PCB的形式)组成一个双向链表。next_task和  就是链表的前后指针。链表的头和尾都是init_task(即0号进程)。
    struct task_struct *next_run,*prev_run;  //由正在运行或是可以运行的,其进程状态均为TASK_RUNNING的进程所组成的一个双向循环链表,即run_queue就绪队列。该链表的前后向指针用next_run和prev_run,链表的头和尾都是init_task(即0号进程)。
    struct task_struct *p_opptr,*p_pptr;和struct task_struct *p_cptr,*p_ysptr,*p_osptr;  //以上分别是指向原始父进程(original parent)、父进程(parent)、子进程(youngest child)及新老兄弟进程(younger sibling,older sibling)的指针
    
  • 进程标识
    unsigned short uid,gid;  //uid和gid是运行进程的用户标识和用户组标识
    int groups[NGROUPS];  //与多数现代UNIX操作系统一样,Linux允许进程同时拥有一组用户组号。在进程访问文件时,这些组号可用于合法性检查
    unsigned short euid,egid; //euid 和egid又称为有效的uid和gid。出于系统安全的权限的考虑,运行程序时要检查euid和egid的合法性。通常,uid等于euid,gid等于 egid。有时候,系统会赋予一般用户暂时拥有root的uid和gid(作为用户进程的euid和egid),以便于进行运作
    unsigned short fsuid,fsgid;  //fsuid 和fsgid称为文件系统的uid和gid,用于文件系统操作时的合法性检查,是Linux独特的标识类型。它们一般分别和euid和egid一致,但在 NFS文件系统中NFS服务器需要作为一个特殊的进程访问文件,这时只修改客户进程的fsuid和fsgid
    

操作系统管理进程必须对每个进程所做的事情进行清楚的描述,使用数据结构来代表处理不同的实体,这个数据结构就是通常所说的进程描述符或进程控制块(PCB)。在linux操作系统下这就是task_struct结构 ,所属的头文件#include <sched.h>每个进程都会被分配一个task_struct结构,它包含了这个进程的所有信息,在任何时候操作系统都能够跟踪这个结构的信息.

2.分析fork函数对应的内核处理过程do_fork

  • 代码如下
long do_fork(unsigned long clone_flags,
          unsigned long stack_start,
          unsigned long stack_size,
          int __user *parent_tidptr
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值