选择教材

这个暑假的安排之一是学习操作系统。这方面的学习材料有 MIT 6.828, UCB CS 162, NJU 的 OS 课。

其中 6.828 没有在线视频,有 Lab。 NJU 的 OS 课在 B 站有视频。CS 162 在 Youtube 上有生肉。当然英语对计算机相关专业的学生应该不是什么问题。

我选择的学习路线是阅读英文原版的 Operating Systems: Three Easy Pieces ,这可以在网上免费获取 + 完成 MIT 6.828 的 Lab。一般来说我会觉得视频课比较拖沓,简单看了 NJU 和 UCB 的视频之后我决定只看书。

家庭作业和 Lab 可以在这本书的网站上方便的获取。

学习路径

目前为止我阅读了 Virutalization 的一半,每章末尾的作业都是一些运行示例程序和思考题。Lab 实际上是单独列于教材之外的。所以你需要阅读几章之后自己决定自己的 Lab 作业。

笔记和部分习题解答

Process API

2

  1. Write a program that opens a file (with the open()system call)and then calls fork()to create a new process. Can both the child and parent access the file descriptor returned by open()? What happens when they are writing to the file concurrently, i.e., at the same time?

父子进程都可以使用文件描述符。同时写入会导致内容相互覆盖,多次运行结果不一致。

/*
 *     ____              _    
 *    / __ \____ _____  (_)___
 *   / /_/ / __ `/ __ \/ /_  /
 *  / _, _/ /_/ / /_/ / / / /_
 * /_/ |_|\__,_/ .___/_/ /___/
 *            /_/             
 *           code@rapiz.me
 *          Sat, 27 Jun 2020 17:18:45 +0800
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

typedef long long ll;
void ww(int fd, int count, const char* str) {
	int len = strlen(str);
	for (int i = 0; i < count; i++) {
		write(fd, str, len);
	}
}
int main() {
	int t = fork();
	int fd = open("/tmp/testfile", O_CREAT | O_WRONLY, S_IRWXU);
	if (t < 0) {
		fprintf(stderr, "opps!\n");
	}
	else if (t == 0) {
		char* child = "imchild";
		ww(fd, 100, child);
	}
	else {
		char* parent = "imparent";
		ww(fd, 100, parent);
	}
}

7

Write a program that creates a child process, and then in the child closes standard output (STDOUT_FILENO). What happens if the child call sprintf()to print some output after closing the descriptor?

Answer

子进程输出不会显示任何字符。

/*
 *     ____              _    
 *    / __ \____ _____  (_)___
 *   / /_/ / __ `/ __ \/ /_  /
 *  / _, _/ /_/ / /_/ / / / /_
 * /_/ |_|\__,_/ .___/_/ /___/
 *            /_/             
 *           code@rapiz.me
 *          Sat, 27 Jun 2020 17:18:45 +0800
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

typedef long long ll;
void ww(int fd, int count, const char* str) {
	int len = strlen(str);
	for (int i = 0; i < count; i++) {
		write(fd, str, len);
	}
}
int main() {
	int t = fork();
	int fd = open("/tmp/testfile", O_CREAT | O_WRONLY, S_IRWXU);
	if (t < 0) {
		fprintf(stderr, "opps!\n");
	}
	else if (t == 0) {
		close(STDOUT_FILENO);
		printf("I'm child\n");
	}
	else {
		printf("I'm parent\n");
	}
}

8

Write a program that creates two children, and connects the standard output of one to the standard input of the other, using the pipe() system call.

/*
 *     ____              _    
 *    / __ \____ _____  (_)___
 *   / /_/ / __ `/ __ \/ /_  /
 *  / _, _/ /_/ / /_/ / / / /_
 * /_/ |_|\__,_/ .___/_/ /___/
 *            /_/             
 *           code@rapiz.me
 *          Sat, 27 Jun 2020 17:43:17 +0800
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
typedef long long ll;
int main() {
	int pipefd[2];
	pipe(pipefd);
	int t = fork();
	if (t < 0) {
		fprintf(stderr,"opps\n");
	}
	else if (t == 0) {
		const char* str = "I'm child one";
		write(pipefd[1], str, strlen(str)); 
	}
	else {
		printf("I'm parent\n");
		int t2 = fork();
		if (t2 == 0) {
			const int LEN = 100;
			char buf[LEN];
			read(pipefd[0], buf, LEN); 
			printf("I'm child two and read: %s\n", buf);
		}
	}
}

VM Intro

/*
 *     ____              _    
 *    / __ \____ _____  (_)___
 *   / /_/ / __ `/ __ \/ /_  /
 *  / _, _/ /_/ / /_/ / / / /_
 * /_/ |_|\__,_/ .___/_/ /___/
 *            /_/             
 *           code@rapiz.me
 *          Sat, 11 Jul 2020 09:11:04 +0800
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef long long ll;
int main(int argc, char** argv) {
	if (argc != 2) {
		fprintf(stderr, "Invalid arguments");
		return 1;
	}
	int size = atoi(argv[1]);
	printf("%d\n", size);
	char* p = malloc(size);
	for (int i = 0; i < size; i++) {
		p[i] = 1;
	}
	printf("done\n");
	sleep(10);
}

只有使用过的内存才会被分配。

VM API

  1. SIGSEG 程序终止
  2. pass
  3. pass
  4. Memory leak
  5. pass
  6. Invalid read 程序继续运行
  7. Invalid free. SIGABRT 程序终止

VM Swap

  1. 没看到 user time 有明显变化。。sys time 倒是增加了
  2. 因为内存够大所以我禁用了swap。swpd 上啥都看不到。 free 的变化量反映了 ./mem 收集的