《Linux内核分析》之分析fork函数对应的系统调用处理过程

实验过程

实验过程

1、在实验楼中shell终端依次执行如下代码:

cd LinuxKernel

rm -rf menu

git clone https://github.com/mengning/menu.git

cd menu

mv test_fork.c test.c

make rootfs

可看到启动后的MenuOS已经包含了fork命令。

2、通过增加-s -S启动参数打开调试模式

①其中在之前代码基础上先通过

 cd ..

返回上一级目录

②再执行如下代码打开调试模式,若无步骤①会提示找不到相关文件

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

3、打开gdb进行远程调试

①相关配置

gdb

file linux-3.18.6/vmlinux

target remote:1234

②设置断点

b sys_clone

b do_fork

b dup_task_struct

b copy_process

b copy_thread

b ret_from_fork

代码及分析

tast_struct

xref: /linux-3.18.6/include/linux/sched.h

struct task_struct {
    volatile long state;        //说明了该进程是否可以执行,还是可中断等信息
    unsigned long flags;        //进程号,在调用fork()时给出
    int sigpending;             //进程上是否有待处理的信号
    mm_segment_t addr_limit;    //进程地址空间,区分内核进程与普通进程在内存存放的位置不同
                                //0-0xBFFFFFFF for user-thead
                                //0-0xFFFFFFFF for kernel-thread
    //调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度
    volatile long need_resched;
    int lock_depth;             //锁深度
    long nice;                  //进程的基本时间片
    //进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER
    unsigned long policy;
    struct mm_struct *mm;       //进程内存管理信息
    int processor;
    //若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1 这个值在运行队列被锁时更新
    unsigned long cpus_runnable, cpus_allowed;
    struct list_head run_list;  //指向运行队列的指针
    unsigned long sleep_time;   //进程的睡眠时间
    //用于将系统中所有的进程连成一个双向循环链表, 其根是init_task
    struct task_struct *next_task, *prev_task;
    struct mm_struct *active_mm;
    struct list_head local_pages;       //指向本地页面
    unsigned int allocation_order, nr_local_pages;
    struct linux_binfmt *binfmt;        //进程所运行的可执行文件的格式
    int exit_code, exit_signal;
    int pdeath_signal;                  //父进程终止是向子进程发送的信号
    unsigned long personality;

    int did_exec:1;
    pid_t pid;                          //进程标识符,用来代表一个进程
    pid_t pgrp;                         //进程组标识,表示进程所属的进程组
    pid_t tty_old_pgrp;                 //进程控制终端所在的组标识
    pid_t session;                      //进程的会话标识
    pid_t tgid;
    int leader;                         //表示进程是否为会话主管
    struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;
    struct list_head thread_group;      //线程链表
    struct task_struct *pidhash_next;   //用于将进程链入HASH表
    struct task_struct **pidhash_pprev;
    wait_queue_head_t wait_chldexit;    //供wait4()使用
    struct completion *vfork_done;      //供vfork() 使用
    unsigned long rt_priority;          //实时优先级,用它计算实时进程调度时的weight值
    …… //后面就不看了 我们不关心
};

进程创建分析

fork一个子进程的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(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");
    }
}

 创建一个新进程在内核中的执行过程

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

Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:

复制一个PCB——task_struct

err = arch_dup_task_struct(tsk, orig);

要给新进程分配一个新的内核堆栈

ti = alloc_thread_info_node(tsk, node);
tsk->stack = ti;
setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xiaoheike

Elasticsearch Network Settings

Elasticsearch 缺省情况下是绑定 localhost。对于本地开发服务是足够的(如果你在相同机子上启动多个节点,它还可以形成一个集群),但是你需要配...

17720
来自专栏菩提树下的杨过

ActiveMQ笔记(2):基于ZooKeeper的HA方案

activemq官网给出了3种master/slave的HA方案,详见:http://activemq.apache.org/masterslave.html ...

22060
来自专栏电光石火

使用Maven创建web项目

​使用eclipse插件创建一个web project

24080
来自专栏电光石火

使用Maven创建web项目

使用eclipse插件创建一个web project 首先创建一个Maven的Project如下图 ? 我们勾选上Create a simple ...

360100
来自专栏自由而无用的灵魂的碎碎念

分享:Eclipse 中 drop to frame 的调试技巧

前些天和同事交流调试技巧时,知道了 Eclipse debug 时有个 drop to frame 的技巧。这是我以前不知道的,自己又查了一下这个功能的含义。官...

9120
来自专栏我是攻城师

SparkStreamingj集成Kafka的几个重要参数

40870
来自专栏MasiMaro 的技术博文

PE解析器的编写(一)——总体说明

之前自己学习了PE文件的格式,后来自己写了个PE文件的解析器,这段时间工作上刚好要用到它,老板需要能查看某个exe中加载的dll的一个工具,我在使用之前自己写的...

22220
来自专栏武军超python专栏

2018年7月31日学习ubuntu的基础操作命令和打包压缩解压缩

今天遇到的新单词: faith n 信用,信任 usage n 用法 upload n上传

17340
来自专栏张戈的专栏

Llinux文件目录权限及chmod命令简析

这些天,在互推联盟群(344134224 )遇到几例关于 WP 升级失败以及 FTP 账号登陆的问题。最终发现都是主机的目录权限设置存在问题。比如,博友【PPT...

46460
来自专栏菩提树下的杨过

ActiveMQ笔记(2):基于ZooKeeper的HA方案

activemq官网给出了3种master/slave的HA方案,详见:http://activemq.apache.org/masterslave.html ...

218100

扫码关注云+社区

领取腾讯云代金券