我正在学习一门操作系统课程,我们必须在xv 6中实现dup2()
。我编写的代码理论上应该可以工作,但是,当我尝试执行测试时,它并没有通过所有测试。
这是我的系统调用:
int sys_dup2(void) {
int oldfd, newfd;
struct file *oldf, *newf;
struct proc *curproc = myproc();
if (argfd(0, &oldfd, &oldf) < 0)
return -1;
if (argfd(1, &newfd, &newf) < 0)
return -1;
if (oldfd == newfd)
return newfd;
if (newfd != 0)
fileclose(newf);
filedup(oldf);
curproc->ofile[newfd] = oldf;
return newfd;
}
未通过的测试包括:
if (dup2 (1,4) != 4)
printf (2, "dup2 not working with existing fd.\n");
printf (4, "This message outputs on terminal.\n");
if (dup2 (4,6) != 6)
printf (2, "dup2 not working with existing fd (2).\n");
我认为这个问题与argfd()
有关,因为当我尝试用GDB调试时,我发现oldfd
等于某个随机数。
这是xv 6的argfd()
:
static int
argfd(int n, int *pfd, struct file **pf)
{
int fd;
struct file *f;
if(argint(n, &fd) < 0)
return -1;
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
return -1;
if(pfd)
*pfd = fd;
if(pf)
*pf = f;
return 0;
}
我留下xv 6的函数argint()
、fetchint()
和filedup()
,以便更好地理解上面的代码。
第一个
感谢您的帮助!
1条答案
按热度按时间06odsfpq1#
无论
newfd
是否打开,dup2(oldfd, newfd)
都应该工作。在我看来,如果使用未打开的文件描述符调用argfd
,argfd
将失败(假定myproc()->ofile
表中的相应条目为空),在这种情况下,您的函数只返回-1,这是错误的。所以你不能用argfd
来验证newfd
参数。也许有其他的标准函数可用,或者你只需要自己做同样的检查。测试中并不清楚fd 4是否应该已经打开(“现有fd”是指旧的还是新的?),但如果不是,那么看起来您的实现确实会失败。
测试
if (newfd != 0)
看起来也是错误的; 0是一个有效的文件描述符(标准输入),所以不应该区别对待。事实上,每次在shell中使用<
输入重定向时,都需要使用dup2(fd, 0)
。我不确定您在这里输入什么,但当您重新进行验证时,它可能无论如何都要更改。最后,我不知道xv 6的并发和线程规则是什么,但我担心竞争和TOCTOU错误。在检查文件描述符的有效性/状态和执行实际工作之间,您没有任何锁。
如果这个进程的另一个线程在您测试
oldfd
或newd
后关闭它,并释放struct file
,那么您的struct file *
就是悬空的。dup2
操作应该是原子的,因此另一个线程中的write(newfd, data, sz)
应该写入原始的newfd
或复制的oldfd
,但不应该在EBADF
时失败。如果写操作发生在fileclose(newf)
和curproc->ofile[newfd] = oldf;
之间的窗口中,则代码中会出现这种情况。