跳转到内容

讨论:Nachos 2013: Multiprogramming

来自ACM Class Wiki

要怎么知道一个process是否是正常退出的?

A1:The exit status of a process that exits abnormally is up to you.

A2:exit什么值都是正常的,理论上不应该依赖于对于status的值判断是否正常退出。不正常推出主要是指exception或者unknown systemcall。

A3:Nachos就是一个低幼的操作系统。如果真的有什么操作系统不认识的情况出现,操作系统就会崩掉,而不仅仅是进程非正常结束。所以不正常结束,可以视为操作系统知道发生的是什么,但不知道怎么处理。

具体来说,就是操作系统发现出现问题后,他的所有处理方案都不能用,就只能不正常结束了。

A4:“The exit status of the exiting process should be transferred to the parent, in case the parent calls the join system call. The exit status of a process that exits abnormally is up to you. For the purposes of join, a child process exits normally if it calls the exit syscall with any status, and abnormally if the kernel kills it (e.g. due to an unhandled exception).”

举个例子:如果进程还能继续跑,就没有什么能说明它是否在正常跑,也就没有干掉它的理由。只有当进程发现,它无法继续跑了,它就会给操作系统抛个异常。操作系统看到这个异常,就去处理这个异常。如果是操作系统认识的异常,比如open,操作系统就会去做,然后再给进程去做。但如果操作系统不知道怎么处理这个异常,它就有干掉这个进程的理由。这个时候,它才会干掉这个进程。于是干掉子线程并且让父线程知道,就是操作系统需要做的事情。

作为一个进程,他抛异常是因为他做不下去了,让操作系统帮他继续做下去。于是它是不应该知道操作系统能处理哪些问题,不能处理哪些问题的。至于怎么搞死它,只要能让父进程知道你把他儿子搞死了,怎么做都可以。

跑test_exit,test_matmult的时候会出现exceptionReadOnly和exceptionIllegalInstruction

A:For the purposes of join, a child process exits normally if it calls the exit syscall with any status, and abnormally if the kernel kills it (e.g. due to an unhandled exception).

stdin stdout要上锁吗?

A1:Do not implement any kind of file locking; this is the file system's responsibility.

A2:看UserKernel.console.openForReading()的实现。另外Nachos的每个进程都只有一个线程。

lotteryScheduler里pickNextThread的时候是自己随机一个数,然后随便选个priority比这个数大的thread吗?

A:[n1,n2,n3,n4,n5]

假设上面是一个队列中各个线程持有的彩票的数量,一种实现方法是产生一个1-(n1+n2+n3+n4+n5)之间的随机数,然后这个随机数落到哪个区间就选择哪个线程。

测试的话,比如一个线程还在等待锁,你让它运行了,当然是不可以的,但是一个有两张彩票,一个有3张彩票,哪个到底下一个运行,我们是没法测的。但是后面的phase3中,你的lotteryScheduler如果有问题,很可能会超时。

操作系统自身的内存使用是由谁管里的?

Q:操作系统本身有很多数据结构,队列啊什么。我们好像想建一个队列就建一个,而它们好像是游离在整个内存区域之外的。但是操作系统的这些数据结构的存储也应该是在内存里啊。那它们是由谁怎么管理的?

A:Nachos是运行在jvm上的,不是运行在硬件之上的,和真实的操作系统有区别。

Phase 2该如何运行?

Q:Phase 2该如何运行啊?我无论设置什么coff,比如-[] nachos-sjtu/conf/proj2.conf -- nachos.ag.CoffGrader -x hello.coff,结果都是

Testing the console device. Typed characters

will be echoed until q is typed.

然后就卡住了,输了q也没什么用。求问这是什么情况?

A:把UserKernel.selfTest()的内容注释掉。

test_files3

如果有人跟我一样苦逼地在调test_files3的话。。。友情提示一下,如果运行完了,如果一个苦逼的on_the_fly_delete还存在在test文件夹里的话,要苦逼地将它手动删掉。。。

反正我是在它把自己删掉之前程序就跪了,没等到它把自己删掉。。导致后来再跑都提前跪了。。。T.T

对于test_file的一点声明

linux 和 windows不同的区别让我们注意到:

