熟悉Minix3.1.2a操作系统的进程管理

操作系统 专栏收录该内容
3 篇文章 0 订阅

一、目的

熟悉 Minix 操作系统的进程管理
学习 Unix 风格的内存管理

二、内容与设计思想

修改Minix3.1.2a的进程管理器,改进brk系统调用的实现,使得分配给进程的数据段+栈段空间耗尽时,brk系统调用给该进程 分配一个更大的内存空间,并将原来空间中的 数据复制至新分 配的内存空间,释放原来的内存空间,并通知内核映射新分配的内存段。

三、使用环境

Minix,Moba

四、实验过程

1、完成安装minix3.1.2系统并配置相关设置。
要先编译Minix再修改内核。

2、PM是用户进程,printf结果显示在虚拟机下,可以不需要串口输出。
相关的函数
alloc_mem 分配内存
sys_abscopy 拷贝内存内容
free_mem 释放内存
sys_newmap 通知内核,注册内存段
用户调用brk函数针对的是虚拟地址,而minix最底层内存管理是物理地址,不能混淆。
需要小心处理clicks 和 bytes的单位换算和对齐。

3、修改/usr/src/servers/pm/alloc.c 中的 alloc_mem 函数,把 first-fit 修改成 best-fit,即分配 内存之前,先遍历整个空闲内存块列表,找到最小最佳匹配的空闲块。

PUBLIC phys_clicks alloc_mem(clicks)
phys_clicks clicks;		/* amount of memory requested */
{
  register struct hole *hp, *prev_ptr, *best, *prev_best;
  phys_clicks old_base;
  int flag=0;

  do {
    prev_ptr = NIL_HOLE;
    hp = hole_head;
    while (hp != NIL_HOLE && hp->h_base < swap_base) //遍历空闲链表
    {
      if(hp->h_len >= clicks && ((hp->h_len < best->h_len)||(flag==0)))
		//当找到合适的空闲块时,先让best等于这个比他大的块,当找到更小的则替换。
      {
        best=hp;
        prev_best=prev_ptr;
        flag=1;
      }
      prev_ptr = hp;
      hp = hp->h_next;
    }
	} while (swap_out());		/* try to swap some other process out */

  if (flag==1) //能找到
  {
    old_base = best->h_base; //记录块的起始位置
    best->h_base += clicks;	//best起始位置发生了变化,等于其实位置加分配的clicks大小。
    best->h_len -= clicks;	块的大小等于原长度-被分配的长度

    /* Remember new high watermark of used memory. */
    if(best->h_base > high_watermark)
      high_watermark = best->h_base;

    /* Delete the hole if used up completely. */
    if (best->h_len == 0) del_slot(prev_best, best);

    /* Return the start address of the acquired block. */
    return(old_base);
  } 

  return(NO_MEM);
}

4、修改/usr/src/servers/pm/break.c中的adjust函数,并增加了一个allocate_new_mem局部函数在adjust函数中调用。brk系统调用流程:
do_brk函数计算数据段新的边界,然后调用adjust函数,adjust函数计算程序当前的空闲空间是否足够分配:
(1)若足够,则调整数据段指针,堆栈指针;通知内核程序的映像发生了变化,返回do_brk函数。
(2)若不够,调用allocate_new_mem函数申请新的足够大的内存空间;将程序现有的数据段贺堆栈段的内容分别拷贝至新内存区域的底部(bottom)和顶部(top);通知内核程序的映像发生了变化;返回do_brk函数。

