[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FDclone-users:00164] Re: {FreeBSD,OpenBSD}/sparc64, IA64(AIX対応その後)



 しらいです。

In Message-Id <03May7.115324jst.119047@inetgw.lightwell.co.jp>
        SHIOTA Shoichi <Shoichi.Shiota@lightwell.co.jp>さんwrites:
> 潮田です。

> >  この本は UNIX の bible なので私も新旧両方持っているのです
> > が、会社に置いてあるために最近忙しくて読めていませんでした。
> > 今朝読んで私もこれが原因かと思いました。
> バイブルですか。
> 購入してみます。

 ソフトバンクから出ていた旧版は絶版になっているので入手不可
能かと思いますが、ピアソンから出ている新装版はまだ普通に売ら
れているので一般の書店でも買うことが出来ます。
 但し、定価 7,800 円と書籍にしてはお高めです。これ以上判り
易い UNIX system call 解説は見たことがないので、値段に見合う
価値はあるかと思いますけど。

# Stevens 本は「UNIX ネットワークプログラミング」もお奨め。
#新装版になって分冊化したので合わせて 12,800 円と馬鹿高くな
#ってしまいましたが。「詳解 TCP/IP」は三分冊なので Vol.1 で
#断念してます :-)


> POSIX の規格書(?)等は持っていないので、 
> 「The Single UNIX? Specification, Version 2」の Web 版を
> ローカルに落としてきて見ているのですが、

 それって次世代 POSIX の draft じゃありませんでしたっけ?こ
の URL で参照出来るヤツですよね?
http://www.unix-systems.org/single_unix_specification_v2/idx/index.html
 現行版は「The Open Group Base Specifications Issue 6」で下
記 URL になると思います。
http://www.opengroup.org/onlinepubs/007904975/nfindex.html

# URL は両方とも index page を指しています。


> > new applications should use sigaction() rather than signal().
> 程度なんですよね。
> signal() も wait3() みたいに LEGACY  とか書いてほしいですね。

 wait3() が waitpid() により完全に置換可能なのに対し、signal()
は依然 sigaction() を用いた library 関数として用意されていま
す。
 これは、単純な置換が出来ないだけでなく、実装が環境依存で一
意な代替関数を用意出来ませんし、wait() family と異なり ANSI
C に記載されている基本関数であることも理由になっていると思い
ます。


> > 	3. ./fdsh で「&」付の back ground job として 2. と同
> > 	   様の検証。
> sleep は 2. と同様。
> 
> echo は、そのままバックで停止したままになる。
> (これは、他の shell でもそうなるので、それで正しいのですよね)
> fg で表に持ってくれば、2. と同様になる。

 echo は端末出力を伴うので SIGTTOU で止められてしまうのかも
知れません。この辺りの挙動は環境依存でしょうね。1., 2. の挙
動に関しては予想通りです。


> > 	4. ./fd で set -b を実行した後 1. と同様の検証。
> 子供の終了時に、正常に FD へ戻ってくる。

 これは 5. で 2. と同様の検証をした場合と同じになる筈なんで
すが、EDITOR や PAGER の場合は返り値の check をしていないの
で、起動さえすれば正常動作しているように見えているだけです。


> > 	5. ./fdsh で set -b を実行した後 2., 3. と同様の検証。
> 2. は、子供の終了後
> ./fdsh: No child processes
> と表示し、 fdsh へ戻るようになる。

 この症状は Linux 以外の各種 OS 環境で再現を確認しました。
signal handler で先に wait してしまうと、子を待ち続けている
mail process では子の終了を捕捉出来ないので、error 表示にな
るだけでなく終了 status も取得出来ません。
 多分、/usr/bin/false 辺りを実行しても常に $? が 0 になって
いるんじゃないでしょうか。これでは実用的ではありませんね。

 SIGCHLD 無限発呼問題は AIX や System V 固有の問題ですが、
set -b は Linux 以外の殆んどの UNIX 環境の問題ですので、この
支障は修正する必要があります。
 最後に 2.03a に対する修正 patch をつけておきます。


> >  これが 7. の patch 適用により全てのケースで解消されるよう
> > であれば、この実装で暫く様子を見てみて下さい。
> patch で問題は解消されているですが、
> ./fdsh: No child processes
> の表示が気になります。

 SIGCHLD 無限発呼の件に関してはこれで解消出来そうですので、
この対処法を適用しようと思います。GW 明けに予定していた 2.03b
ですが、この辺りを整理してから release しますので、一週間ほ
ど遅れると思います。


> ハンドラーの内部で waitpid() しているので、もともと存在する
> wait() が余分になっているぐらいでしょうか。
> (また甘いかな)

 handler が呼ばれた時点で waitpid() に割込みがかかって、こ
