• 进程的创建和调度分析


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

    关于task_struct数据结构

    每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。task_struct是Linux内核的一种数据结构,它会被装载到RAM中并且包含着进程的信息。每个进程都把它的信息放在 task_struct 这个数据结构体,task_struct 部分内容如下: 

     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; //包括睡眠时间的创建时间 }

    关于do_fork()函数调用

    Linux中创建进程有三个函数fork(),vfork()和clone(),do_fork()函数对应其系统调用。调用copy_process,将当期进程复制一份出来为子进程,并且为子进程设置相应地上下文信息之后将子进程压入队列,等待被调度。以下为do_fork()函数部分代码:

    long do_fork(unsigned long clone_flags,
              unsigned long stack_start,
              unsigned long stack_size,
              int __user *parent_tidptr,
              int __user *child_tidptr)
    {
        struct task_struct *p;
        int trace = 0;
        long nr;
    
        // ...
    
        // 复制进程描述符,返回创建的task_struct的指针
        p = copy_process(clone_flags, stack_start, stack_size,
                 child_tidptr, NULL, trace);
    
        if (!IS_ERR(p)) {
            struct completion vfork;
            struct pid *pid;
    
            trace_sched_process_fork(current, p);
    
            // 取出task结构体内的pid
            pid = get_task_pid(p, PIDTYPE_PID);
            nr = pid_vnr(pid);
    
            if (clone_flags & CLONE_PARENT_SETTID)
                put_user(nr, parent_tidptr);
    
            // 如果使用的是vfork,那么必须采用某种完成机制,确保父进程后运行
            if (clone_flags & CLONE_VFORK) {
                p->vfork_done = &vfork;
                init_completion(&vfork);
                get_task_struct(p);
            }
    
            // 将子进程添加到调度器的队列,使得子进程有机会获得CPU
            wake_up_new_task(p);
    
            // ...
    
            // 如果设置了 CLONE_VFORK 则将父进程插入等待队列,并挂起父进程直到子进程释放自己的内存空间
            // 保证子进程优先于父进程运行
            if (clone_flags & CLONE_VFORK) {
                if (!wait_for_vfork_done(p, &vfork))
                    ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
            }
    
            put_pid(pid);
        } else {
            nr = PTR_ERR(p);
        }
        return nr;
    }

     

    通过gdb跟踪系统调用内核处理函数do_fork()

    输入命令:

    rm menu -rf
    git clone https://github.com/mengning/menu.git
    cd menu
    mv test_fork.c test.c
    make rootfs

    然后进行gdb调试:

    b sys_clone
    b _do_fork
    b dup_task_struct
    b copy_process

    调试效果如上图所示。

    理解编译链接的过程和ELF可执行文件格式

    1、 编译与链接的过程: 

    从源代码到可执行程序所要经历的过程概述如下图:

       源代码(.c .cpp .h)经过c预处理器(cpp)后生成.i文件,编译器(cc1、cc1plus)编译.i文件后生成.s文件,汇编器(as)汇编.s文件后生成.o文件,链接器(ld)链接.o文件生成可执行文件。

    2、 ELF可执行文件

    ELF文件格式包括三种主要的类型:可执行文件、可重定向文件、共享库。
    1.可执行文件(应用程序)可执行文件包含了代码和数据,是可以直接运行的程序。
    2.可重定向文件(.o)可重定向文件又称为目标文件,它包含了代码和数据(这些数据是和其他重定位文件和共享的object文件一起连接时使用的)。
    .o文件参与程序的连接(创建一个程序)和程序的执行(运行一个程序),它提供了一个方便有效的方法来用并行的视角看待文件的内容,这些.o文件的活动可以反映出不同的需要。
    Linux下,我们可以用gcc -c编译源文件时可将其编译成.o格式。
    3.共享文件(*.so)也称为动态库文件,它包含了代码和数据(这些数据是在连接时候被连接器ld和运行时动态连接器使用的)。动态连接器可能称为ld.so.1,libc.so.1或者 ld-linux.so.1。

    实验总结

    所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

    源代码(.c .cpp .h)经过c预处理器(cpp)后生成.i文件,编译器(cc1、cc1plus)编译.i文件后生成.s文件,汇编器(as)汇编.s文件后生成.o文件,链接器(ld)链接.o文件生成可执行文件。

     

  • 相关阅读:
    对比<input type="text" id="">和<asp:TextBox runat="server" ID="">
    EasyUI 启用行内编辑
    水平居中和transform: translateY(-50%) 实现元素垂直居中效果
    表头的一些解释
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">详解
    访问远程桌面 步骤
    jQuery EasyUI API 中文文档
    用JavaScript方式创建easyUI datagrid Column Group(列组)
    jquery中innerheight outerHeight()与height()的区别
  • 原文地址:https://www.cnblogs.com/xiguas/p/10604320.html
Copyright © 2020-2023  润新知