Linux操作系统进程管理与调度算法实现(1)

1. main函数之前的事情

在终端执行C/C++程序,终端将调用execve函数执行程序

  • filename —— 表示可执行文件
  • argv —— 表示参数
  • envp —— 表示环境变量

构建一个进程,然后执行。

#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);

1)首先是构造linux_binprm对象

  • mm是mm_struct对象
    • pgd是新进程的页表,mm_alloc_pgd申请储存页表的空间,然后拷贝内核页表内容
  • vma是栈空间,最大8MB,初始时4KB

  • p指向栈顶,初始时指向vm_end - sizeof(void*)位置处

将filename、env和argv写入到栈中。

2)然后调用load_elf_binary()函数加载ELF文件,初始化进程虚拟内存空间

  • begin_new_exec:设置新的mm_struct数据结构,刷新页表
  • setup_new_exec:设置mmap_base位置
  • setup_arg_pages:随机化stack_top位置

3)最后调用start_thread()函数,修改ip和sp寄存器的值,开始执行_start()函数,开始main()函数执行

#define START_THREAD(elf_ex, regs, elf_entry, start_stack)    \
    start_thread(regs, elf_entry, start_stack)

void
start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
{
    start_thread_common(regs, new_ip, new_sp,
                __USER_CS, __USER_DS, 0);
}

2. 进程 vs 线程

Linux并没有区分进程和线程,两者没有差别,统一是task,使用task_struct描述

  • thread_info和thread记录和架构相关的task信息
  • stack内核栈,默认大小16KB,stack_vm_area表示使用vmalloc分配的内核栈内存区域
  • mm记录虚拟内存
  • fs和files分别表示文件系统和打开的文件
  • signal表示信号

Linux也没有提供创建进程和线程的系统调用,fork/vfork/clone统一调用kernel_clone()函数创建一个task。

clone_flags控制了创建task时,父子task可以共享的资源

  • CLONE_VM:虚拟地址空间
  • CLONE_FS:文件系统
  • CLONE_FILES:打开的文件
  • CLONE_SIGHAND:信号以及处理handler

当调用pthread_create()函数创建一个线程时,使用的clone_flags如下:

 const int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM
               | CLONE_SIGHAND | CLONE_THREAD
               | CLONE_SETTLS | CLONE_PARENT_SETTID
               | CLONE_CHILD_CLEARTID
               | 0);

当使用CLONE_VM时,copy_mm()函数直接使用父进程的mm;否则调用dup_mm复制父进程的虚拟内存空间:遍历每个vma,复制页表:

static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
{
// ...
    if (clone_flags & CLONE_VM) {
        mmget(oldmm);
        mm = oldmm;
    } else {
        mm = dup_mm(tsk, current->mm);
        if (!mm)
            return -ENOMEM;
    }

    tsk->mm = mm;
    tsk->active_mm = mm;
    sched_mm_cid_fork(tsk);
    return 0;
}

如果支持COW,父进程和子进程的页表被设置位写保护wrprotect。

对对应的page执行写操作会触发缺页中断,do_cow_fault()函数会处理这类缺页中断。

另外,pthread_create传入了newsp表示线程用户空间的栈空间(pthread使用mmap分配的内存)。

在运行子进程前,内核栈空间构造了fork_frame对象。

struct fork_frame {
    struct inactive_task_frame frame;
    struct pt_regs regs;
};

pt_regs::bp指向线程栈空间,子进程运行ret_from_fork_asm()返回用户空间,使用newsp线程栈空间

更多内容请看下回。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值