IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 从一个ELF程序的加载窥探操作系统内核-(3) -> 正文阅读

[Java知识库]从一个ELF程序的加载窥探操作系统内核-(3)

从一个ELF程序的加载窥探操作系统内核-(3)

操作系统加载一个ELF程序看似一个EASY的动作,其实下面隐藏了很多很多OS内核的关键实现,让我们一起来解密其中的流程

作者是一个micro kernel的开发者,在设计动态链接器的时候,在此留下一些笔记,重点参考了以下资料文献

  • 《程序员的自我修养》
  • 《深入理解计算机系统》
  • 《现代操作系统-原理与实现》
  • 《深入理解LINUX内核》
  • 《设计模式/JAVA》

进程和线程究竟有何区别

让我们先回到MCU的世界:

  • 由于MCU没有MMU单元,所以在RTOS中没有进程的概念,只有任务的概念,任务调度是基于任务来进行的
  • 也没有内核态用户态之分,RTOS下操作系统和用户程序都处于一种状态(在Armv7-M下为线程模式),所以用户可以修改内核的数据,而且一旦应用程序崩溃,OS内核也会崩溃,因为他们共享了堆栈空间
  • 所有的内存读写都处于实地址模式下,也就是直接操作的是物理地址空间

现在我们有个需求我们需要把内核和应用程序分开,这样用户就不能随意修改我的内核了,在MMU没有出现之前这是没有办法实现的,当然还得要CPU支持两种模式

  • 有了MMU,我们可以把内核和app分别编译到不同的地址空间去,这个由链接脚本指定就可以
  • Armv7-A中支持7种模式,我们使用其中的User和SVC这两种来对应用户态和内核态
  • 在页表的映射中,我们可以指定内核只能在内核态才能资源访问,这样在用户态就无权对内核地址空间做修改了
    if (iskernel) {
             /*
             * 内核页表
             * 内核代码段:只有内核态有RO权限
             * 内核数据段:只有内核态有RW权限
             */
            ap_ro = MAP_AP_KRO_UNA;
            ap_rw = MAP_AP_KRW_UNA;
        } else {
            /*
             * 用户页表
             * 用户代码段:用户和内核态都只有RO权限
             * 用户数据段:用户和内核态都拥有RW权限
             */
            ap_ro = MAP_AP_KRO_URO;
            ap_rw = MAP_AP_KRW_URW;
        }
    

重中之重:页表

无论是内核态用户态的划分,还是多进程的实现,关键就在于页表的映射

  • 当内核启动后,启动第一个用户任务,这个任务的tcb里包含了pagetable的数据结构,在2级映射中,一级页表其实就是一个4096的数组,二级页表是动态分配的。
  • 在1号进程中,对地址空间进行了映射,首先内核的代码和数据,需要进行映射到1号进程的页表中,有小伙伴要问了,1号不是用户进程吗?为什么要映射内核的代码和数据给他呢?
    • 其实这里有一个认识误区:我们区分的是用户态和内核态,不是用户页表与内核页表,对没有内核线程的OS来说,除了idle任务外,其他的任务都是用户任务,我们的任务调度实际上是在用户任务中进行
    • 如果你不把内核资源映射给1号进程,会发生什么?当中断调度发生,此刻会陷入内核态,但是页表还是1号,此刻进入内核态执行的代码全是在内核地址空间,此刻是不是就有问题?所以必须要把内核的代码和数据映射给用户进程的页表
    • 我们只需要设置用户页表里必须进入内核态才能访问访问内核的AP权限就可以了,这才是实现隔离用户空间和内核空间的关键
  • 在linux经典的VMA空间布局中,每个进程的高端内存都是内核地址空间的映射,就是由此而来

理解了这个后,多进程其实就很简单了,多进程就是每个任务有不同的页表,虽然看起来大家都是从同一个虚拟地址(linux下是从0x08040000)开始,但是由于页表不同,最后对应的物理地址空间是不一样的。

线程:轻量级进程

首先,线程是依赖于进程的,一个进程下的多个线程共享了同一个页表而已

进程模型:通常我们称这样为一个进程

int main()
{
    printf("hallo world");
    return 0
}

线程模型:通常我们要先建立一个进程,然后再在这个进程上创建线程

void *hallo(void *pthread)
{
    while(1)
    {
        printf("hallo thread");
        sleep(1);
    }
}

int main()
{
    printf("hallo world");
    pthread_create(hallo_thread);
    return 0
}

在线程模型中,多个线程的TCB中的页表是相同的,都指向进程的页表,这就是轻量级进程的由来,地址空间的创建是消耗很大的

总结一下线程和进程的区别:

  • 进程间的资源是隔离的,页表不同
  • 线程间的资源是共享的,页表相同,可以理解成线程就是MCU下RTOS的任务模型
    在这里插入图片描述

从上图可以看到

  • 对于调度器来说,不管你是进程还是线程,对我来说都是以任务为单元来进行调度的,task1,task2,task3明显就是一个进程内的,他们的页表是相同的,task1是在fork+exec创建的进程,task2,task3是通过pthread_create创建的线程
  • 从资源管理的角度来说,task1,task2,task3统称为一个进程,task4,task5为单独进程
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:09:58  更:2022-03-30 18:12:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:49:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码