if (lower < gap_base) {/* data and stack collided */
      if (allocate_new_mem(rmp,(phys_clicks)(mem_sp->mem_vir+mem_sp->mem_len-mem_dp->mem_vir)) == 0)  
	        return(ENOMEM);
}
/*=======================================================*
 *				allocate_new_mem 				     *
*=======================================================*/
PUBLIC int allocate_new_mem(rmp,clicks) 
register struct mproc *rmp; 
phys_clicks clicks; 
{ 
  /* local variables declarations */
	register struct mem_map *mem_sp,*mem_dp; /* stack and data structs */
	phys_bytes old_bytes,data_bytes,stak_bytes,old_d_abs,new_d_abs,old_s_abs,new_s_abs; /* used to transform between bytes and clicks */
	phys_clicks old_clicks,old_base,new_clicks,new_base; /* used to transform the old click to a new one */
	phys_clicks data_clicks,new_s_base,old_s_base,stak_clicks; /* used to transform the old stack or data to a new one */
	int error; /* used to receive error code */


  /* allocation of new memory */
	mem_dp = &rmp->mp_seg[D]; /* get data struct */
	mem_sp = &rmp->mp_seg[S]; /* get stack struct */

	old_clicks = clicks; /* old size */
	new_clicks = clicks*2; /* new size */

	if ((new_base = alloc_mem(new_clicks))==NO_MEM) return (0);  /* get new_base pointer */



  /* copy data from original source */
	old_base = rmp->mp_seg[D].mem_phys;  /* get old_base address */
	old_s_base = rmp->mp_seg[S].mem_phys;  /* get old_stack_base address */
	new_s_base = new_base + new_clicks - mem_sp->mem_len;  /* get new_stack_base address */
  
	new_d_abs = (phys_bytes) new_base << CLICK_SHIFT;  /* new data address */
	old_d_abs = (phys_bytes) old_base << CLICK_SHIFT;  /* old data address */
	new_s_abs = (phys_bytes) new_s_base << CLICK_SHIFT;  /* new stack address */

	data_bytes = (phys_bytes) rmp->mp_seg[D].mem_len << CLICK_SHIFT;  /* data size (bytes) */
	stak_bytes = (phys_bytes) rmp->mp_seg[S].mem_len << CLICK_SHIFT;  /* stack size (bytes) */

	if ((error=sys_memset(0,new_d_abs,(new_clicks<<CLICK_SHIFT)))!=OK){ /* get a new empty space */
		panic(__FILE__,"new mem can't be zero",error); 
	} 

	error = sys_abscopy(old_d_abs,new_d_abs,data_bytes);  /* copy data from old memory allocation */
	if (error < 0 ) panic(__FILE__,"allocate_new_mem can't copy",error); /* error handler  */

	error = sys_abscopy(old_s_abs,new_s_abs,stak_bytes); /* copy stack from old memory allocation */
	if (error < 0 ) panic(__FILE__,"allocate_new_mem can't copy",error); /* error handler */

  /* change pointer to fit the current allocation */
	rmp->mp_seg[D].mem_phys = new_base;  /* change data address to new_base */
	rmp->mp_seg[S].mem_phys = new_s_base;  /* change data address to new stack base */
	rmp->mp_seg[S].mem_vir = mem_dp->mem_vir + new_clicks - mem_sp->mem_len; /* change stack memory address to click-len */

	free_mem(old_base,old_clicks); /* free old_base altogether */

	return (1); 
}

5、(1)进入/usr/src/servers目录,输入make image, 等编译成功之后输入make install 安装新的PM程 序。
(2)进入/usr/src/tools目录,输入make hdboot, 成功之后再键入make install命令安装新的内核程 序。
(3)键入shutdown 命令关闭虚拟机,进入boot monitor界面。设置启动新内核的选项,在提示符键入:newminix(5,start new kernel) {image=/boot/image/3.1.2ar1;boot;}
(4)然后回车,键入save命令保存设置。
(5)为启动菜单中的选择内核版本的键(数字键,可选其 他数字键),3.1.2ar1为在/usr/src/tools目录中输入make install 之后生成的内核版本号,请记 得在/usr/src/tools中执行make install命令之后记录生成的新内核版本号。 5. 输入menu命令,然后敲数字键(上一步骤中设置的数字)启动新内核,登录进minix 3中测试。

但因为我先修改了内核再编译的minix,就出现了问题:
在这里插入图片描述

但事已至此,我先尝试用编译好的test1和test2文件直接运行也没有成功,然后我又尝试使用chmod +x ./test1赋予权限,终于成功了。

