本实验的主要内容:
- 实现文件系统。
- spawn process。
- 实现 shell。
1、文件系统服务器
JOS 中文件系统以独立进程的方式存在。当其他进程需要访问文件系统时,就与该进程进行 IPC。
与文件系统服务器进程的 IPC 过程。
Regular env FS env
+---------------+ +---------------+
| read | | file_read |
| (lib/fd.c) | | (fs/fs.c) |
...|.......|.......|...|.......^.......|...............
| v | | | | RPC mechanism
| devfile_read | | serve_read |
| (lib/file.c) | | (fs/serv.c) |
| | | | ^ |
| v | | | |
| fsipc | | serve |
| (lib/file.c) | | (fs/serv.c) |
| | | | ^ |
| v | | | |
| ipc_send | | ipc_recv |
| | | | ^ |
+-------|-------+ +-------|-------+
| |
+-------------------+
当系统启动时创建文件系统服务器进程 (serv.c
),简述其启动以及服务流程。
/fs/serv.c
--> umain()
// 为文件系统中的每个文件分配一个页,1024 * 4KB。
--> serve_init()
// Initialize the file system
--> fs_init()
// 找到 IOS 的磁盘,使用第二个 IDE 磁盘块。
--> ide_probe_disk1()
--> ide_set_disk()
// 初始化块缓存。
--> bc_init()
--> set_pgfault_handler(bc_pgfault)
// Test that the block cache works, by smashing the superblock and
// reading it back.
--> check_bc()
// cache the super block by reading it once
--> memmove(&super, diskaddr(1), sizeof super)
// Set "super" to point to the super block.
--> super = diskaddr(1)
--> check_super()
// Set "bitmap" to the beginning of the first bitmap block.
--> bitmap = diskaddr(2)
--> check_bitmap()
--> serve()
// while(1) 循环。
// 文件服务器循环等待接收其他进程的 IPC 请求。
--> ipc_recv()
// 打开请求的文件并存储在 fd page 中。
--> r = serve_open(whom, (struct Fsreq_open*)fsreq, &pg, &perm)
// 发送目标内容。
--> ipc_send()
// 取消为发送数据而分配的页面
--> sys_page_unmap()
2、Spawning Processes
/lib/spawn.c
// Spawn a child process from a program image loaded from the file system.
--> spawn(const char *prog, const char **argv)
// 1. Open the program file.
--> r = open(prog, O_RDONLY)
// 2. Read the ELF header, as you have before, and sanity check its
// magic number. (Check out your load_icode!)
--> if (readn(fd, elf_buf, sizeof(elf_buf)) != sizeof(elf_buf)
|| elf->e_magic != ELF_MAGIC)
// 3. Create new child environment.
--> r = sys_exofork()
// 4. Set child_tf to an initial struct Trapframe for the child.
--> child_tf
// 5. Call the init_stack() function above to set up
// the initial stack page for the child environment.
--> r = init_stack(child, argv, &child_tf.tf_esp)
// 6. Set up program segments as defined in ELF header.
--> for()
// 7. Call sys_env_set_trapframe(child, &child_tf) to set up the
// correct initial eip and esp values in the child.
--> r = sys_env_set_trapframe(child, &child_tf)
// 8. Start the child process running with sys_env_set_status().
--> r = sys_env_set_status(child, ENV_RUNNABLE)
以 spawnhello
为例:
/user/spawnhello
创建一个进程,任务是从文件系统中加载 hello.c 二进制映像并运行。
--> umain(int argc, char **argv)
//
--> r = spawnl("hello", "hello", 0)
--> spawn(prog, argv)
3、The Shell
以 icode.c
为例。
/user/icode.c
--> umain(int argc, char **argv)
--> fd = open("/motd", O_RDONLY)
--> n = read(fd, buf, sizeof buf-1)
--> sys_cputs(buf, n)
--> close(fd)
--> r = spawnl("/init", "init", "initarg1", "initarg2", (char*)0)
/lib/spawn.c
--> spawnl(const char *prog, const char *arg0, ...)
--> spawn(const char *prog, const char **argv)
/user/init.c
--> umain(int argc, char **argv)
--> r = opencons()
--> r = dup(0, 1)
--> r = spawnl("/sh", "sh", (char*)0)
--> wait(r)
/user/sh.c
--> umain(int argc, char **argv)
--> argstart(&argc, argv, &args)
--> r = argnext(&args)
-->