A stub file system interface to the UNIX file system is already provided for you

所以实际情况应该是:

对于大部分操作win和linux是一致的,但对于unlink这个操作两边不一致。

很多涉及unlink的问题,在linux下很可能就是完全正确的,但在win下评测,被评测为错误。

在handleExit里加一句 coff.close();

没过test_file2的同学在handleExit里加一句 coff.close();

grader_user1.coff的运行参数是什么?

A:用到的是: -[] conf/proj2.conf -- nachos.ag.UserGrader1 -x grader_user1.coff

所有测试用的都是pre里APhase2的内容。

关于shCXR.coff

Q:它是新建了几个process跑,没有用join,然后主程序exit了。 这时候是应该等那几个在后台跑的process跑完还是主程序跑完就halt?

A:最后一个process结束的时候负责关机

怎么把输出里面一大堆汇编去掉?

A:把参数里的-d ma去掉就行了

File名字最长是多少?

Q:那些filename 是 char *,我想用readVirtualMemoryString读出来,那设置的maxLength应该是多少?

A:'User processes store filenames and other string arguments as null-terminated strings in their virtual address space. The maximum length of for strings passed as arguments to system calls is 256 bytes. '

印象中从来没有考虑过文件名大于256的情况。。。

phyPageNum大小需要多少?

A:对于不同的测试点,会有不同的Configure需求,每个Phase都是这样。

在phase2里,至少要开到256才能保证样例数据。

一个文件可以多次open?

A:以下结论仅供你们参考

1. creat返回的fd是可读写的,不必要再open一次;

2. 但是creat之后再open也是允许的。换句话说,一个文件允许被open多次;

3. 既然允许被open多次,就允许被close多次,比如下面的代码合法:

int fd1, fd2;

fd1 = create("test");

fd2 = open("test");

close(fd1);

close(fd2);

 这里的fd1和fd2是否相同,取决于你们实现。我当时是返回不同的fd;

4. 允许多个进程对同一个文件读写。这在主流操作系统也是允许的(主流操作系统在open的时候大多可以指定是否与其他进程共享这个文件;但是nachos比较简陋,可以认为永远允许)。但是同时读写产生的结果是未定义的;

5. 上面这条的意思是说同时读写同一个文件,read和write可以返回以任意顺序进行读写的返回值,但是不可以造成对文件系统的破坏。这是要在文件系统里做的。

exit和join的调用顺序,以及传递status的机制

Q:刚才看了\test\syscall.h,有一个问题求问助教:

关于void exit(int status)和int join(int pid, int *status)

这里面两句话看得我一头雾水:

在exit的注释里有句话:

status is returned to the parent process as this process's exit status and can be collected using the join syscall.

在join的注释里有句话:

status points to an integer where the exit status of the child process will be stored. This is the value the child passed to exit().

本来对join还是比较清楚的,看完这段就什么都不懂了。。。助教能否解释一下exit和join的调用顺序,以及传递status的机制?

A:当调用join的时候,父线程停止运行,子线程运行,子线程运行完了,父线程当然是从join处接着运行,join的地方发生了线程的切换,status可以设置一个父线程子线程都认识的地方存就行了。

请问怎么给测试程序加参数?

Q:比如echo.c中argc和argv是如何提供的?

A:注意在UserKernel中Run()过程Lib.assertTrue(process.execute(shellProgram, new String[] { }));

这里可以传递参数,但从外部Nachos直接传参数是不行的

评测时直接在c中将参数写入后编译成coff,保证测试数据中不含参数,也不会改动你们的程序

handleExec(....)打开的可执行文件,要不要用一个descriptor记录下来?

A:不要,这不是打开文件,这是load程序代码

如果一个文件被同一个进程open了两次,那么第二次open应该返回什么?

Q:1. 如果一个文件被同一个进程open了两次,那么第二次open应该返回什么?-1?旧的描述符?还是新的描述符?这里假设两次打开都成功;

2. 要是把上面问题中的任何一个或者两个open替换成creat,结果也是一样的吗?

A:1.在phase2不需要关心这个问题,因为你是直接调用filesystem,filesystem返回什么你就把它返回给用户。不必检查是否文件已经打开过。

2.同上

