2023-2024-1 20232816《Linux内核原理与分析》第七周作业

一、阅读理解 task_struct 数据结构

task_struct 是 Linux 内核中用于表示进程的数据结构。它定义在 <linux/sched.h> 头文件中,包含了进程的各种属性和状态信息。
进程标识符(PID)和进程状态:pid 字段表示进程的唯一标识符,state 字段表示进程的当前状态,如运行、等待、停止等。
进程调度和优先级:prio 字段表示进程的调度优先级,policy 字段表示进程的调度策略。这些字段用于进程调度器确定进程的执行顺序。
进程描述符和资源管理:files 字段表示进程打开的文件描述符表,mm 字段表示进程的内存管理信息,包括虚拟地址空间和页表等。
进程上下文和寄存器状态:context 字段保存进程的上下文信息,包括进程在切换时需要保存和恢复的寄存器状态。
进程间通信:signal 字段表示进程当前接收到的信号,sigaction 字段保存信号处理程序的相关信息。这些字段用于进程间的通信和信号处理。
进程父子关系和进程组:real_parent 字段表示进程的实际父进程,parent 字段表示进程的当前父进程。group_leader 字段表示进程所属的进程组的领导进程。
进程计时器和时间戳:start_time 字段表示进程的启动时间,utime 和 stime 字段表示进程的用户态和内核态运行时间。
调度统计信息:se 字段保存进程的 CFS(Completely Fair Scheduler)调度器相关的统计信息,如虚拟运行时间、优先级等。
进程间关系和线程组:group_leader 字段用于组织线程组,多个进程共享相同的 group_leader 字段表示它们属于同一线程组。
进程挂起和等待队列:state 字段中的状态可以表示进程是否处于挂起状态,wait_channel 字段表示进程当前等待的事件或资源。
1.进程描述符
进程描述符示意图:
在这里插入图片描述
大致结构:

struct task_struct {
    // 进程标识符和状态
    pid_t pid;
    int state;

    // 进程调度和优先级
    int prio;
    int policy;

    // 进程描述符和资源管理
    struct files_struct *files;
    struct mm_struct *mm;

    // 进程上下文和寄存器状态
    struct pt_regs *thread_regs;
    struct switch_stack *thread_info;

    // 进程间通信
    sigset_t signal;
    struct sigaction *sighand;

    // 进程父子关系和进程组
    struct task_struct *real_parent;
    struct task_struct *parent;
    struct task_struct *group_leader;

    // 进程计时器和时间戳
    unsigned long start_time;
    cputime_t utime;
    cputime_t stime;

    // 调度统计信息
    struct sched_entity se;

    // 其他字段
    // ...
};

2.进程状态
在 task_struct 结构体中,进程的状态通常由 state 字段表示。该字段可以采用不同的枚举值来表示进程的不同状态。以下是一些常见的进程状态及其对应的枚举值:

TASK_RUNNING0):进程正在运行或准备运行。
TASK_INTERRUPTIBLE1):进程处于可中断睡眠状态,等待某个事件的发生,例如等待输入/输出完成。
TASK_UNINTERRUPTIBLE2):进程处于不可中断睡眠状态,类似于可中断状态,但不会被信号中断。
TASK_STOPPED4):进程已停止运行,通常由于收到 SIGSTOP 信号或调试器的作用。
TASK_TRACED8):进程正在被跟踪,通常由调试器追踪该进程。
EXIT_ZOMBIE16):进程已终止,但其父进程尚未调用 wait()waitpid() 来回收其资源。
EXIT_DEAD32):进程已终止并回收了其资源。

task_struct中的进程状态转化示意表
当前状态 (state) | 允许的下一个状态 (next state)
------------------------------------------------

TASK_RUNNING       | TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE, TASK_STOPPED, TASK_TRACED, EXIT_ZOMBIE, EXIT_DEAD
TASK_INTERRUPTIBLE | TASK_RUNNING, TASK_UNINTERRUPTIBLE, TASK_STOPPED, TASK_TRACED, EXIT_ZOMBIE
TASK_UNINTERRUPTIBLE | TASK_RUNNING, TASK_STOPPED, TASK_TRACED, EXIT_ZOMBIE
TASK_STOPPED       | TASK_RUNNING, TASK_TRACED
TASK_TRACED        | TASK_RUNNING, TASK_STOPPED
EXIT_ZOMBIE        | EXIT_DEAD
EXIT_DEAD          | (终止状态,无下一个状态)

二、实验过程

1、在MenuOS中添加fork函数,函数如下:

#include <unistd.h> 
int Fork(int argc, char *argv[]) 
{
int pid;
/* fork another process */
pid = fork();                                 
if (pid<0) 
{ 
/* error occurred */
fprintf(stderr,"Fork Failed!");
exit(-1);
} 
else if (pid==0)                              
{
/*   child process  */
printf("This is Child Process!\n");
} 
else 
{   
/*  parent process   */
printf("This is Parent Process!\n");          
/* parent will wait for the child to complete*/
wait(NULL);
printf("Child Complete!\n");
}
}

在这里插入图片描述

2、在main函数中加入如下代码

MenuConfig("fork","Fork a new process",Fork);

在这里插入图片描述
3.进行gdb跟踪调试,在sys_clone、do_fork、dup_task_struct、copy_process、copy_thread、ret_from_fork等处各设置断点,执行过程如下图所示:
在这里插入图片描述
在这里插入图片描述
设置完断点后执行fork,能够发现只输出了一个命令描述,后面没有执行,停在了sys_clone这里,如果继续执行会停在do_fork的位置,之后是copy_process、dup_task_struct,ret_from_fork。
在这里插入图片描述

三、实验总结

通过本次实验学会了进程管理与父子进程之间的调用。fork函数用于创建一个新的进程,新进程是现有进程(父进程)的复制品。父进程和子进程在fork函数调用后的代码处开始分别执行。会将父进程的所有资源(包括代码、数据、打开的文件、堆栈等)复制到子进程中。子进程是父进程的副本,但有自己的进程ID。在调用fork函数后,父进程和子进程的执行顺序是不确定的。操作系统决定它们的执行顺序,可能是交替执行,也可能是先执行父进程或子进程。父进程和子进程有不同的进程ID,可以通过返回值来区分它们。在父进程中,fork函数返回子进程的进程ID,而在子进程中,fork函数返回0。当一个进程终止时,它的子进程可能会成为孤儿进程。操作系统会将孤儿进程的父进程设置为init进程(进程ID为1),init进程会接管孤儿进程的管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值