2011年10月31日5:26 KOSAKI Motohiro <kosaki.motohiro / gmail.com>:
>
> akrさん、このコードなんですが、rb_cloexec_dup2(oldfd, newfd)のoldfdとnewfdが一致する可能性は
> あるでしょうか?あるとしたら、どういう動作をすべきと意図しているAPIでしょうか?

公開APIなので、可能性はあり得るでしょう。

動作は、dup2() + CLOEXECをセット、という名前なので、
一致したら、CLOEXECをセットだけがいいかなぁ。

> といいますのも、さいきんglibcのメーリングリストでdup2とdup3とで oldfd == newfd のときの
> 仕様が異なっており、libcのdup2() が システムコールのdup3() を呼ぶようにしてしまったので、
> regressionしたというバグが報告されています。
>
> http://cygwin.com/ml/libc-alpha/2011-09/msg00061.html

なるほど。

% svn diff --diff-cmd diff -x '-u --ignore-all-space -p'
Index: io.c
===================================================================
--- io.c	(revision 33577)
+++ io.c	(working copy)
@@ -239,6 +239,10 @@ rb_cloexec_dup2(int oldfd, int newfd)
 {
     int ret;

+    if (oldfd == newfd) {
+        ret = newfd;
+    }
+    else {
 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
     static int try_dup3 = 1;
     if (2 < newfd && try_dup3) {
@@ -258,6 +262,7 @@ rb_cloexec_dup2(int oldfd, int newfd)
     ret = dup2(oldfd, newfd);
 #endif
     if (ret == -1) return -1;
+    }
     fd_set_cloexec(ret);
     return ret;
 }

> btw, めちゃくちゃ余談なんですが、dup3でEINVALにしてるのは本当にいい仕様なんですかねえ?

dup3 だけの仕様としてみれば悪くないように思えます。
oldfd == newfd かどうかで close の回数が変わってきますから、
いずれその判断はアプリケーション側でやらないといけないでしょう。
どうせやるなら dup3 の前にやることを勧めてもいいのでは。

dup2 の drop in replacement として使いにくいという点との比較については、
どの段階の状況を重視するかですかねぇ。
-- 
[田中 哲][たなか あきら][Tanaka Akira]