总结一下测试几个coff的方法

1. 确保你的framework是最新的( 其实是因为AutoGrader升级了 )

2. 建立test文件夹,使得其与你的工程nachos-sjtu在同一级文件夹(即保持svn的目录结构,如果本来就用svn目录结构的同学就不用管了)

不想使用原有test路径的同学,需要在conf里添加FileSystem.testDirectory,同时运行时要在 -#后添加参数testRoot。

注意: 如果不这样做的话你不仅要设定FileSystem.testDirectory还要改CoffGrader的路径处理,否则找不到*.out

3. 将test-case-preview/phase2/testcases中的所有文件不带目录地copy到那个test文件夹里,同时确保nachos-framework/test里的文件(*.c啊*.coff啊什么的)也都在test文件夹里

4. 测试: -- nachos.ag.CoffGrader -[] YOUR_CONFIGURE_FILE_PATH -x TEST_GRADER [ -# output=STANDARD_ANSWER_FILE ]

Example: -- nachos.ag.CoffGrader -[] conf/proj2.conf -x test_matmult.coff -# output=test_matmult.out

注意: --后面有空格!!!output是指标准答案文件,用来比较的,不是用来输出到文件的。。。

Reference:

[1]. XiaoJia - 关于运行phase2的preview testcases的一点心得(?)。。。

preview的testcase里,sample.sh里是不是拼写错误了

Q:

matmult
echo 123
matmult &
matmult &
matmult &
matmult &
matmult &
exut
exit
end

倒数第三行和倒数第二行差距比较大啊,是故意而为之?

A:这个是故意的。正确情况就应该是exec failed。

exut.coff这个文件是不存在的,所以不能执行,所以你的nachos需要容忍这种情况,但又不影响其他程序。


用户的进程认为他虚地址空间是无限大的吗?

A:不是无限大,是足够大。在这里就是物理内存的大小,phase3就是虚拟内存的大小

如果一个新创建的进程所需要的页表数当前的物理内存不能满足,那么要不要执行换页操作?

A:不需要,phase3的内容,这里只需要假设内存够大就行了

一个UserKernel在一次simulate中只会有一个吗?

A:对

如果父进程exit了,那么要让所有的子进程exit吗?

A:spec目前没有要求,那就应该不会有这样的数据

PS:你们可以多看看Processor里面的函数,有些比较有用的,比如pageFromAddress等。

hint: 在UserProcess.loadSections()里面有一行注释,// for now, just assume virtual addresses=physical addresses,这里是要初始化pageTable的。

hint2: 注意在分配内存的时候的同步性问题。

创建文件的时候用不用考虑文件名重名的问题?

A:在phase2你只需要调用filesystem,你不用实现filesystem,所以不需要care这个,因为你并不实现创建文件的逻辑

每个进程包含一个还是多个线程?

A:在nachos里是单线程

standard input and standard output被关闭后,0和1两个文件描述符其他文件还能用吗?

A:应该是不能用的吧。。。不过没有这么bt的数据吧

能不能解释一下coff是怎么回事?

A:coff就理解成exe吧,或者是汇编代码,ld a(b), r1; add r1 r2 r3之类的,Processor会解释他们并进行计算。

create一个文件后要不要在进程中保留下来?也就是要不要给它个文件标识符?

Q:看Nachos代码中的comment似乎是要返回文件标识符的

不过在cp.c中

creat(argv[2]);
dst = open(argv[2]);
......
close(dst);


如果create要在进程中保存文件对象的话,那么程序中并没有close这个文件对象将会导致这个文件不能被删除

所以我个人感觉不需要为create在进程中保存下文件对象,不知是不是这样?

A:syscall的语义请严格按照syscall.h中的specification实现

"Returns the new file descriptor, or -1 if an error occurred."

用户程序如何写不能作为参考标准,但有一点:只要程序合法,你不能让他crash

比如你说的cp.c先creat再open,这个没有问题,哪怕open很多此也没有问题,一直不close也没有问题,因为OS要负责在进程退出时回收所有资源(file descriptor table, file table entry等)

我们只能表示这样的程序写的不好,会在退出之前占用不必要的资源(遗憾的是事实上这种程序遍地都是……)