初学ucore操统笔记(5)--用户进程管理

来源:互联网 发布:淘宝文案岗位职责 编辑:程序博客网 时间:2024/05/16 18:36

1.概述

    操作系统呆在核心态,才能管理整个计算机系统。但是应用程序员也需要编写各种应用软件,且要在计算机系统上运行。如果把这些应用软件都作为内核线程来执行,那系统的安全性就无法得到保证了。所以系统要提供用户态进程的创建和执行机制,给应用程序执行提供一个用户态运行环境。

    与之前有所不同的是体现在进程管理和内存管理部分。

    此时增加用户态虚拟内存管理。

    不同的进程有各自的页表,所以即使不同进程的用户态虚拟地址相同,但由于页表把虚拟页映射到了不同的物理页帧,所以不同进程的虚拟内存空间是被隔离开的,相互之间无法直接访问。在用户态内存空间和内核态空间之间需要拷贝数据。

    进程管理方面,主要涉及到的是进程控制块中与内存管理相关的部分,包括建立进程的页表和维护进程可访问空间的信息;加载一个ELF格式的程序到进程控制块管理的内存中的方法;在进程复制(fork)过程中,把父进程的内存空间拷贝到子进程内存空间的技术。另一部分与用户态进程生命周期管理相关,包括让进程放弃CPU而睡眠等待某事件;让父进程等到子进程结束;一个进程杀死另一个进程;给进程发消息;建立进程的血缘关系链表。

2.创建用户进程

   与用户进程的创建过程相比,创建内核线程的过程还远远不够。而这两个过程的差异本质上就是用户进程和内核线程的差异决定的。

 (1)应用程序的组成和编译

 (2)用户进程的虚拟地址空间

           把用户进程的虚拟地址空间分了两块,一块与内核线程一样,是所有用户进程都共享的内核虚拟地址空间,映射到同样的物理内存地址空间中,这样在物理内存中只需放置一份内核代码,使得用户进程从用户态进入核心态时,内核代码可以统一应对不同的内核程序;另外一块是用户虚拟地址空间,虽然虚拟地址范围一样,但映射到不同且没有交集的物理内存空间中。

 (3)创建并执行用户进程

// kernel_execve - do SYS_exec syscall to exec a user program called by user_main kernel_threadstatic intkernel_execve(const char *name, unsigned char *binary, size_t size) {    int ret, len = strlen(name);    asm volatile (        "int %1;"        : "=a" (ret)        : "i" (T_SYSCALL), "0" (SYS_exec), "d" (name), "c" (len), "b" (binary), "D" (size)        : "memory");    return ret;}#define __KERNEL_EXECVE(name, binary, size) ({                          \            cprintf("kernel_execve: pid = %d, name = \"%s\".\n",        \                    current->pid, name);                                \            kernel_execve(name, binary, (size_t)(size));                \        })#define KERNEL_EXECVE(x) ({                                             \            extern unsigned char _binary_obj___user_##x##_out_start[],  \                _binary_obj___user_##x##_out_size[];                    \            __KERNEL_EXECVE(#x, _binary_obj___user_##x##_out_start,     \                            _binary_obj___user_##x##_out_size);         \        })

// init_main - the second kernel thread used to create user_main kernel threadsstatic intinit_main(void *arg) {#ifdef TEST    KERNEL_EXECVE2(TEST, TESTSTART, TESTSIZE);#else    KERNEL_EXECVE(hello);#endif    panic("kernel_execve failed.\n");    return 0;}
    init_main函数在缺省情况下是执行宏KERNEL_EXECVE(hello),而这个宏最终是调用kernel_execve函数来调用SYS_exec系统调用,由于ld在链接hello|应用程序执行码时定义了两全局变量:

    _binary_obj___user_hello_out_start:执行码的起始位置

    _binary_obj___user_hello_out_size:hello执行码的大小

    把这两个变量作为SYS_EXEC系统调用的参数,让ucore操作系统来创建此用户进程。

3.进程退出和等待进程

   当进程执行完它的工作以后,就需要执行退出操作,释放进程占用的资源。ucore粉两步完成这个工作,首先由进程本身完成大部分资源的占用内存回收工作,然后由此进程的父进程完成剩余资源占用内存的回收工作。

4.系统调用实现

   操作系统为什么需要实现系统调用呢?其实这是实现了用户进程后,自然引申出来需要实现的操作系统功能。用户进程只能在操作系统给它圈定好的“用户环境”中执行,但“用户环境”限制了用户进程能够执行的指令,即用户进程只能执行一般的指令,无法执行特权指令。如果用户进程想执行一些需要特权指令的任务,比如通过网卡发网络包等,只能让操作系统来代劳了。就是救需要一种机制来确保用户进程不能执行特权指令,但能够请操作系统“帮忙”完成需要特权指令的任务,这种机制就是系统调用。

  

0 0
原创粉丝点击