当前课程知识点:Linux 内核分析与应用 > 第4章 内存管理 > 4.7 动手实践-Linux内存映射测试(下) > Video
我们来看看用户测试程序的代码
测试程序分为两部分 一个是读程序一个是写程序
在读程序中 我们将展示进程在用户态
直接读取到我们在内核态写入内存的数据
而在写程序中我们将展示进程在用户态
直接向我们在内核态申请的内存区里写入数据
我们来分别看看两个程序的代码
这是读程序的代码在读程序中
我们首先要做的是打开设备文件
紧接着调用mmap系统调用 这是用户态的mmap函数
它第一个参数是映射区的地址
第二位是映射区的长度
接下来的prot 是一个标志位
表示期望的内存保护标志
prot_read 表示页内容可以被读取的
紧接着是flags位
它可以使多个标志位的组合
用来指定映射对象的类型
MAP_PRIVATE表示建立的是一个写入时拷贝的私有映射区
而MAP_LOCKED 表示的是
锁定映射区的页面 从而防止页面被交换出内存
这个fd就是我们刚刚打开的文件描述符
最后一位是offset位表示
被映射对象从那里开始
也就是从该文件中的
哪一个文件偏移量开始 这里我们从0开始
这个循环呢我们可以看到
我们读取了映射区中2页的数据
并将它们打印了出来
最后呢这里是
一个死循环让进程执行完先暂时不要退出
接着呢我们来看写入程序
在写入程序中我们可以看到与读取程序的代码很类似区别
仅在于这里
我们的
mmap标志位是SHARED
而在读程序中用的是MAP_PRIVET
用MAP_SHARED就表示
该映射区可以和其它所有映射这个对象的进程共享
空间 因为我们要写入 如果我们还用的是私有的映射区的话
那么我们写入的数据 将只能被
我们写入的进程看到 其他
映射该内存区的进程是无法看到的
接着我们在该区域的第一页中
写入了一段字符串
最后这个死循环也是防止进程执行完退出的
好了 我们来看看它们的执行情况
在开始之前首先要将我们的驱动模块编译 并插入内核
先看一下makefile文件
这个makefile文件与我们之前做的
内核模块的makefile很类似
我们make它 然后用insmod命令插入.ko文件
然后我们需要创建一个虚拟字符设备的设备节点
使用mknod命令
在dev目录下 这里我们的
设备文件名要与我们在驱动模块中
声明的设备名一致
设备类型为字符
主设备号也要与在驱动模块中定义的一致 次设备号为0
完成这些后我们就在系统中创建好了我们的设备
先来看看读程序的运行情况
可以看到它成功的在用户态读到了
两个页面的数据
我们看一下dmesg中的信息
在dmesg中我们可以看到读进程的pid是24945
然后映射前的线性地址 这是
映射前的物理地址
这是映射后的线性地址
我们可以看到映射前的线性地址
它是连续的
映射后在进程中的线性地址也是连续的
而物理页款号呢也就是物理地址
它是不连续的
而且我们注意到
我们的fault函数被调用了两次
也就意味着我们在用户进程中访问的那两页
而其他映射区的页表项还没有被建立
有了进程的pid后我们可以再使用命令查看该进程的内存映射信息
我们使用这样的命令proc
看一下proc
进程号是24945
然后在maps文件夹下
在这里 我们可以看到
设备文件
dev/mapnopage这个设备文件被映射到了
该进程的虚拟地址空间中
而且映射区的大小呢
也跟我们在mmap系统调用中设置的是一样大小
好了 我们再执行一个写的程序看看
执行完了写的程序 我们在dmesg中查看信息
在dmesg中可以看到 写程序呢
它的pid是24964
而且我们注意到,因为我们在写的程序中只写了一页
所以fault函数也就被调用了一次
而且我们注意到
在映射前的线性地址
与我们在读进程中看到的是一样的
物理地址当然也是一样的
但是映射后的线性地址那它是不一样的 这是因为
这是在两个完全不同的进程地址空间中
完成了映射
那么我们再来执行一次读的程序看看
有没有将刚才写入的数据 写入到内存中
我们看到 第一页的数据已经发生了改变
这三个进程映射了同一块物理内存
实现了在用户态直接读写内核空间的数据
并且在这三个进程之间实现了共享内存
到这里我们的mmap内存程序演示就全部完毕了
最后还要补充一点 还记得我们在一开始有关mmap的介绍中提到
mmap是内存映射文件的一种方法
但我们在程序演示中好像除了打开设备文件 再没提过文件的事了
mmap也只是对内存物理地址做了映射
而如果我们映射了一个普通文件
那么必然涉及到磁盘数据到内存数据之间的传输
这张图展示了没我们没有提到的那一部分
在内存中存在一个叫做文件cache的区域
在打开文件后
磁盘上的一部分文件数据会先被读取到内存中的文件cache中
当我们对文件读取或者写入时
实际上是对文件cache中的数据进行读写的
而当我们读取的数据不在内存中时
或者要向文件中写入新的数据时 操作系统就会调用磁盘I/O
将数据读写到磁盘上
具体的工作是由文件系统来负责的
这部分的内容展开来讲有很多东西
感兴趣的同学可以下去了解
那么 今天的分享就是这些 谢谢大家
-1.1 Linux操作系统概述
-1.2 Linux内核结构以及内核模块编程
--Video
-1.3 Linux内核源码中的双链表结构
--Video
-1.4 源码分析-内核中的哈希表
--Video
-1.5 动手实践-Linux内核模块的插入和删除
--Video
-第1章 概述--章节测验
-2.1 内存管理之内存寻址
--Video
-2.2 段机制
--Video
-2.3分页机制
--Video
-2.4 动手实践-把虚拟地址转换成物理地址
--Video
-第2章 内存寻址--章节测验
-3.1 进程概述
--Video
-3.2 Linux进程创建
--Video
-3.3 Linux进程调度
--Video
-3.4 动手实践-打印进程描述符task_struct中的字段
--Video
-3.5工程实践-基于内核模块的负载监控
--Video
-第3章 进程管理--章节测验
-4.1 Linux内存管理机制
--Video
-4.2 进程用户空间管理机制
--Video
-4.3 物理内存分配与回收机制(上)
--Video
-4.4 物理内存分配与回收机制(下)
--Video
-4.5 动手实践-Linux内存映射基础(上)
--Video
-4.6 动手实践-Linux内存映射实现(中)
--Video
-4.7 动手实践-Linux内存映射测试(下)
--Video
-4.8 初学者对内存管理的常见疑惑
-第4章 内存管理--章节测验
-5.1 中断机制概述
--Video
-5.2 中断处理机制
--Video
-5.3 中断下半部处理机制
--Video
-5.4 时钟中断机制
--Video
-5.5 动手实践-中断上半部的代码分析及应用
--Video
-5.6 动手实践-中断下半部的代码分析及应用
--Video
-第5章 中断--章节测验
-6.1 Linux中的各种API
--Video
-6.2 系统调用机制
--Video
-6.3 动手实践-添加系统调用(系统调用日志收集系统)
--Video
-第6章 系统调用--章节测验
-7.1 内核同步概述
--Video
-7.2 内核同步机制
--Video
-7.3 动手实践-内核多任务并发实例(上)
--Video
-7.4 动手实践-内核多任务并发实例(下)
--Video
-第7章 内核同步--章节测验
-8.1 虚拟文件系统的引入
--Video
-8.2 虚拟文件系统的主要数据结构
--Video
-8.3 文件系统中的各种缓存
--Video
-8.4 页高速缓存机制以及读写
--Video
-8.5 动手实践-编写一个文件系统(上)
--Video
-8.6 动手实践-编写一个文件系统(中)
--Video
-8.7 动手实践-编写一个文件系统(下)
--Video
-第8章 文件系统--章节测验
-9.1 设备驱动概述
--Video
-9.2 I/O空间管理
--Video
-9.3 设备驱动模型
--Video
-9.4 字符设备驱动程序简介
--Video
-9.5 块设备驱动程序简介
--Video
-9.6 动手实践-编写字符设备驱动程序
--Video
-9.7工程实践-编写块设备驱动的基础(上)
--Video
-9.8 工程实践-块设备驱动程序分析(中)
--Video
-9.9 工程实践-块设备驱动程序实现(下)
--Video
-第9章 设备驱动--章节测验
-致谢与说明
--Video