どうにか回復。そして日付け越え。
snapshotの10/30版が出ていたのでダウンロード。
眠くて死亡。
ダウンロード完了後、configure&makeを仕掛けて再死亡。
回復できず、もう一回休み。昨日より悪くなっている感じ。
ぐったりしながらCygwinの最新版を探った所、置かれていたようなので
ダウンロード。先日失敗したgccも何故かうまくダウンロードできる
所が謎。
で、注目のfork問題が直っているかという所ですが、取りあえず
エラーするかという所は置いといて、
以前書いたテストを試してみたのですが、Winが固まる
(正確には固まったかのような遅さ)現象は変わらず。
10月23日付けのsnapshotをダウンロードしてmakeしてみたのですが、
newlibのコンパイルでコンパイルエラー。
風邪で一回休み。一日寝て過ごすけどあまりよくならず。
mmapの件、冷静に考えてみますにホストOSでネイティブにmmap()を
実行するのはダメダメですよ。アドレスを取得したところで、
シミュレーションコアはシミュレータメモリしかアクセスできない
のですから。
で、シミュレータメモリをブロック管理して、開放ができる様に
してみました。でも、結局NGという事が判明。
2MB確保→1MB開放→2MB確保→1MB開放→....を繰り返している
ようで、結果、開放された1MBの穴は埋められる事なくどんどん
穴だらけになって行き、最後はメモリ領域不足になってしまうと
いう感じ。それにしても、少しくらい使えば良いのに2MB確保後、
すぐに1MB開放しているっぽいところが納得いかんです。
Cygwinの新しいのをダウンロードしようとするも、最新は
まだ国内のサーバーに置かれておらず。一つ前のをダウンロード
しようとした所、何故かgccのダウンロードができず。gccの
パッケージを100%取った所で、そのまま無反応状態。でも
キャンセルは可能。なんでや。
日付け越え。
gccのPPCネイティブに自力コンパイル。自力というのは、ソース自動生成
を行うgen*系の実行をppcsimを使って行ってみるというもの。
insn-attrtab.cの生成がうまくできなくてNG。メモリが足りなくなって
いるみたい。
gcc> make insn-attrtab.c ppcsim -L -a ./genattrtab.exe ../../gcc/config/rs6000/rs6000.md > tmp-attrtab.c Cannot allocate 16 bytes after allocating 4025954124 bytes
10031bd0:Syscall_NO=90 mmap(00000000,00200000,00000000)===> ret(0x00404000) 10031be0:Syscall_NO=91 munmap(0x00404000,0x000fc000) 10031be0:Syscall_NO=91 munmap(0x00600000,0x00004000)
昼頃起床。かなり微妙な体調。
ここ二週間の確認結果を元に、クロスツールのビルド方法をまとめて
みました。御参考まで。
何気にネイティブツールを生成する為に、先日の方法で
binutilsをconfigure/makeしてみたり。.exeが付くのがアレですが、
エラー無くネイティブPPC実行ファイルの生成に成功。
gas/as-newを実行してみた
所、UnknownSyscall(77)。_getrusage()。なんだこりゃ?infoを
みてみると、
- Function: int getrusage (int PROCESSES, struct rusage *RUSAGE)
This function reports resource usage totals for processes
specified by PROCESSES, storing the information in `*RUSAGE'.
binutils> ~/develop/ppcsim/src/ppcsim.exe -L PPC> exec objdump.exe -d objdump.exe
ppcsim.exe -L -a objdump.exe -d strip-new.exe > foo.dis
昼過ぎ起床。なんかまた調子悪げ。でも休出。
PPCクロスbinutils,gcc,glibcをクリーンインストールするテスト。
最初からやるとほとんどまる一日かかるような感じ。
glibcビルドの為のパッチを生成したり。確認したり。
何気にIJGのjpegツールをconfigureから実行してみたり。
AR=powerpc-linux-ar CC=powerpc-linux-gcc RANLIB=powerpc-linux-ranlib ./configure make
日付け越え。
先日のgcc-3.2の再ビルドは結局失敗。glibc-2.3.1pre2と同じエラー。
結論。glibc-2.2.2をどうにかコンパイルして使用する以外の選択肢は
今の所無さそう。
うーん、クロス環境のbuildについてまとめようと確認するのに
二週間くらいかかってしまってこれかよって感じ。まぁ、しかた無し
とした所か。
日付け越え前に帰着。
elf/dl-machine.cのコンパイルでエラー。それを例のごとく修正すると、
あとはエラー無しでコンパイル完了。make installでinfoのインストール
に失敗したので、それも適当に直してインストール完了。
gcc-3.2の再ビルド中。
終らず。
日付け越え前に帰着。
glibc-2.2.2とglibc-2.3.1pre2とで、locale.ccをコンパイルした
時、問題の__ctype_bの違いの部分は以下の通り。
# 81 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3 | # 75 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3
extern __const unsigned short int **__ctype_b_loc (void) | extern __const unsigned short int *__ctype_b;
__attribute__ ((__const)); | extern __const __int32_t *__ctype_tolower;
extern __const __int32_t **__ctype_tolower_loc (void) | extern __const __int32_t *__ctype_toupper;
__attribute__ ((__const)); | # 91 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3
extern __const __int32_t **__ctype_toupper_loc (void) <
__attribute__ ((__const)); <
日付け越え。
glibc-2.2.2をインストールしてgcc-3.2をbuildしてみると、やはり
libc++のmakeには成功する模様。で、glibc-2.3.1pre2でずっこけた
locale.ccをコンパイルするところを見てみたところ、少し様子が違っている
模様。-E付きでプリプロセッサを通した後のソースを見てみると、
# 75 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3
extern __const unsigned short int *__ctype_b;
extern __const __int32_t *__ctype_tolower;
extern __const __int32_t *__ctype_toupper;
:
<中略>
:
# 43 "/tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-li
nux/bits/ctype_noninline.h"
const ctype_base::mask*
ctype<char>::classic_table() throw()
{ return __ctype_b; }
Changes since 1.4: +47 -28 lines
Diff to previous 1.4 (colored)
2002-09-01 Roland McGrath <roland@redhat.com>
* ctype/ctype.h (__ctype_b, __ctype_toupper, __ctype_tolower):
Variable declarations removed.
朝起きると状態悪化。一回休み。
gcc-3.2のbuild失敗の件。
libstdc++-v3/src/locale.ccのコンパイルで、
In file included from ../../../../libstdc++-v3/src/locale.cc:406: /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h: In static member function `static const short unsigned int* std::ctype<char>::classic_table()': /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:45: ` __ctype_b' undeclared (first use this function) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:45: (Each undeclared identifier is reported only once for each function it appears in.) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h: In constructor `std::ctype<char>::ctype(int*, const short unsigned int*, bool, unsigned int)': /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:61: ` __ctype_toupper' undeclared (first use this function) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:61: ` __ctype_tolower' undeclared (first use this function)
37 #if _GLIBCPP_USE_SHADOW_HEADERS
38 using _C_legacy::__ctype_toupper;
39 using _C_legacy::__ctype_tolower;
40 using _C_legacy::__ctype_b;
41 #endif
42
43 const ctype_base::mask*
44 ctype<char>::classic_table() throw()
45 { return __ctype_b; }
昼頃起床。休出。
glibc-2.3.1pre2 という奴を拾ってコンパイルしてみました。
elf/dl-machine.cに手を入れる必要がありましたが、その他
でコンパイルエラーをする事は無く、結果的にはこれが一番
良さそう。でも、make installすると、infoの生成でエラーして
installに失敗したり。infoのinstallだけをすっ飛ばして
取りあえずインストール完了。結局、手放しでbuildできる
glibcは世の中に存在しないみたい。
そういや、時々shellが気を失って無反応状態になることが
あるらしく、configureやmake実行を放置しておくと、途中で
止まっている事がありました。forkコードに改造を入れたのが
関係しているのかは不明。
で、glibcのインストールよりも、問題はgccの再ビルドが
うまくできるかという点。.......
失敗(涙; うーむ。
KOJIさんと長電話。
メモ。文字で書くと意味がすぐ取れないなぁと思ったので
気を付けようと思った言いまわし。「○○でない」は
否定の意味「○○ではありません」として受け取れそう。では、
「○○でない?」は否定の意味で疑問形「○○ではないのではなかろうか?」
でしょうか?
それとも肯定の意味で同意を求める疑問形「○○なのではなかろうか?」
でしょうか?
昼頃起床。休出。
glibc-2.2.5のmakeで、misc/syslog.cのコンパイルがずっこける方を調査。
どうやら、/sysdeps/generic/bits/libc-lock.h内で定義
しているマクロが、2.2.2ではただの空マクロになっているのですが、
2.2.5では実体が書かれていて、それだとエラーしてしまうと
いう事みたいです。私自身がよく使う「直したら壊れた」という
状態になっているっぽい。
touch syslog.o で先に進めたところ、nss/nsswitch.cのコンパイル
エラーが発生。結局2.2.2と同じ話があるようですが、
2.2.2ではsyslog.cのコンパイルではエラーしなかったので、
2.2.5はやっぱNG。
風邪で急速に体が動かなくなってきたり.........
日付け越え。
以前makeに成功したglibc-2.2.2のgnu/lib-names.hの中身を見てみると、
sharedライブラリ関係臭かったので、--disable-sharedを外すと
gnu/lib-names.hを生成してからコンパイルを開始するという
仕掛けになっているようでした。取りあえずコンパイルが開始される
所で一度止めて、--disable-sharedを付けて再度configure&make
を実行する事で、nss/nsswitch.cのコンパイルはOKとなりました。
次に突っかかるのは、elf/dl-machine.cのコンパイルで、これは
以前直した方法で
乗り越え。それ以外で突っかかることは無くmakeは終了。
うーむ、手を入れなきゃいけないのが面倒臭い.......
何気にCygwin関連サイトをぐるぐるしていたら、
rxvtの日本語パッチ関連サイトに行きつきました。
rxvt-2.7.xベースになっているのが良い感じ。他にも色々不具合
が修正されているようです。ただ、デフォルトフォントが明朝
になっていて、私的に少々読みにくく感じたのでフォントを変更
しようとしたのですが、フォント名の指定の仕方がよくわからず。
うーむ。
一回休み。
gcc-3.2の方はconfigureに--disable-sharedを追加したら取りあえず
エラー無しにmake成功。
で、glibcのmakeを行う事にしましたが、glibc-2.2.2ではgcc-3.2には
正式に対応していないので、glibc-2.2.5をダウンロードしてconfigure
スクリプト内をチェックしてみました。3.xの文字列を引っ掛けて
いるようなので、一応対応されている模様。で、configure/makeを
実行した所、2.2.2で問題となったnss/nsswitch.cのコンパイルよりも
手前misc/syslog.cのコンパイルでコンパイルエラーになってヘコリ。
しかた無いので、2.2.2のconfigureを少し直す事して、nss/nsswitch.c
のエラー原因を探る事に。
先日の様に、
単純にgnu/lib-names.hが無くてエラーしているだけなのですが、
本当に存在していません。しかし、以前コンパイルしたものでは
ちゃんとgnu/lib-names.hが生成されているようなので、何か
手順が抜けていると思われます。うーむ。
日付け越え前に帰着。
glibcのmakeをそのままほっといたのですが、空ファイルを作った
nsswitch.oの影響と思われるリンクエラーでずっこけ。でも、
gcc-2.95.2でコンパイルしていたから.exeの付くppcネイティブ
バイナリが生成されるのは変わらなかったので、やっぱgcc-3.2
でどうにかmakeする方法を探る方が後々面倒でなくて良さそう
な気がします......いや、気のせいかも(ぉい;
で、そのgcc-3.2の方は結局libgccのmakeで使用するヘッダが
glibcのヘッダである事を期待している部分があるため、仕方なく、
今makeに成功しているglibcのヘッダファイルをそのまま使って
configure/makeしてみました。一応コンパイルエラーでずっこけて
いた個所をクリア。でもリンクで失敗。crti.oファイルが見つからない
らしい。んー、なんで?
コンパイルログを取って文字列サーチしてもcrti.oをリンクしている
痕跡が見当たらないのですが。うーむ。
雷雨の中、日付け越え前に帰着。
前はgcc-2.95.2をppcクロスでbuildしてもエラーしなかった気がする
のですが、何故かエラー終了している模様。しかたないので、
libgcc.aが出来ているのを確認してそのままmake install。
そしてglibc-2.2.2をconfigure&make。
以前makeした時は
nsswitchのコンパイルでgccがInternalエラーをぶっこいていた
のですが、今回は
nsswitch.c:37: gnu/lib-names.h: No such file or directory make[1]: *** [nsswitch.o] Error 1
一晩中鼻水生産機になってました。休出予定だったけど出来ず。
buildチェックの続き。Cygwin上でgcc-2.95.2を使用してglibcを
buildすると、一部のネイティブツールに.exeが付いてインストール
時に大量の手作業を必要とする為、gcc-3.2をいきなり使用できないか
とconfigure&makeを実行した所、libgccのコンパイルで
glibcのヘッダファイルを使用できる事が期待されていてbuild
失敗。しかたないので、gcc-2.95.2をコンパイルして、最後
.exeが付くところを事前にどうにかしておこうと思いbuildを
行ってみたところエラーしてうまくゆかず。なぜに?(汗;......
風邪が悪化し一日病人。
少し動けそうになった所でちょこーりお出かけ。
何故どの本屋にも「銃夢 LastOrder」の二巻だけが無いのか不思議に
思いつつ三巻を買ってみたり。
やっぱダメ気味なので、PPCクロスgccやglibcのbuildについてまとめ
る為の確認とかしてみたり。現在のbuildしたツールやライブラリは
エラー&リトライで組上げたものなのですが、最初からやると
うまくいかなかったりしてへこり。
何気にXFree86 on Cygwin上で
tgifをコンパイルしてみました。一応使えるようですが、
御存知の方は判ると思いますが、tgifは3ボタンマウス使用デフォルト
のソフトウェアな為、XFree86 on Cygwinで本気で使うのは
少々無理がありそうな気分。tgif関連ページを検索していて、
このようなページを発見したり。Tgifでギャル画を描く!は、
やり過ぎ(笑 あぁ、でもTgifをベースにイラストレーター風の
ソフトに仕立て上げるとかいうのはアリかも。
寒くて起床。
最後のリンクはg++コマンドを使用して行うのですが、何気に
-staticオプションを付けると開始アドレスが同じになりました。
で、実行。UnknownSyscall(173)。rt_sigaction()の模様。でも、
何者か判らず。signal関係っぽいので、取りあえず-1を返すように
スタブ実装して再度実行。簡単なシーンファイルの
レンダリングに成功(^^)v。
以前、
MegaPOVやWin版POV-Ray3.5でレンダリングしたPhotonMapを使用した
シーンファイルをレンダリングしてみました。一発目は
シミュレータ割り当てメモリが足りなくて失敗。割り当てメモリ
を増やして再実行.........
待っている間に風邪が悪化気味で死亡。
povray-3.50b> ~/develop/ppcsim/src/ppcsim.exe -L
PPC> exec povray -Linclude -IMegaPov/spherecyl_for3.5.pov +W320 +H240 +A -Ospherecyl_ppcsimpov3.5.png
:
<中略>
:
Displaying...
0:01:01 Rendering line 1 of 240 o supersampled
0:43:11 Rendering line 11 of 240 ..*o.. ......... .oooooo. o supersampled
1:58:36 Rendering line 21 of 240 ..oo... ....... oo..... o supersampled
2:46:32 Rendering line 31 of 240 ..oo... ........ ..oooooo ... supersampled
3:21:58 Rendering line 41 of 240 ..oo... . ..oooo....o supersampled
4:14:47 Rendering line 51 of 240 ..oo.. ..oo*oo...oo supersampled
5:18:12 Rendering line 61 of 240 . ..ooo.... oo...oo. . supersampled
5:57:19 Rendering line 71 of 240 ....oMM@o... oo*ooo*o...o supersampled
6:32:43 Rendering line 81 of 240 ......@M... .. *ooooooo.ooo. supersampled
7:07:29 Rendering line 91 of 240 ..... ...MMMMM. o*****@@*oooo supersampled
7:46:45 Rendering line 101 of 240 ........... oooooo ...........o*@@@@@@@@@@ooo. supersampled
8:18:13 Rendering line 111 of 240 ............oooooooooo . .o@@@@M@@ooooo supersampled
8:44:08 Rendering line 121 of 240 ......ooooooooo........oooooooooooooo. supersampled
8:48:36 Rendering line 131 of 240 ...ooooooo............ooooooooooooooo supersampled
8:52:32 Rendering line 141 of 240 ooooo.................ooooooooooooooo. supersampled
9:18:43 Rendering line 151 of 240 .............oooo.................ooo.......ooooooooo supersampled
9:44:56 Rendering line 161 of 240 ..........oooo...................o..........@..ooooooo. supersampled
10:02:18 Rendering line 171 of 240 .......ooo.....................................oooooooo supersampled
10:21:27 Rendering line 181 of 240 ....................... . ..........oooooooo supersampled
10:44:53 Rendering line 191 of 240 ................. o. ...ooooooooooo supersampled
11:08:42 Rendering line 201 of 240 .............. oMM@*oooo@ . ..ooooooooooooo supersampled
11:24:43 Rendering line 211 of 240 .......... oMMMM@MM o...oooooooooooo supersampled
11:35:03 Rendering line 221 of 240 .......... ........oooooooooo supersampled
11:50:16 Rendering line 231 of 240 supersampled
11:51:03 Rendering line 240 of 240 supersampled 0 times.
Done Tracing
Statistics for MegaPov/spherecyl_for3.5.pov, Resolution 320 x 240
----------------------------------------------------------------------------
Pixels: 77120 Samples: 168152 Smpls/Pxl: 2.18
Rays: 1417650 Saved: 3 Max Level: 4/4
----------------------------------------------------------------------------
Ray->Shape Intersection Tests Succeeded Percentage
----------------------------------------------------------------------------
Box 875989 457194 52.19
Cone/Cylinder 915023 522700 57.12
Sphere 399515 263188 65.88
Bounding Box 8205875 3383525 41.23
Light Buffer 3257386 1537976 47.22
Vista Buffer 531713 365415 68.72
----------------------------------------------------------------------------
Calls to Noise: 0 Calls to DNoise: 10
----------------------------------------------------------------------------
Shadow Ray Tests: 722427 Succeeded: 235148
Reflected Rays: 536445 Total Internal: 26642
Refracted Rays: 496436
Transmitted Rays: 27451
Number of photons shot: 189166
Surface photons stored: 453289
Priority queue insert: 53261589
Priority queue remove: 22269685
Gather function called: 327723
----------------------------------------------------------------------------
Smallest Alloc: 13 bytes Largest: 327688
Peak memory used: 9372215 bytes
----------------------------------------------------------------------------
Time For Parse: 0 hours 0 minutes 2.0 seconds (2 seconds)
Time For Photon: 0 hours 48 minutes 0.0 seconds (2880 seconds)
Time For Trace: 11 hours 51 minutes 4.0 seconds (42664 seconds)
Total Time: 12 hours 39 minutes 6.0 seconds (45546 seconds)

大幅に日付け越え。
先日仕掛けたまま放っておいたppcクロスgccのmakeはlibc++も含めて
成功していた模様。make installでもエラーせず。バッチリです(^^)v
そしていよいよ本題のPOV-Ray3.5のコンパイルに挑戦。
途中、pnglib,zlib,jpeglib,tifflibのヘッダを要求されたため、
それぞれのライブラリをmakeしながら進めてリンク成功。
そしてppcsimで実行した所、いきなりunknown_instruction。
objdumpで見てみると、スタートアドレスがなんかずれていますよ。
なんで?
日付け越え前に帰着。
いやいや、CreateProcess()には入力は無いので、heapサイズの
違いでかかる負荷が変化することは無いハズ....と思い直し。
ということは、やはりWriteProcessMemory()が重いという事
以外に考えられなくなります。で、試しに、書き込みサイズを
4096byteに分割してメモリサイズに達するまでWriteProcessMemoryを
何度か実行するという「そりゃナシだろ」という方法を試してみました。
所が、このコードに書き換えた途端、先日書いたテストコードが
ウソのようにあっさり実行完了するようになりました(激汗;;;;;;
推測しますに、WriteProcessMemoryでプロセスサイズを増やしながら
メモリ書き込みを行う際、できるだけ大きなサイズを取りながら
割り当てているのではなかろうかと思います。その際、メモリ管理
テーブルをリニアサーチのような、あるサイズを
越えた途端、驚くほど遅くなるアルゴリズムで検索しているのでは
ないかと思われます。
一般的に、OSのSystemCall実行はコストの高い実行とされる為、
ブチブチ刻んでいちいち呼ぶよりは、まとまったサイズになるまで
プロセス側のメモリ領域で溜め込んでおき、一気に吐き出す
というのが普通(mallocしかりfread/fwriteしかり)だと思うのです
が、WriteProcessMemory()は例外らしいです。ふーん。
過程はともあれ、gccに限らずconfigure実行を開始すると全体的に
動きがスローになってイライラすることこの上なしだったのですが、
全然突っかかることが無くなりました(^^)。かなり幸せ。
御参考まで、
winsup/cygwin/fork.cc:fork_copy()を、
以下の様に実装しました。冗長でダサいコードですが、
結果オーライという事で(^^;
/* Copy memory from parent to child.
The result is a boolean indicating success. */
#define MEMDIVSIZE 4096
static int
fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
{
va_list args;
char *low;
int pass = 0;
va_start (args, what);
while ((low = va_arg (args, char *)))
{
char *high = va_arg (args, char *);
DWORD todo = wincap.chunksize () ?: high - low;
char *here;
int blk ;
int mod ;
int i ;
for (here = low; here < high; here += todo)
{
DWORD done = 0;
if (here + todo > high)
todo = high - here;
blk=todo/MEMDIVSIZE ;
mod=todo%MEMDIVSIZE ;
for( i=0 ; i<blk ; i++,here+=MEMDIVSIZE ){
int res = WriteProcessMemory (pi.hProcess, here, here, MEMDIVSIZE, &done);
if (!res || done != MEMDIVSIZE ){
if (!res)
__seterrno ();
/* If this happens then there is a bug in our fork
implementation somewhere. */
system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",
what, pass, low, high, done, pi.dwProcessId);
goto err;
}
}
if( mod!=0 ){
int res = WriteProcessMemory (pi.hProcess, here, here, mod, &done);
if (!res || mod != done){
if (!res)
__seterrno ();
/* If this happens then there is a bug in our fork
implementation somewhere. */
system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",
what, pass, low, high, done, pi.dwProcessId);
goto err;
}
}
}
pass++;
}
debug_printf ("done");
return 1;
err:
TerminateProcess (pi.hProcess, 1);
set_errno (EAGAIN);
return 0;
}
一回休み。
fork()のどこで時間を食っているのか調べてみる事にしました。
winsup/cygwin/fork.cc:fork_parent()の中でくっていそうなの
ですが、CreateProcessを実行する前後のsystem_printf()
によるメッセージ出力タイミングが実行する度に異なったりして
時間関係がなんだかよく判らず。
恐らくメッセージ出力がバッファリングされている都合だと
思われます。でも、システムが硬直するところから考えると、
Win32APIの実行が契機になっているという気はしますが.....
んーー、やっぱCreateProcessが全体を止めているような気が
するなぁ。
日付け越え。
heapの増やし方調査。どうやら、malloc()一発ではダメで、
何度もmalloc()を実行すると良かったらしい。で、以下のような
テストプログラムを書いてみたところ、fork()ずっこけが再現
する場合が(確実ではない)あるようです。
#include <stdlib.h>
#include <stdio.h>
#define MALLOCSIZE 4096
#define BLOCK_COUNT 4096
#define FORK_COUNT 16
int main()
{
unsigned char *p[BLOCK_COUNT] ;
int i,j ;
int pid ;
for( i=0 ; i<BLOCK_COUNT ; i++ ){
p[i]=malloc(MALLOCSIZE) ;
if( p[i]==NULL ){
printf("malloc faild\n") ;
exit(-1) ;
}
}
for( i=0 ; i<FORK_COUNT ; i++ ){
printf("Enter fork()\n") ;
pid=fork() ;
if( pid==0 ){
printf("Leave fork() child %d\n",i) ;
for( j=0 ; j<BLOCK_COUNT ; j++ ){
free( p[j] ) ;
}
exit(0) ;
}else if( pid>0 ){
printf("Leave fork() parent\n") ;
wait(0) ;
continue ;
}else{
break ;
}
}
exit(0) ;
}
日付け越え。
heapの増やし方がよくわからなかったので調査。コンパイル後の
実行ファイルをobjdumpで逆アセンブルしてみても、sbrk|brkの
文字列は見つからず。
直接sbrk()を書いて、コンパイル&実行した所、Cygwin網掛け
には引っかかったので、sbrk()を呼び出すことで実行されること
には間違い無さそう。
テストで書いたプログラムではsbrk()を実行している様子が無い
のでppcsimを実行してみた所、これはsbrk()を実行していました。
でも直接sbrk()を使ってはいないので、当然の事ながらobjdump
の逆アセンブル結果にはsbrk|brkの文字列は見つからず。
gdb上でppcsimを実行。run実行前にb _sbrkを実行してもシンボル
見つからず。b main(),run を実行し、停止しているところで
b _sbrk を実行すると、ブレークポイントの設定に成功。
(gdb) b main Breakpoint 1 at 0x401080 (gdb) run Starting program: /cygdrive/c/tane/develop/ppcsim/src/ppcsim.exe Breakpoint 1, 0x00401080 in main () (gdb) b _sbrk Breakpoint 2 at 0x61041927 (gdb) c Continuing. Breakpoint 2, 0x61041927 in _sbrk () (gdb) where #0 0x61041927 in _sbrk () #1 0x610bd6b2 in sbrk () #2 0x61046471 in sYSMALLOc () #3 0x00402259 in memal (mres=0x42d258, seg=0, size=65536) at memal.c:29 #4 0x00407f59 in create_proc () #5 0x004016a4 in init_system () #6 0x0040132b in main () #7 0x61007983 in dll_crt0_1 () #8 0x61007d71 in _dll_crt0@0 () #9 0x61007dc9 in dll_crt0 () #10 0x0041d042 in cygwin_crt0 () #11 0x0040103c in mainCRTStartup () #12 0xbff8b6e6 in _system_dlls__ () #13 0xbff8b598 in _system_dlls__ () #14 0xbff89f5b in _system_dlls__ () Error: Cannot access memory at address 0x8ee61fec
(gdb) s
Single stepping until exit from function _sbrk,
which has no line number information.
0x610bd6b2 in sbrk ()
(gdb) s
Single stepping until exit from function sbrk,
which has no line number information.
0x61046471 in sYSMALLOc ()
(gdb) s
Single stepping until exit from function sYSMALLOc__FUiP12malloc_state,
which has no line number information.
0x610471b6 in dlmalloc ()
(gdb) s
Single stepping until exit from function dlmalloc,
which has no line number information.
0x610485f5 in malloc ()
(gdb) s
Single stepping until exit from function malloc,
which has no line number information.
memal (mres=0x42d258, seg=0, size=65536) at memal.c:30
(gdb) l
25 free(mres->mem[j]) ;
26 mres->mem[j] =NULL ;
27 mres->mem_size[j]=0 ;
28 }
29 mres->mem[j]=malloc(k) ;
30 if( mres->mem[j]==NULL ){
31 return(MEM_ALLOC_ERROR) ;
32 }
33 mres->mem_size[j]=k ;
34 memclear( mres, j, k ) ;
(gdb)
#include <stdlib.h>
#include <stdio.h>
#define MALLOCSIZE 0x10000000
int main()
{
unsigned char *p ;
int i ;
p=malloc(MALLOCSIZE) ;
if( p==NULL ){
printf("malloc faild\n") ;
exit(-1) ;
}
for( i=0 ; i<MALLOCSIZE ; i++ ){
p[i]=i%256 ;
}
printf("mem fill complete.\n") ;
exit(0) ;
}
昼頃起床。休出
帰りに「ヒカ碁(19)」査収。一気読み。このマンガ2〜3巻くらい
まとめて読まないと続きが気になってしかたないですよ。
_sbrk()で網掛けを行ったところ、本当に4096Byte単位で2MB分
メモリを要求していました(^^; そして、大きくなったshを
forkする為、動きがスローになってしまっている模様。しかし、
それを繰り返すとリソース不足に陥るのはやはり解せません。
なんだか追いかけているうちに、だんだんheapbaseとheaptopの区別が
つかなくなってきた(^^;
winsup/cygwin/cygheap.cc:cygheap_setup_for_child()の
CreateFileMappingなどに網を仕掛けてみましたが特にエラーせず。
このAPIの戻り値で「#define ERROR_ALREADY_EXISTS 183L」が
戻る場合があるらしいのですが、一番最初のhFileに
INVALID_HANDLE_VALUE を指定がしていされていると、
新規のファイルマッピングオブジェクトを生成するようなので
問題なさげ。ただ、ディスク容量が足りないと「ERROR_DISK_FULL」
を返すようですが、それはチェックされていない模様。
戻り値のハンドラもNULLが返るという事なので、その先で
NULLを食って正しくずっこけるからOKという説はありそうですが。
うまくいったりいかなかったりする所を見ると、何かヘンなもの
を食わせているか、プロセス動作タイミングの時間関係が
ずれたりとかそんな感じがしなくもないですが........
それよりも、そもそもC++ライブラリを入れる事が目的だったのに、
脱線してCygwin本体を調べるところまでずらされているのですが、
たまにうまく通ったその先でコンパイルエラーになっている
事の方が深刻かも(汗;
heapが大きくなっていることでforkが重くなっているようなので、
簡単なテストプログラムで再現しないか考えてみました。
所が、heapをどうやったら消費できるのか判らず(汗;
単純にmalloc()で巨大なメモリ割り当てを行ってもちっとも
_sbrk()に触れていない模様。
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned char *p ;
int i ;
p=malloc( 2*1024*1024 ) ;
if( p==NULL ) exit(-1) ;
for( i=0 ; i<3 ; i++ ){
int pid ;
pid=fork() ;
if( pid==0 ){
printf("pid=%d\n") ;
exit(0) ;
}else if( pid> 0 ){
continue ;
}else{
exit(-1) ;
}
}
exit(0) ;
}
964958442 [main] bash 1810511 _sbrk: sbrk= 4096 ( 86016)
964959198 [main] bash 1810511 _sbrk: sbrk= 4096 ( 90112)
964967021 [main] bash 1810511 cygheap_setup_for_child: cygheap_setup : 0
586 [unknown (0xFFE21A49)] A 1810511 _sbrk: sbrk= 4096 ( 0)
1724 [unknown (0xFFE21A49)] A 1810511 _sbrk: sbrk= 0 ( 4096)
5421 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0
164921 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020
815 [main] A 1958811 _sbrk: sbrk= 4096 ( 4096)
1345 [main] A 1958811 _sbrk: sbrk= 0 ( 8192)
175780 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32
176274 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16
176727 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096
177116 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100
177901 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936
400044 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512
401165 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0
pid=-2121000100
564904 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020
155 [main] A 1835655 _sbrk: sbrk= 4096 ( 4096)
620 [main] A 1835655 _sbrk: sbrk= 0 ( 8192)
573620 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32
574070 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16
574505 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096
574857 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100
575614 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936
581351 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512
582231 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0
pid=-2121000100
745800 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020
597 [main] A 1835471 _sbrk: sbrk= 4096 ( 4096)
1644 [main] A 1835471 _sbrk: sbrk= 0 ( 8192)
754260 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32
754772 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16
755235 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096
755760 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100
756638 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936
978652 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512
pid=-2121000100
2002/10/05
昼頃起床。
winsup/cygwin/fork.cc:fork_copy() にはあまり見る所が無くなって
来た感じがしたので少し捜索範囲を広げてみたり。因みに、
先日のエラーコード183は以前に実行されてWinAPIの結果っぽい。
というのは本来ならエラーしたときにその詳細を知るために
見るという手順からいくと、実行自体が成功しているなら見なくても
良いからという気がしてきたため。でも、エラーしたときだけ
コードを入れなくても、エラーしなければエラー無しというコード
を入れてくれれば良い気がしなくもありません。真相は不明。
本屋でWin32APIのリファレンス本を買って来たり。
winsup/cygwin/fork.cc:fork_parent() のCreateProcess()を
疑ってみたり。以前、ppcsimでスレッドを使用したときに
スレッド上で初期化されるグローバル変数に別スレッドから
アクセスに行って死ぬなんて事がありましたが、それに似た
現象が起こっていないか疑ってみたため。
CreateProcess()自体はプロセスを生成すると、すぐに
戻ってくるという事なので、プロセス自体が生成されたばかりで
準備中のところにWriteProcessMemory()がぶつかってしまった
のではなかろうかと疑ってみました。CreateProcess()の後ろに
Sleep(100)(100ms)とか入れてみたのですが、特に何かが変わる
といった感じではなさそう。因みにデバッグコードを仕込んで
実行すると、エラーしないでうまくいったりする場合があったり
してイマイチ。
先日2MB程度の領域確保で死ぬか?と書いたのですが、この2MBは
heap領域のサイズ(pass 2がそれ)の様で、逆に たかだかshで
2MBもheapを使うか?という点に疑問が移ってきたのでそこを
狙って追っかけてみることにしました。
網をかけて眺めていた所、通常は80kB〜150kBなのですが、
ある点を境にいきなり2MBになるようで、実際にこの2MBの
heapサイズでforkが始まるとカーソルが動かなくなるなどの
副作用が発生するようです。
winsup/cygwin/heap.cc:_sbrk()に網を仕掛けて調査してみる
事にしました。newlibのmalloc()での割り当て単位は
4096Byteのようで、それ以下での要求は無いようです。また、
Cygwinのsbrk()システムコールではサイズにマイナスを入れる
場合にも対応されているようで、不要ブロックはOSに返す
ように実装されているようです。Win32API的には
VirtualAlloc/VirtualFreeを使用して実装しているようです。
取りあえず_sbrk()が実行されたら要求サイズと現在のheap
サイズを表示してみることにして実行してみた所、
再現しなくて失敗。うーむ。
ハングらかしてSCANDISKだったりMATRIXを観たり。
日付け越え。
エラーメッセージの「Win32 error 8」の8はGetLastError()の
エラーコードと同じものを示していることが判明。
/usr/include/w32api/winerror.hを見てみると、
「#define ERROR_NOT_ENOUGH_MEMORY 8L」という事らしい。
ちゅうことは本当にメモリが足りないとのたまわっている
らしい。むぅ、なんでだ?確かにforkずっこけが起こると、
Meadowはメモリが不足しているという旨のエラーを出して
起動失敗するので、システムがおかしくなっている事は
確からしいのですが......
因みに183は「#define ERROR_ALREADY_EXISTS 183L」という
事らしい。勝手な想像ですが、データの転送先プロセス
が既に消滅しているときにこうなるのかしら?てゆーか、
そんな事あるのか?
日付け越え。
-O0にしてCygwinコンパイル。なんか微妙に状況が変わるけどエラーずっこけ
は変わらず。
日付け越え前に帰着。
先日のCygwinのコンパイルは成功。そんな感じでデバッグコードを
少し仕込んで再コンパイル。そして実行した所、
662372290 [main] sh 1759717 fork_copy: user/cygwin data pass 1 failed, 0x47C000..0x483570, done 30064, windows pid 4293173107, Win32 error 0 662382288 [main] sh 1759717 fork_copy: user/cygwin data pass 2 failed, 0x9F0000..0xC0A000, done 2203648, windows pid 4293173107, Win32 error 8 662385344 [main] sh 1759717 fork_copy: user/cygwin data pass 2 failed, 0x9F0000..0xC0A000, done 0, windows pid 4293173107, Win32 error 8
台風のため早めに帰着。
何気に買ったまま置いといた「GRADIUS III and IV」のベスト版
などをやってみたり。やっぱむずいわ(^^;
IIIもIVもアーケードでは全くやった事がなかったりします
(何故か置いてある所が少なかった)。IIIの出た'89頃というとシューティングゲーム
は上手い人とそうでない人との差が付いて、結局 難しくなる方向に
進んで行った辺りだと思います。それと比べると、
今の弾幕系シューティングって最初の方は結構遊べるように
思ったりして。スーファミ版のIIIは結構やった記憶が
ありますが、あれはゲームバランスがEasy気味に調節されてて
(オリジナルがハード過ぎるというのはおいといて(汗;)
結構遊べた記憶があります(上上下下.....が使えたという説はありますが(^^;)。
IVは怒首領蜂とか弾幕系シューティングが幅を利かせ始めた
頃に出たと思いますが、すぐ無くなっちゃいましたよね(ぉい;
でも弾の出が悪く、素っ裸だと全く歯が立たない、それが
GRADIUSって感じなのかも知れません。
そんな感じでIIIの1面をクリアするのにえらい苦労した所
のTANEでした。でも「あぁ、これこれ、GRADIUSって感じ」だから
「こういうもの」だと思ってプレイしてたりする自分(笑。
ふと思ったのが、折角のBEST版なので、オマケで全面ノーミス
リプレイデータとか入れてくれると良かったのになぁなどと贅沢を
言ってみたり。IIIだと見るだけで1時間くらいかかりそうですが(^^;
Cygwinのconfigure/makeについて検索してみた所、
このようなTIPSページを発見しました。
どうやらconfigureの実行方法に暗黙の了解があるらしい。
configure使ってずっこけると訳わからないので、
ソースと同じディレクトリで実行できないならconfigureの最初に
自動的にディレクトリを掘ってその中で実行するように
しといてくれれば良いのに。何の為のシステム自動検査
スクリプトなんだか。ぷんぷん(ぉ
configureの実行終了後、make実行.......うまくいってそう
な予感。