Chinaunix

标题: <<APUE>>--Exercises 3.2 [打印本页]

作者: balabalacha    时间: 2006-05-18 20:40
标题: <<APUE>>--Exercises 3.2
3.2
Write your own function called dup2 that performs the same service as
the dup2 function we described in section 3.12,without calling the
fcntl function. Be sure to handle errors correctly.


  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <unistd.h>
  4. int
  5. my_dup2(int oldd,int newd)
  6. {
  7.     int fd;
  8.     if(oldd==newd){
  9.         return (-1==(fd=dup(oldd)))?-1:close(fd),oldd;
  10.     }else{
  11.         if( (-1==lseek(newd,0,SEEK_CUR)) && (errno==EBADF) ){
  12.             close(newd);
  13.         }
  14.         if(newd != (fd=dup(oldd))){
  15.             if(fd ==  -1){
  16.                 return -1;
  17.             }else{
  18.                 int fd1;
  19.                 if(newd != (fd1=my_dup2(oldd,newd))){
  20.                     close(fd1);
  21.                 }
  22.             }
  23.         }
  24.     }
  25.     return fd;
  26. }


  27. int
  28. main(void)
  29. {
  30.     int fd;
  31.     if(-1==(fd=my_dup2(1,5))){
  32.         perror("5555555");
  33.         exit(-1);
  34.     }
  35.     write(5,"hahahahahahahaha",17);

  36.     exit(0);
  37. }
复制代码




请问这样写的my_dup2有问题吗?

[ 本帖最后由 雨丝风片 于 2006-5-21 09:03 编辑 ]
作者: gvim    时间: 2006-05-18 21:33
我没有看这个练习,不过,题目允许可以用dup吗?
另外,好像逻辑有错吧?如果my_dup2(10,5)可以运行吗?
作者: balabalacha    时间: 2006-05-18 22:03
原帖由 gvim 于 2006-5-18 21:33 发表
我没有看这个练习,不过,题目允许可以用dup吗?
另外,好像逻辑有错吧?如果my_dup2(10,5)可以运行吗?



题目只不允许fcntl,没不让dup


my_dup2(10,5)将会在这 if( (-1==lseek(newd,0,SEEK_CUR)) && (errno==EBADF) ){
里退出返回-1
perror输出Bad file descriptor


我也觉得逻辑很差,思路还没理顺过来,我再想几天看看
作者: gvim    时间: 2006-05-18 22:06
呵。 你是怎么试验的?
你首先要有fd=10啊。
作者: balabalacha    时间: 2006-05-18 22:12
我写了段这个,输出了字串  @.@


  1. 28
  2.      29 int
  3.      30 main(void)
  4.      31 {
  5.      32     int fd;
  6.      33     if(-1 == (fd=dup2(2,10))){
  7.      34         perror("error");
  8.      35         exit(-1);
  9.      36     }
  10.      37     if(-1==(fd=my_dup2(fd,5))){
  11.      38         perror("5555555");
  12.      39         exit(-1);
  13.      40     }
  14.      41     write(5,"hahahahahahahaha",17);
  15.      42
  16.      43     exit(0);
  17.      44 }
复制代码

作者: 雨丝风片    时间: 2006-05-19 08:51
还要用递归?你再看看dup2的要求和dup的特性,在纸上画画图,理一理思路。

另外,如果你能够确定你的程序的合法值范围,那就应该适时地给出错误信息并终止程序,而不应该让它(至少从代码本身来看有可能)继续运行下去。
作者: ocean390    时间: 2006-05-19 11:03
这是网上的一种写法,检验old fd,没有用lseek,直接dup,然后检查返回值
  1. int dup2(int oldd, int newd) {
  2.         int fd;

  3.         /*
  4.          * First of all, check the parameters.
  5.          */
  6.         if(oldd < 0 || newd < 0) {
  7.                 errno = EBADF;
  8.                 return -1;
  9.         }

  10.         /*
  11.          * Duplicate the file descriptor.
  12.          */
  13.         fd = dup(oldd);
  14.         if(fd == -1)
  15.                 return -1;

  16.         if(fd == newd)
  17.                 return 0; /* Plain luck */

  18.         /*
  19.          * If the new fd is larger then the newd,
  20.          * it means that by closing the newd we
  21.          * guarantee that the new dup() will open
  22.          * it with the newd index.
  23.          */
  24.         if(fd > newd) {
  25.                 close(fd);
  26.                 close(newfd);
  27.                 fd = dup(oldd);
  28.                 assert(fd == newfd); /* reasonable */
  29.                 return fd;
  30.         }

  31.         /*
  32.          * Do it recursively.
  33.          */
  34.         newd = dup2(oldd, newd);
  35.         close(fd);
  36.         return newd;
  37. }
复制代码

作者: balabalacha    时间: 2006-05-19 14:01
果然清晰:)

