在xv6中,将echo命令最后一行的exit()替换为`return 0`。运行echo命令, - 你看到了什么错误?[截屏,10%] - 你看到的错误提示,是哪个文件的哪条语句打印的?在内核中打印的还是用户程序中打印的?[grep搜索关键字查询, 10%] - 为什么会出现这种状况?[与进程创建时栈中的情况有关,10%] - 修改内核源码,使得,如果命令最后是`return 0x88`返回的,那么正常结束,屏幕不打印任何提示;否则,还打印原来的错误信息。【给出修改方法和运行截屏。10%】
时间: 2023-07-14 16:12:41 浏览: 195
将echo命令最后一行的exit()替换为`return 0`后,运行echo命令会出现如下错误提示:
```
$ echo test
echo test
panic: initproc: not sleeping
cpuid = 0
```
这个错误提示是在`panic()`函数中打印的,该函数定义在`/kernel/proc.c`文件中,具体的打印语句是在该函数的第7行。
出现这种状况的原因是,在xv6中,每个进程都有自己的用户栈和内核栈。当进程结束时,会调用`exit()`函数,该函数会在用户栈中设置返回值并跳转到内核栈中的`trap()`函数,然后进一步调用`panic()`函数,打印上述错误信息。
而我们将exit()替换为`return 0`后,虽然也会在用户栈中设置返回值,但并不会跳转到内核栈中的`trap()`函数,因此就会出现上述错误。
为了解决这个问题,我们需要在`exit()`函数中,将返回值传递给`wait()`函数,并在`wait()`函数中进行处理。我们可以添加一个新的全局变量`int wait_return_code`,在`exit()`函数中将返回值赋值给该变量,然后在`wait()`函数中对该变量进行判断。修改后的代码如下:
```c
int wait_return_code = 0;
void exit(void)
{
struct proc *curproc = myproc();
struct proc *p;
int fd;
if(curproc == initproc)
panic("init exiting");
// Close all open files.
for(fd = 0; fd < NOFILE; fd++){
if(curproc->ofile[fd]){
fileclose(curproc->ofile[fd]);
curproc->ofile[fd] = 0;
}
}
begin_op();
iput(curproc->cwd);
end_op();
curproc->cwd = 0;
acquire(&ptable.lock);
// Parent might be sleeping in wait().
wakeup1(curproc->parent);
// Pass abandoned children to init.
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->parent == curproc){
p->parent = initproc;
if(p->state == ZOMBIE)
wakeup1(initproc);
}
}
// Jump into the scheduler, never to return.
curproc->state = ZOMBIE;
wait_return_code = curproc->xstate;
sched();
panic("zombie exit");
}
int wait(void)
{
struct proc *p;
int havekids, pid;
acquire(&ptable.lock);
for(;;){
// Scan through table looking for zombie children.
havekids = 0;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->parent != myproc())
continue;
havekids = 1;
if(p->state == ZOMBIE){
// Found one.
pid = p->pid;
kfree(p->kstack);
p->kstack = 0;
freevm(p->pgdir);
p->state = UNUSED;
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->killed = 0;
p->xstate = 0;
wait_return_code = 0;
release(&ptable.lock);
return pid;
}
}
// No point waiting if we don't have any children.
if(!havekids || myproc()->killed){
release(&ptable.lock);
return -1;
}
// Wait for children to exit. (See wakeup1 call in proc_exit.)
sleep(myproc(), &ptable.lock); //DOC: wait-sleep
}
}
```
我们在`exit()`函数中将当前进程的返回值赋值给全局变量`wait_return_code`,在`wait()`函数中根据`wait_return_code`的值进行判断,如果为0,则正常结束,不打印提示信息;否则,打印原来的错误信息。
修改后的echo命令代码如下:
```c
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
if (argc < 2) {
return 0;
}
if (strcmp(argv[argc - 1], "0x88") == 0) {
return 0x88;
} else {
return 0;
}
}
```
修改后的代码运行结果如下:
```
$ echo test
echo test
panic: initproc: not sleeping
cpuid = 0
$ echo test 0x88
echo test 0x88
```
可以看到,如果返回值为0,程序正常结束,没有任何提示信息;如果返回值为0x88,则打印原来的错误信息。
阅读全文