【OS Pintos】Project1 项目要求说明 | 进程中止信息 | 参数传递 | 用户内存访问 | 有关项目实现的建议

简介: 【OS Pintos】Project1 项目要求说明 | 进程中止信息 | 参数传递 | 用户内存访问 | 有关项目实现的建议

💭 写在前面

本篇博客将对 Pintos 的 Project1 项目的实现要求进行说明。建议阅读上篇铺垫内容并阅读 Pintos 手册,了解 Pintos 项目的 "游戏规则"。



0x00 进程终止信息(Process Termination Messages

当用户程序被终止(terminated)时,内核会打印终止信息,输出形式如下所示:

Process Name: exit(exit status)\n

(具体参考 Pintos 手册 3.3.2)

❓ 思考:用户程序是如何终止的呢?

当 ELF 用户程序运行时,lib/user/entry.c 中的_start() 首先被调用:

void _start(int argc, char* argv)
{
    exit (main (argc, argv));
}
  • 在执行程序后,exit() 系统调用被调用。
  • Pintos 只提供了 exit() 系统调用 API 接口,但 exit() 系统调用还没有实现。

我们如何得到一个进程的名称?

struct thread
{
    /* 拥有者为 thread.c  */   
    tid_t tid;
    enum thread_status status;
    char name[16];

用户程序又是如何终止的?lib/user/syscall.c exit() 的函数调用流程:

  • -> lib/user/syscall.c 中的 syscall1 (SYS_EXIT, status)
  • -> userprog/syscall.c 中的 syscall_handler()
  • -> threads/thread.c 中的 thread_exit()
  • -> userprog/process.c 中的 process_exit()

(具体请参考25-29页

0x01 参数传递(Argument Passing)

用户程序可以有多个参数:

根据 80x86 的调用惯例,解析参数并将其分配到内存中(参考 Pintos 手册 3.5)

假设参数的长度小于 4KB

  • 测试程序使用少于 128 字节的参数。

 

/bin/ls -l foo bar 将被解析为 /bin/ls-lfoobar

你可以在以下函数之后开始实现参数传递:

userprog/process.c : static bool setup_stack(void **esp)

请参考上一节的 "代码级流程" :

我们刚才说了, /bin/ls -l foo bar 将被解析为 /bin/ls-lfoobar,将参数推到栈顶:

hex_dump() 的结果,这个函数对调试非常有用(在 src/lib/stdio.c 中):

userprog/process.c 中,有 setup_stack() ,它分配了一个最小的栈页(4KB)。

由于给定的代码只分配了栈页,我们需要在 setup_stack() 之后补上栈。

(参照 Pintos 手册中的 "3.5 80x86 调用约定" 来构成栈)

0x02 系统调用:基本实现(System Calls

你需要实现下列系统调用(每个系统调用的要求在 Pintos 手册 3.3.4 中有描述):

实现:halt, exit, exec, wait, read(stdin), write(stdout)

📌 注意:Pintos exec 不同于 UNIX exec()

两个新的系统调用(fibonacci, max_of_four_int),读和写是这个项目中的特殊情况。

与文件系统相关的系统调用不需要在本项目中实现:

选择实现:create, remove, open, filesize, read, write, seek, tell, close

但是,读和写至少应该做到能执行标准流的输入输出!

halt 函数

halt()    // 通过调用 shutdown_power_off() 终止Pintos。
  • 该函数调用 shutdown_power_off() 函数,终止 Pintos。

exit 函数

exit()    // 终止当前用户程序,并将状态返回给内核
  • 终止当前用户程序,并将状态返回给内核。

exec 函数

exec()
  • 创建子进程
  • 参考 userprog/process.c 中的 process_execute()

wait 函数

wait()
  • wait() 系统调用要做的是礼貌地等待子进程,直到它完成其工作。
  • 需要检查子线程的 ID 是否有效
  • 当子线程寄了,你需要从子线程获取退出状态
  • 为了防止程序在 wait() 返回之前就终止进程,你可以使用自旋锁与忙等待技术,或使用在threads/thread.cthread_yield() 函数。

💡 神奇海螺:什么也不做。"忙等待技术" 就是代码什么也不做,只是不断地检查状况。

write 和 read 函数

write() 
read()

虽然没有完全实现,但至少可以从 STDIN 读,写到 STDOUT。

文件描述符:STDIN,STDOUT

  • STDIN = 0,STDOUT = 1

使用下面的函数来实现 read(0)

  • pintos/src/devices/input.c路径下的 uint8_t input_getc(void) 函数

使用下面的函数来实现 write(1)

  • pintos/src/lib/kernel/console.c 路径下的 void putbuf(...)  函数

代码级流程

  • 当 ELF 可执行程序(用户程序)完成后,exit() 系统调用 被调用。
  • exit() 系统调用后,返回到 process_wait() 。(exit 调用完成后系统进入进程等待状态)

源代码(Source Code)

lib/user/syscall.h lib/user/syscall.c

  • 系统调用的 API 接口已经在 Pintos 代码中给好了
  • 这意味着我们不需要为系统调用的 API 添加任何东西

userprog/syscall.h

  • 这里只有一个 syscall_init() 的样板 ,在 Pintos 启动时注册系统调用中断
  • 我们可以在这个文件中编写系统调用的原型

userprog/syscall.c

  • 必须钦定 syscall_handler() 大手子去处理系统调用
  • 如果已经做了参数传递,可以从 intr_frame* f 中获得系统调用号
  • intr_frame* f 的 esp 成员指向系统调用号。(可以参考 lib/syscall-nr.h 来检查每个系统调用号)
  • 然后你可以用 switch 语句对系统调用进行分类(分清这些系统调用到底是做什么的会写在这里)

0x03 系统调用:额外实现(Additional System Calls)

试着在 pintos 中写几个新的系统调用接口:

  • 斐波那契数列的第 项:
int fibonacci(int n)   // 返回斐波那契数列的第n项
  • 返回四个整数的最大值:
int max_of_four_int(int a, int b, int c, int d)  // 返回 a b c d 中的最大值

      * 命名请使用 fibonacci max_of_four_int ,不要使用其他名称!

 

  • 编写用户级程序,使用新的系统调用

pintos/src/examples 中制作 additional.c  (执行文件的名称必须是 "additional")

通过使用新的系统调用编写简单的例子,用法:./additional [num 1] [num 2] [num 3] [num 4]

功能:使用 [num 1] 作为参数打印 fibonacci 系统调用的结果;

使用 [num 1, 2, 3, 4] 作为参数打印 max_of_four_int 系统调用的结果。

你可以运行以下命令以检查你的程序是否正常工作:

pintos/src/userprog$ pintos --filesys-size=2 -p ../examples/additional -a additional -- -f -q run 'additional 10 20 62 40'

* additional 需要在 Pintos 里运行

📌 注意:为了编译新增加的用户程序 additional ,你需要修改 src/examples 中的 Makefile,参照 Makefile中其他用户程序的编写方式去修改。

源代码(Source Code)

lib/user/syscall.h

编写2个新的系统调用API的原型

lib/user/syscall.c

max_of_four_int() 定义新的 syscall4() 函数(lib/user/syscall.c)

定义 fibonacci() max_of_four_int() 的系统调用 API

lib/syscall-nr.h

为 2 个新的系统调用添加系统调用号

userprog/syscall.h

编写 2 个新的系统调用的原型

userprog/syscall.c

定义 fibonacci()max_of_four_int() 系统调用

这些系统调用到底是做什么的,会写在这里。

0x04 用户内存访问(Accessing User Memory)

用户程序可以传递一个无效的指针。

  • 空指针,如 tests/userprog/open-null.c 中的 open (NULL)  
  • 未映射的虚拟内存
  • 指向内核地址空间的指针

无效的指针(Invalid pointers)必须在不损害内核或其他运行进程的前提下被拒绝。

  • 它可以通过 2 种方式实现
  • 验证用户提供的指针的有效性validity of a user-provided pointer),然后取消对它的引用。
  • 只检查一个用户指针是否指向 PHYS_BASE 下面,然后取消对它的引用。如果该指针无效,将导致缺页异常(page fault)。你可以通过修改 userprog/exception.c 中的 page_fault() 代码来处理它。

* 参考 Pintos 手册 3.1.5

  • 可以利用 userprog/pagedir.c threads/vaddr.h 中的函数验证用户提供的指针的有效性
  • 利用 pagedir_get_page() 函数检查未映射的虚拟内存
  • 利用 is_user_vaddr() is_kernel_vaddr() 函数检查指向内核地址空间的指针
  • 使用这些函数来验证给定指针的有效性

0x05 实现的先后顺序(建议)

在你实现核心功能之前,你无法看到结果。

强烈建议先阅读/理解上面说的内容和 Pintos 手册,设计好结构,然后开始编写。

Step1:参数传递:实现后,可用 hex_dump() 函数检查结果。

请参考代码级流程

可用 src/userprog/process.c load() 检查 load() 的参数

如果你想在执行 process_wait() 之前检查 dump values,可暂时把 process_wait() 改成无限循环,以阻止进程,便于测试检查。    ( 等后面完成 process_wait() 的实现后再说)

Step2:用户内存访问保护用户内存访问不受系统调用的影响。

参考 src/threads/vaddr.h

建议实现检查给定地址有效性的函数。

Step3:系统调用处理程序实现 syscall_handler() 函数来处理系统调用。

src/userprog/syscall.c syscall_handler() 函数
检查
syscall.c syscall_handler() 的参数 struct intr_frame

struct intr_frame src/threads/interrupt.h 中)

Step4:系统调用实现先实现完 exec()exit()write()read(),再实现其它的。

将需要进行同步化 (可以选择使用忙等待)
syscall_handler 以非正常方式终止时,退出状态为 -1 。

Step5:额外实现最后再实现 fibonacci()max_of_four_int()

修改以下内容:

src/lib/syscall-nr.h
src/lib/syscall.h
src/lib/syscall.c

* 可参考 src/tests/userprog 路径下的源代码,Refer to Pintos manual 3.2

🚩 评分(Evaluation)

  • 在这个项目中,76 个测试中有 21 个将计入评分。
  • 总分是 100 分,包括 80 分的测试案例和20分的文档。
  • 每一个额外的系统调用的实现都会有额外的2.5分。(实现中的 fibonacci() max_of_four_int() 有5分)※ 这将在开发部分(80%)计算,所以总分将是 4 分(5*80%)。
  • 将使用 Pinots 提供的评分脚本(make grade 或 make check in src/userprog)。
  • 在评分之后,请参考 src/userprog/build 中的 '成绩' 和 '结果'文件( '成绩' 文件只有在你使用 make grade 时才会被创建)。
  • 测试用例被分为功能测试和稳健性测试,请参考以下内容,根据测试类型检查每个测试案例的要点:
  • pintos/src/tests/userprog/Rubric.functional.
  • pintos/src/tests/userprog/Rubric.robustnesss
  • 功能性和稳健性分别占总分的50% (... SeeMore)

* Refer to Pintos manual 1.2.1

如果你看到 src/tests/userprog/Grading,功能测试集占总分的 35%,健壮性测试集占总分的25%.

📃 评分方式如下:

(剩余的 20%是留给项目报告的,占总分的20%)

 

📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   2022.9.24
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy Pieces

A. Silberschatz, P. Galvin, and G. Gagne,

Operating System Concepts, 9th Edition, John Wiley & Sons, Inc., 2014, ISBN 978-1-118-09375-7.

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

相关文章
|
2月前
|
关系型数据库 MySQL
MySQL查看连接数和进程信息
这篇文章介绍了如何在MySQL中查看连接数和进程信息,包括当前打开的连接数量、历史成功建立连接的次数、连接错误次数、连接超时设置,以及如何查看和终止正在执行的连接进程。
563 10
|
2月前
|
存储 Linux 调度
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第44天】本文将带你深入操作系统的核心,探索其背后的原理和机制。我们将从进程管理开始,理解如何创建、调度和管理进程。然后,我们将探讨内存分配,了解操作系统如何管理计算机的内存资源。最后,我们将通过一些代码示例,展示这些概念是如何在实际操作系统中实现的。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
|
8天前
|
安全 Linux 网络安全
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息。本文分三部分介绍 nmap:基本原理、使用方法及技巧、实际应用及案例分析。通过学习 nmap,您可以更好地了解网络拓扑和安全状况,提升网络安全管理和渗透测试能力。
45 5
|
1月前
|
分布式计算 算法 大数据
探索操作系统的核心:调度与内存管理机制
【10月更文挑战第11天】 本文深入探讨了操作系统中两大核心功能——调度与内存管理机制。通过分析调度算法、进程状态转换及内存分配策略等关键方面,揭示了它们如何共同维护系统性能和稳定性。旨在为读者提供对操作系统内部运作的深刻理解,同时引起对优化策略的思考。
61 5
|
20天前
|
人工智能 Anolis 开发者
|
1月前
|
算法
深入理解操作系统:内存管理机制的探索之旅
【10月更文挑战第2天】在数字世界的浩瀚海洋中,操作系统犹如一艘精密的航船,承载着软件与硬件的和谐共舞。本文将揭开内存管理的神秘面纱,从基础概念到高级策略,引领读者领略操作系统内存分配的智慧。通过深入浅出的解释和生动的比喻,我们一同遨游在内存的江河之中,感受操作系统如何巧妙地协调资源,确保数据的有序流动。让我们跟随内存的脚步,探索那些隐藏在每次点击、每次命令背后的奥秘。
|
1月前
|
监控 开发者
深入理解操作系统:内存管理的艺术
【10月更文挑战第2天】在数字世界的幕后,操作系统扮演着至关重要的角色。本文将深入探索操作系统的心脏——内存管理,揭示它是如何协调和管理计算机的宝贵资源。通过浅显易懂的语言和生活化的比喻,我们将一起走进内存管理的奥秘世界,了解它的原理、机制以及为何对整个系统的性能和稳定性有着不可替代的影响。无论你是技术新手还是资深开发者,这篇文章都将为你打开新的视角,让你对日常使用的设备有更深层次的认识和尊重。
|
1月前
|
缓存 算法 调度
深入浅出操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅。我们将从进程管理的基本概念出发,逐步深入到内存管理的复杂世界,最终探索如何通过实践技巧来优化系统性能。文章将结合理论与实践,通过代码示例,帮助读者更好地理解操作系统的核心机制及其在日常技术工作中的重要性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往操作系统深层次理解的大门。
|
2月前
|
人工智能 运维 安全
专访浪潮信息:AI 原生时代,浪潮信息引领服务器操作系统创新 全面贡献龙蜥社区
分享了关于 AI 原生化趋势下服务器操作系统进化的思考,以及浪潮信息在龙蜥社区开源贡献的思路、成果与未来技术发展规划。
专访浪潮信息:AI 原生时代,浪潮信息引领服务器操作系统创新 全面贡献龙蜥社区
|
1月前
|
存储 算法 C语言
MacOS环境-手写操作系统-17-内存管理算法实现
MacOS环境-手写操作系统-17-内存管理算法实现
37 0