# ./test1
incremented by 1, total 1
incremented by 2, total 3
incremented by 4, total 7
incremented by 8, total 15
incremented by 16, total 31
incremented by 32, total 63
incremented by 64, total 127
incremented by 128, total 255
incremented by 256, total 511
incremented by 512, total 1023
incremented by 1024, total 2047
incremented by 2048, total 4095
incremented by 4096, total 8191
incremented by 8192, total 16383
incremented by 16384, total 32767
incremented by 32768, total 65535
incremented by 65536, total 131071
incremented by 131072, total 262143
incremented by 262144, total 524287
incremented by 524288, total 1048575
incremented by 1048576, total 2097151
incremented by 2097152, total 4194303
incremented by 4194304, total 8388607
incremented by 8388608, total 16777215
incremented by 16777216, total 33554431
incremented by 33554432, total 67108863
# ./test2
incremented by: 1, total: 1 , result: 760
incremented by: 2, total: 3 , result: 4096
incremented by: 4, total: 7 , result: 4098
incremented by: 8, total: 15 , result: 4102
incremented by: 16, total: 31 , result: 4110
incremented by: 32, total: 63 , result: 4126
incremented by: 64, total: 127 , result: 4158
incremented by: 128, total: 255 , result: 4222
incremented by: 256, total: 511 , result: 4350
incremented by: 512, total: 1023 , result: 4606
incremented by: 1024, total: 2047 , result: 5118
incremented by: 2048, total: 4095 , result: 6142
incremented by: 4096, total: 8191 , result: 8190
incremented by: 8192, total: 16383 , result: 12286
incremented by: 16384, total: 32767 , result: 20478
incremented by: 32768, total: 65535 , result: 36862
incremented by: 65536, total: 131071 , result: 69630
incremented by: 131072, total: 262143 , result: 135166
incremented by: 262144, total: 524287 , result: 266238
incremented by: 524288, total: 1048575 , result: 528382
incremented by: 1048576, total: 2097151 , result: 1052670
incremented by: 2097152, total: 4194303 , result: 2101246
incremented by: 4194304, total: 8388607 , result: 4198398
incremented by: 8388608, total: 16777215 , result: 8392702
incremented by: 16777216, total: 33554431 , result: 16781310
incremented by: 33554432, total: 67108863 , result: 3355852
  • 0
    点赞
  • 1
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

