练习
===========================================

课后练习
-------------------------------

编程题
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. `*` 分别编写基于UNIX System V IPC的管道、共享内存、信号量和消息队列的Linux应用程序，实现进程间的数据交换。
2. `**` 分别编写基于UNIX的signal机制的Linux应用程序，实现进程间异步通知。
3. `**` 参考rCore Tutorial 中的shell应用程序，在Linux环境下，编写一个简单的shell应用程序，通过管道相关的系统调用，能够支持管道功能。
4. `**` 扩展内核，实现共享内存机制。
5. `***` 扩展内核，实现signal机制。

问答题
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. `*` 直接通信和间接通信的本质区别是什么？分别举一个例子。
2. `**` 试说明基于UNIX的signal机制，如果在本章内核中实现，请描述其大致设计思路和运行过程。
3. `**` 比较在Linux中的无名管道（普通管道）与有名管道（FIFO）的异同。
4. `**` 请描述Linux中的无名管道机制的特征和适用场景。
5. `**` 请描述Linux中的消息队列机制的特征和适用场景。
6. `**` 请描述Linux中的共享内存机制的特征和适用场景。
7. `**` 请描述Linux的bash shell中执行与一个程序时，用户敲击 `Ctrl+C` 后，会产生什么信号（signal），导致什么情况出现。
8. `**` 请描述Linux的bash shell中执行与一个程序时，用户敲击 `Ctrl+Zombie` 后，会产生什么信号（signal），导致什么情况出现。
9. `**` 请描述Linux的bash shell中执行 `kill -9 2022` 这个命令的含义是什么？导致什么情况出现。
10. `**` 请指出一种跨计算机的主机间的进程间通信机制。

实验练习
-------------------------------

实验练习包括实践作业和问答作业两部分。

**本次难度也就和lab3一样吧** 

编程作业
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

进程通信：邮箱
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

这一章我们实现了基于 pipe 的进程间通信，但是看测例就知道了，管道不太自由，我们来实现一套乍一看更靠谱的通信 syscall吧！本节要求实现邮箱机制，以及对应的 syscall。

- 邮箱说明：每个进程拥有唯一一个邮箱，基于“数据报”收发字节信息，利用环形buffer存储，读写顺序为 FIFO，不记录来源进程。每次读写单位必须为一个报文，如果用于接收的缓冲区长度不够，舍弃超出的部分（截断报文）。为了简单，邮箱中最多拥有16条报文，每条报文最大长度256字节。当邮箱满时，发送邮件（也就是写邮箱）会失败。不考虑读写邮箱的权限，也就是所有进程都能够随意给其他进程的邮箱发报。

**mailread**:

    * syscall ID：401
    * Rust接口: ``fn mailread(buf: *mut u8, len: usize)``
    * 功能：读取一个报文，如果成功返回报文长度.
    * 参数：
        * buf: 缓冲区头。
        * len：缓冲区长度。
    * 说明：
        * len > 256 按 256 处理，len < 队首报文长度且不为0，则截断报文。
        * len = 0，则不进行读取，如果没有报文读取，返回-1，否则返回0，这是用来测试是否有报文可读。
    * 可能的错误：
        * 邮箱空。
        * buf 无效。

**mailwrite**:

    * syscall ID：402
    * Rust接口: ``fn mailwrite(pid: usize, buf: *mut u8, len: usize)``
    * 功能：向对应进程邮箱插入一条报文.
    * 参数：
        * pid: 目标进程id。
        * buf: 缓冲区头。
        * len：缓冲区长度。
    * 说明：
        * len > 256 按 256 处理，
        * len = 0，则不进行写入，如果邮箱满，返回-1，否则返回0，这是用来测试是否可以发报。
        * 可以向自己的邮箱写入报文。
    * 可能的错误：
        * 邮箱满。
        * buf 无效。
  
实验要求
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- 实现分支：ch6-lab
- 实验目录要求不变
- 通过所有测例

  在 os 目录下 ``make run TEST=1`` 加载所有测例， ``test_usertest`` 打包了所有你需要通过的测例，你也可以通过修改这个文件调整本地测试的内容。

  你的内核必须前向兼容，能通过前一章的所有测例。

challenge: 支持多核。

问答作业
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(1) 举出使用 pipe 的一个实际应用的例子。

(2) 共享内存的测例中有如下片段(伪代码)：

    .. code-block:: c 

      int main()
      {
          uint64 *A = (void *)0x10000000;
          uint64 *B = (void *)(0x10000000 + 0x1000);
          uint64 len = 0x1000;
          make_shmem(A, B, len); // 将 [A, A + len) [B, B + len) 这两段虚存映射到同一段物理内存
          *A = 0xabab;
          __sync_synchronize();  // 这是什么？
          if(*B != 0xabab) {
              return ERROR;
          }
          printf("OK!");
          return 0;
      }

    请查阅相关资料，回答 ``__sync_synchronize`` 这行代码的作用，如果去掉它可能会导致什么错误？为什么？


实验练习的提交报告要求
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* 简单总结本次实验与上个实验相比你增加的东西。（控制在5行以内，不要贴代码）
* 完成问答问题
* (optional) 你对本次实验设计及难度的看法。