那不要递归是不是还要找个空间存放dup出来的fd,最后再close就行了?
作者: 雨丝风片    时间: 2006-05-20 08:17
原帖由 balabalacha 于 2006-5-19 14:01 发表
果然清晰:)

那不要递归是不是还要找个空间存放dup出来的fd,最后再close就行了?


俺很少使用递归算法,不过这道题确实用递归比较简练一些。
作者: balabalacha    时间: 2006-05-20 09:36


我看了一下dup2.c是调用fcntl的,而fcntl是_fcntl的,
里面好似.........看木懂  --.--

  1. case F_DUPFD:
  2.                         /*
  3.                          * Get the file descriptor that the caller wants to
  4.                          * use:
  5.                          */
  6.                         oldfd = va_arg(ap, int);

  7.                         /* Initialise the file descriptor table entry: */
  8.                         if ((ret = __sys_fcntl(fd, cmd, oldfd)) < 0) {
  9.                         }
  10.                         /* Initialise the file descriptor table entry: */
  11.                         else if (_thread_fd_table_init(ret) != 0) {
  12.                                 /* Quietly close the file: */
  13.                                 __sys_close(ret);

  14.                                 /* Reset the file descriptor: */
  15.                                 ret = -1;
  16.                         } else {
  17.                                 /*
  18.                                  * Save the file open flags so that they can
  19.                                  * be checked later:
  20.                                  */
  21.                                 _thread_fd_setflags(ret,
  22.                                     _thread_fd_getflags(fd));
  23.                         }
  24.                         break;

复制代码

作者: balabalacha    时间: 2006-05-20 09:58
另外,我还想到:
以7楼的代码为例(我的是错的*^_^*),假设运气好,在这儿成功

  1. assert(fd == newfd); /* reasonable */
  2.                 return fd;
复制代码

而在此之前还经过了N次递归过程,现在由于分到了newfd,程序开始回归,假设回归过程时,另一个进程也使用了dup2来分配newfd,那会造成第一个进程分的newfd被释放(有可能,假设oldd!=newfd),但第一个进程并不知情,仍在回归,直到返回到调用进程,此时调用进程就会出问题

我说的对吗?
作者: 雨丝风片    时间: 2006-05-20 10:15
原帖由 balabalacha 于 2006-5-20 09:58 发表
另外,我还想到:
以7楼的代码为例(我的是错的*^_^*),假设运气好,在这儿成功

  1. assert(fd == newfd); /* reasonable */
  2.                 return fd;
复制代码

而在此之前还经过了N次递归过程,现在由 ...


每个进程都有自己独立的文件描述符空间,互不影响。
作者: gvim    时间: 2006-05-20 10:18
就像num 1 文件符,你dup标准输出之后在自己的进程里关闭它,并不影响其他进程如父层的shell继续输出。
作者: balabalacha    时间: 2006-05-20 10:59
真要命,赶紧弄懂

every process has an entry in the process table
在process table内的process table entry都有一个只属于自己的在自己进程打开的file descriptors的表,不管对这个表内的fd如何,并不影响process table中的其它的process table entry

是这样吗
作者: gvim    时间: 2006-05-20 11:07
看这个逻辑

fork()  --->  fdinit()  ---> newfd = malloc(......)  --->  初始化一些东西。

可以看出来每个进程自己分配的有空间存放这些东西。

当然描述符表还有这两个操作,fdcopy()/fdshare(),分别对应拷贝,共享,上面那个比较简单,意思是关闭fd,fd table清0。
作者: balabalacha    时间: 2006-05-20 11:46
原帖由 gvim 于 2006-5-20 11:07 发表
看这个逻辑

fork()  --->  fdinit()  ---> newfd = malloc(......)  --->  初始化一些东西。

可以看出来每个进程自己分配的有空间存放这些东西。

当然描述符表还有这两个操作,fdcopy()/fdshar ...



还没学到那呢,现在正在看第4章,谢谢各位的指导
作者: 雨丝风片    时间: 2006-05-20 12:37
原帖由 balabalacha 于 2006-5-20 11:46 发表
还没学到那呢,现在正在看第4章,谢谢各位的指导


结合《FreeBSD操作系统设计与实现》一起看。
作者: balabalacha    时间: 2006-05-20 14:09
哦!我找找)




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2