自己动手写操作系统在详细分析操作系统原理的基础上,用丰富的实例代码,一步一步地指导读者用C语言和汇编语言编写出一个具备操作系统基本功能的操作系统框架。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不仅能使读者更深刻地认识操作系统的核心原理,而且使整个开发过程少走弯路。全书共分7章。 第1章 马上动手写一个最小的“操作系统1 1.1 准备工作1 1.2 10分钟完成的操作系统1 1.3 Boot Sector3 1.4 代码解释3 1.5 水面下的冰山5 1.6 回顾6 第2章 搭建你的工作环境7 2.1 虚拟计算机(Virtual PC)7 2.1.1 Virtual PC初体验8 2.1.2 创建你的第一个Virtual PC9 2.1.3 虚拟软盘研究12 2.1.4 虚拟软盘实战14 2.2 编译器(NASM & GCC)18 2.3 安装虚拟Linux19 2.4 在虚拟Linux上访问Windows文件夹26 2.5 安装虚拟PCDOS26 2.6 其他要素29 2.7 Bochs29 2.7.1 Bochs vs. Virtual PC vs. VMware30 2.7.2 Bochs的使用方法31 2.7.3 用Bochs进行调试33 2.7.4 在Linux上开发34 2.8 总结与回顾36 第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Des criptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT(Local Des criptor Table)58 3.2.3 特权级62 3.3 页式存储82 3.3.1 分页机制概述83 3.3.2 编写代码启动分页机制84 3.3.3 PDE和PTE85 3.3.4 cr388 3.3.5 回头看代码88 3.3.6 克勤克俭用内存90 3.3.7 进一步体会分页机制100 3.4 中断和异常107 3.4.1 中断和异常机制109 3.4.2 外部中断111 3.4.3 编程操作8259A113 3.4.4 建立IDT116 3.4.5 实现一个中断117 3.4.6 时钟中断试验119 3.4.7 几点额外说明121 3.5 保护模式下的I/O122 3.5.1 IOPL122 3.5.2 I/O许可位图(I/O Permission Bitmap)123 3.6 保护模式小结123 第4章 让操作系统走进保护模式125 4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的“操作系统144 第5章 内核雏形146 5.1 用NASM在Linux下写Hello World146 5.2 再进一步,汇编和C同步使用148 5.3 ELF(Executable and Linkable Format)150 5.4 从Loader到内核155 5.4.1 用Loader加载ELF155 5.4.2 跳入保护模式161 5.4.3 重新放置内核170 5.4.4 向内核交出控制权175 5.4.5 操作系统的调试方法176 5.5 扩充内核184 5.5.1 切换堆栈和GDT184 5.5.2 整理我们的文件夹191 5.5.3 Makefile191 5.5.4 添加中断处理200 5.5.5 两点说明218 5.6 小结219 第6章 进程221 6.1 迟到的进程221 6.2 概述222 6.2.1 进程介绍222 6.2.2 未雨绸缪——形成进程的必要考虑222 6.2.3 参考的代码224 6.3 最简单的进程224 6.3.1 简单进程的关键技术预测225 6.3.2 第一步——ring0→ring1227 6.3.3 第二步——丰富中断处理程序243 6.3.4 进程体设计技巧254 6.4 多进程256 6.4.1 添加一个进程体256 6.4.2 相关的变量和宏257 6.4.3 进程表初始化代码扩充258 6.4.4 LDT260 6.4.5 修改中断处理程序261 6.4.6 添加一个任务的步骤总结263 6.4.7 号外:Minix的中断处理265 6.4.8 代码回顾与整理269 6.5 系统调用280 6.5.1 实现一个简单的系统调用280 6.5.2 get_ticks的应用286 6.6 进程调度292 6.6.1 避免对称——进程的节奏感292 6.6.2 优先级调度总结300 第7章 输入/输出系统302 7.1 键盘302 7.1.1 从中断开始——键盘初体验302 7.1.2 AT、PS/2键盘304 7.1.3 键盘敲击的过程304 7.1.4 解析扫描码309 7.2 显示器325 7.2.1 初识TTY325 7.2.2 基本概念326 7.2.3 寄存器328 7.3 TTY任务332 7.3.1 TTY任务框架的搭建334 7.3.2 多控制台340 7.3.3 完善键盘处理346 7.3.4 TTY任务总结354 7.4 区分任务和用户进程354 7.5 printf357 7.5.1进程指定TTY357 7.5.2 printf()的实现358 7.5.3 系统调用write()361 7.5.4 使用printf()363 后记366 参考文献369 附录书中的章节和代码对照表370
CH1 概论 1 1.1 操作系统的定义和目标 1 1.1.1 OS作为用户与计算机硬件之间的接口 2 1.1.2 OS作为计算机系统的资源管理者 2 1.1.3 OS作为虚拟计算机 2 1.2 操作系统的形成和发展 3 1.2.1 人工操作阶段 3 1.2.2 管理程序阶段 4 1.2.3 操作系统的形成 5 1.2.4 操作系统发展的主要动力 6 1.2.5 操作系统的发展 6 1.3 流行操作系统简介 9 1.3.1 DOS操作系统 9 1.3.2 Windows操作系统 9 1.3.3 OS/2操作系统 10 1.3.4 Unix操作系统 11 1.3.5 Macintosh操作系统 11 1.3.6 MINIX操作系统 12 1.3.7 Linux操作系统 12 1.3.8 MACH操作系统 12 1.4 操作系统的分类 13 1.4.1 批处理操作系统 13 1.4.2 分时操作系统 13 1.4.3 实时操作系统 14 1.4.4 网络操作系统 15 1.4.5 分布式操作系统 16 1.4.6 嵌入式操作系统 17 1.4.7 自由软件和Linux操作系统 18 1.5 操作系统的功能 19 1.5.1 处理机管理 20 1.5.2 存储管理 20 1.5.3 设备管理 20 1.5.4 文件管理 21 1.5.5 用户接口 21 1.6 操作系统提供的用户接口 21 1.6.1 联机用户接口——操作命令 21 1.6.2 脱机用户接口——作业控制语言 22 1.6.3 程序接口——系统调用 23 1.7 操作系统的主要特性和需要解决的主要问题 23 1.7.1 操作系统的主要特性 23 1.7.2 操作系统需要解决的主要问题 24 CH2 操作系统的运行环境 26 2.1 中央处理器 26 2.1.1 单机系统和多机系统 26 2.1.2 寄存器 26 2.1.3 程序状态字寄存器 26 2.1.4 机器指令 27 2.1.5 特权指令 27 2.1.6 处理器状态 28 2.2 中断技术 28 2.2.1 中断的概念 28 2.2.2 中断源 29 2.2.3 中断装置 29 2.2.4 中断事件的处理 30 2.2.5 中断的优先级和多重中断 33 2.2.6 实例研究:Windows 2000的中断处理 34 2.3 主存储器 41 2.3.1 存储器的层次 41 2.3.2 地址转换与存储保护 42 2.4 输入输出系统 42 2.4.1 I/O系统 42 2.4.2 I/O控制方式 42 CH3 进程与线程 45 3.1 多道程序设计 45 3.1.1 多道程序设计的概念 45 3.1.2 多道程序设计的实现 46 3.2 顺序性与并发性 47 3.2.1 程序执行的顺序性 47 3.2.2 程序执行的并发性 48 3.3 进程的基本概念 49 3.3.1 进程的定义和性质 49 3.3.2 进程的状态和转换 51 3.3.3 进程的描述 54 3.3.4 进程的控制 57 3.3.5 进程管理的实现模型 59 3.3.6 实例研究——Unix SVR4的进程管理 60 3.4 线程的基本概念 63 3.4.1 引入多线程技术的必要性 63 3.4.2 多线程环境中的进程与线程 65 3.4.3 线程的实现 69 3.4.4 实例研究:JAVA语言中的线程 71 3.5 实例研究:SOLARIS的进程与线程 78 3.5.1 Solaris中的进程与线程概念 78 3.5.2 Solaris的进程结构 79 3.5.3 Solaris的线程状态 80 3.5.4 Solaris的线程程序设计接口 81 3.6 实例研究:WINDOWS 2000的进程与线程 82 3.6.1 Windows 2000中的进程与线程概念 82 3.6.2 进程对象 82 3.6.3 线程对象 85 3.6.4 作业对象 87 CH4 处理机调度 89 4.1 处理机调度的类型 89 4.1.1 处理机调度的层次 89 4.1.2 高级调度 90 4.1.3 中级调度 91 4.1.4 低级调度 91 4.1.5 选择调度算法的原则 91 4.2 批处理作业的管理与调度 92 4.2.1 批处理作业的管理 92 4.2.2 批处理作业的调度 93 4.2.3 作业调度算法 93 4.3 进程调度 95 4.3.1 进程调度的功能 95 4.3.2 进程调度算法 96 4.3.3 实时调度 98 4.3.4 多处理器调度 99 4.3.5 实例研究——传统Unix调度算法 102 4.3.6 实例研究——Unix SVR4调度算法 103 4.3.7 实例研究——Windows NT调度算法 104 CH5 并发进程 106 5.1 并发进程 106 5.1.1 顺序性和并发性 106 5.1.2 与时间有关的错误 106 5.1.3 进程的交互(Interaction Among Processes)——协作和竞争 108 5.2 临界区管理 109 5.2.1 互斥和临界区 109 5.2.2 临界区管理的尝试 110 5.2.3 实现临界区管理的软件方法 111 5.2.4 实现临界区管理的硬件设施 113 5.3 信号量与PV操作 114 5.3.1 同步和同步机制 114 5.3.2 记录型信号量与PV操作 116 5.3.3 用记录型信号量实现互斥 117 5.3.4 记录型信号量解决生产者-消费者问题 119 5.3.5 记录型信号量解决读者-写者问题 121 5.3.6 记录型信号量解决理发师问题 123 5.3.7 AND型信号量机制 123 5.3.8 一般型信号量机制 125 5.4 管程 127 5.4.1 管程和条件变量 127 5.4.2 Hanson方法实现管程 130 5.4.3 Hoare方法实现管程 135 5.5 消息传递 138 5.5.1 消息传递的概念 138 5.5.2 消息传递的方式 139 5.5.3 有关消息传递实现的若干问题 140 5.5.4 管道和套接字 143
评论 1 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页

打赏作者

张嘉睿大聪明

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值