の waitpid() は handler が終了し次第 error 終了する運命にあ
るということですね。
 そもそもこの死ぬ運命にある waitpid() が SIGCHLD 無限発呼の
元凶だったかも知れません。つまり、sa_flags |= SA_RESTART し
ていれば、待っている waitpid() が有効になって SIGCHLD を抑制
出来ていたのかも。

 幾つかの OS 環境で試してみたのですが、Linux だけがこの辺り
の挙動が特殊で、一旦名指しで waitpid() をすると、これを中断
して後から waitpid() しても失敗してしまうので、handler 側の
waitpid() の方が ECHILD で返って来るんです。
 やはり「GNU/Linux is Not UNIX」と呼ばれるだけのことはあり
ますね。最近 main 環境を Linux にしてしまっているので、こう
いう非 UNIX 的な挙動に振り回されてしまうことが往々にしてあり
ます。


> >  [FDclone-users:00155] の実験で、sa_flags = SA_RESETHAND |
> > SA_NOCLDSTOP にしてみると無限発呼が解消されたりはしませんか?
> > AIX ではこの併用の効果は無かったようですけど。
> 再度確認のため AIX 5.1.0 で

 いえ、AIX でなく HP-UX で試してみることを提案してみたんで
す。SA_RESETHAND だけが原因だとしたら、signal() を使った時に
SIGCHLD が無限発呼されるのは HP-UX でも同じことだと思うんで
す。
 でも実際には、FDclone の子 process 生成で SIGSEGV で死んで
しまうのは AIX だけでしたよね。HP-UX の場合何が違うのかを考
えると、SA_NOCLDSTOP くらいしか違いはありません。
 なので、SA_RESETHAND だけでは死んでしまう HP-UX 環境でも、
SA_NOCLDSTOP も指定することで signal() と同様の sa_flags に
なって、無事子 process の終了を迎えられるのではないかという
推測です。


> もう一台 HP の WS があるのですが、それでも既に 10.0 に
> なっていました。
> AIX も最初に触ったときに既に 3.2.4 でしたし。
> 古いマシンを抱えているとなると大学ですかね。

 学生さん宜しく。


 では最後に修正 patch です。7. で適用する patch をこれに置
き換えて、改めて 8. の検証を行なってみて下さい。l. 1529 の修
正もお忘れなく。

---- Cut Here ----
diff -u ../old/FD-2.03a/system.c ./system.c
--- ../old/FD-2.03a/system.c	Tue Apr 15 00:00:00 2003
+++ ./system.c	Wed May  7 00:00:00 2003
@@ -2219,9 +2219,16 @@
 #ifdef SIGCHLD
 static int trap_chld(VOID_A)
 {
-# if	!MSDOS && !defined (NOJOB)
-	if (bgnotify) checkjob(1);
-# endif
+# if	!MSDOS
+	if (0);
+#  ifndef	NOJOB
+	else if (bgnotify) checkjob(1);
+#  endif
+#  ifdef	SYSV
+	/* TIPS for obsolete SystemV signal() */
+	else while (waitjob(-1, NULL, WNOHANG | WUNTRACED) > 0);
+#  endif
+# endif	/* !MSDOS */
 	return(trap_common(SIGCHLD));
 }
 #endif
@@ -2649,10 +2656,13 @@
 # ifndef	NOJOB
 	int i, j, sig;
 # endif
+	static p_id_t trappid = -1L;
+	static wait_t trapw;
 	wait_t w;
 	p_id_t tmp;
 	int ret;

+	if (pid >= 0L && wp) trappid = pid;
 	for (;;) {
 # ifndef	JOBTEST
 		tmp = (pid < 0L)
@@ -2687,17 +2797,19 @@
 	if (!tmp) return(0);
 	else if (tmp < 0L) {
 		if (pid < 0L || errno != ECHILD) return(-1);
-		ret = -1;
-# ifndef	NOJOB
-		sig = -1;
-# endif
+		if (!wp || trappid >= 0L) return(-1);
+		memcpy(&w, &trapw, sizeof(w));
+		tmp = pid;
+	}
+
+	ret = (pid < 0L || tmp == pid) ? 1 : 0;
+	if (pid < 0L && tmp == trappid) {
+		memcpy(&trapw, &w, sizeof(trapw));
+		trappid = -1L;
 	}
-	else {
-		ret = (pid < 0L || tmp == pid) ? 1 : 0;
 # ifndef	NOJOB
-		sig = getwaitsig(w);
+	sig = getwaitsig(w);
 # endif
-	}

 # ifndef	NOJOB
 	if (ret >= 0 && (i = searchjob(tmp, &j)) >= 0
---- Cut Here ----

                                               しらい たかし