昼過ぎ起床。
もそもそとコーディング。あまりにも遅すぎるのでやり方を変えてみる。
std.regexを使う訳ですが、tokenをランダムアクセスしたい場合に、Rengeで
tokenを返すsplitter()とかは使いにくいです。
また、ランダムアクセス可能なように Rangeをstring配列に変換しようとしたの
ですが、lengthプロパティもwalkLength()も使えないRangeのようで、tokenの数を得るのに
一度スキャンして長さを求め、配列要素に代入するのにもう一度スキャンし直す必要がありました。
積みっぱになっていた「まもるクンは呪われてしまった 冥界活劇ワイド版」を開封。
アーケード版がオリジナルのようですが、実機稼動は一度も見た事ありません。
そんな訳でやってみたり。ワイド版はアーケードとは少しゲームの仕様が違う模様。
何気に1080pで見易かったり。それはアーケードモードをやってみて、「画面狭!」
って感じるくらいに。呪い弾の使い方がイマイチ要領を得なかったのですが、使い方
が判ってくると面白くなってくるように思います。とは言え、最近は2D STGもあまり
やって無いのと寄る年波には勝てないのとで、コンティニュー押しで進めるのが
精一杯です(^^;
起きたら午後もいい時間。寝すぎ。
もそもそとコーディング。pathのデータパースに使う正規表現群を
一通り入れてみたのですが、やっぱりマッチングが遅すぎます。
正規表現の性能についてWebを眺めていたら、
鬼車
なる正規表現ライブラリの存在を知ったり。更にリンクを辿っていて、
「メールアドレスの正規表現」
というページに辿り着いたり。えー?!こんな事になっちゃうんだっけ?(^^; という感想。
早くも無く遅くも無く。
もそもそとコーディング。先日の件は正規表現を少し整理したり、事前加工で
マッチの種類を減らしたりしたらマシになった気も。
早くも無く遅くも無く。
PSN障害。不正アクセスで情報漏えいの可能性があるとも。まぁ、大した情報は入ってない
ので、それほど大事でも無い気が。再開のメドはまだ立っていない模様。
もそもそとコーディング。std.regexを弄っているのですが、何故かマッチの性能が
極端に下がる場合があったり。イメージ的なザックリした例ですが、
「((num num) (num num))+」という感じで、二つの数を1ペアとして、そのペア×2個が
1つ以上並んでいる場合のマッチだと問題無い速度でマッチできるのですが、
これが「((num num) (num num) (num num))+」という感じでペア×3個になると途端に
ハングしたかと思うくらいの速度になってしまいました。
うーむ、どうしたもんか。
遅めに帰着。
もそもそとコーディング。うーむ面倒臭い。
遅めに帰着。
もそもそとコーディング。
AM中に起床。
積みっぱになっていたファミ通WAVE休刊号のDVDをやっと観たり。
最後まで自由な感じでした。
そういやPSNが4/21頃から障害で停止しているもよう。PSNが止まると
週トロとか見れないので結構不便かも。
もそもそとコーディング。std.regexの 正規表現エンジンの格納に、
「auto r = regex("pattern") ;」のようにauto変数として代入する例があります。
この例での r を連想配列にしたい場合、auto変数にしたのではダメなので、
「Regex[string] r; r["hoge"]=regex("pattern");」みたいにすれば良いと思ったのですが、
これだと「Error: struct std.regex.Regex(E) if (is(E == Unqual!(E))) is used as a type」なるエラー。
意味がよくわからないのですが、テクニカル過ぎて基本的な用法がダメになっている
予感がしたりも。
昼過ぎ起床。雨が激しすぎる。
新しいgdcをビルドしてみる事にしたり。tdmのバイナリを置いてくれている
のですが、/usrの下に置かれるのが個人的に具合が悪いので。ただ、configureオプションを
参考にさせてもらうことにしたり。
で、r550:3cf208768d86 はエラー無くビルドできたのですがインストールして使ってみたところ、
リンクで_tlsstart, _tlsendが見つからなくてリンクできず。Webに置かれているバイナリと同じ
r546:efb1b1ed90d8 をビルドしてみたところ、これもエラー無くビルドできたのですが、インストール
して使ってみると_tls_indexが見つからなくてリンクできず。これはr548で修正が入っている
ようだったので、それを手でちょこっと直してひとまず使えるようになりました。
で、手持ちのコードをコンパイルしてみる訳ですが、ファイルエクスプローラ
から起動するとずっこける問題が発動。この辺は何も変わっていないようです。
自前対処をあててなんとなくOKな感じ。
r550で_tlsstart,_tlsendのリンクできなくなった方に、何かしらの対処が入った事を期待したのですが
なんとなくデグってただけっぽい。動的配列の内容が壊れる場合があるのは特に変わりなく。
シネ通でやってたレゴランドの話。スターウォーズのシーンなどをレゴで再現した事が紹介されて
いました。そのイベントに旧三部作でレイア姫役だったキャリー・フィッシャーが招待されて
いたのですが、それを見たバナナマン設楽の「え?この人がレイア姫? ジャバザハットじゃなくて?」
に思わず吹いたり(^^;
遅めに帰着。
もそもそとコーディング。SVGのフォーマット。パスのデータの並びは
判ったものの、ルールが大らか過ぎてなんだかパースが面倒臭いなぁと
思ったりも。例えば同じ命令が続いている場合、後に続く命令では命令文を
省いて良いという仕様。「L 100 100 L 200 200」 と 「L 100 100 200 200」
は同じという感じなのですが、後者の場合だと一つ前のコマンドを覚えておく
必要があります。また、命令と次に続く値の間には空白があっても無くても良い
(「L 100 200」と「L100 200」は同じ)とかは、トークン分離を少し面倒臭くして
いるようにも感じます。パターンが大らかだと、間違い(文法エラー)を検出するのも難しく
なるような気がするので良い事は無いと思うし、大してデータの圧縮にもなっていない
ように思うのですが、何故こんな感じになっているのかは知る由も無く。
早くも無く遅くも無く。
もそもそとコーディング。std.regexpが非奨励になっていたので、std.regexを
使ってみたり。トークン分離の方法で、以前はstringの配列を返すRegExpクラスの
メソッドがあったのですが、最近はRangeなるものとして返されるっぽい。
このRangeはスタックというかリストというか、そういうイメージに近いものらしい。
そういや以前いじったErlangには
tupleとlistがありましたが、このときのlistもしかり今回のRangeもしかり、
ランダムアクセス可能な配列以外に、listやRangeのようにシーケンシャルアクセスに
限定するようなデータを用意するメリットってあるのかしら?
早くも無く遅くも無く。
std.xmlを使う練習。以前は特殊な構文っぽくて
イマイチ意味が判らなかったのですが、タグをハッシュキーとした関数呼び出しの
リストを作っているんだと判ったり。
XMLとしてアトリビュートやエレメントを取り出す事はできそうなのですが、
例えばstyleアトリビュートは
style="color:#000000;fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
の様に「長っ」てな感じの上に、更にXMLとは違う感じのトークン分離を
行わなくてはならないようです。あと、pathのデータ並びがどういう風に
なっているのかがイマイチよく判らなかったり。タグやパラメータの
解説が無いかと探してみると、
SVG 1.1仕様(第2版) 日本語訳
というのが見つかったり。パスなどについても一通りの説明がされているようですが、
パッと見た感じ仕様が大きすぎて読むのに挫けそうかも(^^; また、全ての図形を
cairoの描画プリミティブに1:1に置き換えられる訳では無さそうです。
早くも無く遅くも無く。
もそもそと調査。割と簡単に再現プログラムを書けないか?と思って少し
試してみたのですが、うまく再現できなかったり。
そういや、SVGをパースするのに std.xmlを使うのはどうかしら?と
いうのは以前思った訳ですが、
なんだかバグバグしていたのと、まるで違う言語のようなコードでそのまま
フェードアウトしてました。ひとまず描画プリミティブさえ取り出せれば良い気が
するので、少し実験してみたり。でもまだ何も掴めず。
気持ち遅めに帰着。
もそもそと配列が壊れる件を調査。何に反応しそうかを見てみるだけで終了。
いつの間にか中身がすり替わったりするようなのでどうしたもんか。
昼頃起床。
cairoを使用するコードをgdc 2052対応する為にcairoをMinGWでビルドしたり。
cairoのconfigureで使用する pkg-configが入っていないのを入れようとしたら、
pkg-configは glibを使っていたりしてまずはそこから入れなくてはならないとか、
なかなか面倒臭かったです。
ひとまずOKそう。ついでにlibrsvgもなんとかならないか?と思ってビルドしようと
したのですが、librsvgが依存しているlibxml2 のconfigureが通らないという
感じになってて、あまり調べずに終了。
調査。動的配列の内容が壊れているようなのですが、その前にTLSを調べたり。
問題ありそうなところをshared修飾してみたのですが状況は変わらず。
一応単スレッドアプリなのと、GCをdisableにすると配列の内容が壊れたりは
しないようなので、GC起因の問題のような気が。
なんとなく壊れている配列が限定されてきたりも。でも、どのタイミングで
壊れたのかが良くわからず。少なくとも、配列の範囲チェックに引っかかる事
無くSegfaultでずっこけているようなのと、GCをdisableにすると大丈夫な事から、
開放してはならない領域を間違って開放しているんじゃないか?という推測です。
bitbucketのgdcページ
では、MinGWに関連した変更がいくつか入っている模様。その中にtlsに関連したものも
あるようなので、もしかすると色々直っているかも知れません。
地震の揺れでAM中に起床。
そういや以前 クラス内で
動的配列を確保した時、デストラクト時に何もしないと確保された動的配列の方は
開放されないという話がありました。gdcの2.052対応版だとその辺どうなっているん
だろう?と思い確認してみたり。結果、
遅めに帰着。
もそもそと手持ちコードをgdc 2052対応したり。
早くも無く遅くも無く。
もそもそと調査。
__gshared 修飾されている __blkcache_offsetを threadクラス内のtlsとして
保持するように書き換えてみたり。で、デバッガで値を確認してみたりした
のですが、tlsとして持つようにしたblkcache_offsetと __gshared修飾された
元の__blkcache_offsetは同じ値になっていて、あれぇ?やっぱりオリジナルの
コードで良いのかなぁ?と思ったり。でも、何故かずっこけなくなりました(^^;;;
問題はgdb上で実行するとやっぱりずっこけるという謎の挙動を示すようになった
点でしょうか。もう何が何やら。これで少し使ってみることにします。
少し早めに帰着。
昨日のコード。Cygwinのシェルから起動した場合は問題無かったのですが、
ファイルエクスプローラからダブルクリックで起動した場合はエラー窓が
開いて起動できなかったり。デバッガから起動したら上手く起動したり
するもんなので、色々こねくり回していたのですが、どうやら
件のコードと同じ現象が発生している感じだったり。
うーむ、しばらく大丈夫かなと思ったのですが、昨日の今日でもう踏んでしまいましたか。
ずっこけ所はfullcollect時のrt_processGCMarks()内で再現プログラムと
同じ箇所。GCをdisableにすれば動き続けられるのは変わらず。
そういえば、あるスレッドのTLSな領域を、別のスレッドから見る事って
できるんだっけ?と思ったり。GCのfullcollect内では、collectの発動した
スレッドがthread_suspendALL()
を実行(これでcollect発動スレッド以外のスレッドが全て止まる)します。
続いてcollectコードを実行した後に、全スレッド分のrt_processGCMarks()を実行します。このとき、
スレッド毎の TLSに配置された __blkcache_storage をcollect発動スレッド
から検査する流れになる訳ですが、別のスレッドのTLSな領域を見る事が
できないのであれば、そもそもこの動作って成立しないように思った訳です。
早くもなく遅くも無く。
進展あり。ボンヤリのコードについて、Window基底クラスで
使用しているプロシージャのリストをsharedで修飾して、それに伴うコンパイル
エラーを直したところ、GCをenableにしたままでうまく絵が出るように
なりました(^^;;;; どうも TLSなグローバル変数になっていたのが
猛烈に具合が悪かったようです。
そもそもTLSとsharedだとどう違うのか?という所を確認してみたり。
$ cat -n tls_test.d 1 import std.stdio; 2 import std.stream; 3 import std.string; 4 5 import core.thread; 6 7 class ThreadEx : Thread { 8 shared static int shared_No ; 9 static int tls_No ; 10 11 this(){ 12 super( &run ) ; 13 } 14 15 private void run() { 16 writef("enter Thread shared_No=%d, tls_No=%d\n", shared_No, tls_No ) ; 17 shared_No++ ; 18 tls_No++ ; 19 sleep(10_000_000_0) ; // 10sec 20 writef("leave Thread\n") ; 21 } 22 23 } 24 25 void main(string[] args) 26 { 27 writef("start\n") ; 28 29 auto t1 = new ThreadEx(); 30 t1.name("Thread1") ; 31 t1.start(); 32 33 auto t2 = new ThreadEx(); 34 t2.name("Thread2") ; 35 t2.start(); 36 37 for( int i=0 ; i<10000000 ; i++ ){} 38 39 Thread[] threadlist = Thread.getAll() ; 40 for( int i=0 ; i<threadlist.length ; i++ ){ 41 writef("%d : %s\n", i, threadlist[i].name()) ; 42 } 43 44 writef("end\n") ; 45 } $ gdc -g tls_test.d $ ./a.exe start enter Thread shared_No=0, tls_No=0 enter Thread shared_No=1, tls_No=0 0 : Thread2 1 : Thread1 2 : end leave Thread leave Thread
$ objdump -S a.exe | grep -A12 shared_No++ shared_No++ ; 4013c5: a1 08 80 49 00 mov 0x498008,%eax 4013ca: 83 c0 01 add $0x1,%eax 4013cd: a3 08 80 49 00 mov %eax,0x498008 tls_No++ ; 4013d2: c7 04 24 00 c0 47 00 movl $0x47c000,(%esp) 4013d9: e8 c2 33 05 00 call 4547a0 <___emutls_get_address> 4013de: 8b 00 mov (%eax),%eax 4013e0: 8d 78 01 lea 0x1(%eax),%edi 4013e3: c7 04 24 00 c0 47 00 movl $0x47c000,(%esp) 4013ea: e8 b1 33 05 00 call 4547a0 <___emutls_get_address> 4013ef: 89 38 mov %edi,(%eax) sleep(10_000_000_0) ; // 10sec
早くもなく遅くも無く。
もそもそと調査。dmdのオリジナルコンパイラに -vtlsというオプションがあり、
TLSになっているグローバル変数が表示できます。これでrt/lifetime.dをコンパイル
してみると、__blkcache_storageはTLSだという事のようです。で、
__blkcache_offsetは __gsharedが指定されている為、TLSじゃないグローバル変数
になっています。で、やっぱりよく判らないのが、
thread毎のm_tlsというポインタ位置とTLSである__blkcache_storage領域との
距離が、どのスレッドの場合でも毎回同じになるんだっけ?という点。
やっぱりここん所、何か変な気がするんだけどなぁ?.....
AM中に起床。
もそもそと調査。改めて順に調べてみることにしたり。
各スレッドはそれぞれにm_tlsなるメンバー変数を保持しています。
この変数はあるメモリ領域を指していて、その範囲は_tlsstart〜_tlsend
で示されるアドレスの範囲を指しています。ところが、この_tlsstartと_tlsend
は単純な変数ではなくて、gcc/emutls.cというソース内の
__emutls_get_address()なる関数呼び出しに置き換えられていました。どうりで
表示しようと思っても見られない訳です(^^; で、得られた_tlsstartと_tlsend
の範囲は32バイトとなっており、Phobosの中ではスライシングでこのメモリ領域
を参照する(実際に見る事があるのか否かがまだ不明)ようになってました。
もう一つlibphobos/rt/lifetime.dの中に__blkcache_storageというポインタ変数があります。
このポインタの指す領域の中に不当な値が入っていてずっこけるという流れなのですが、
この領域も__emutls_get_address()で得ていました。で、この領域はどうやって
phobos内で参照しているかと言うと、先に述べたスレッド毎のm_tlsの先頭アドレス
(すなわち_tlsstart)と__blkcache_storageのアドレスとのoffsetを
__blkcache_offsetという変数に保持して、毎度m_tls+__blkcache_offseで
__blkcache_storage領域を参照しています(以前
、何故__blkcache_storageを直接参照してないのか?をスルーした点にかかっています)。
ただ、この__blkcache_offsetの計算が_Dmainに到達する前に一度実行されるだけ
となってるのが謎です。つまり、メインスレッドが起きた時にメインスレッドのm_tlsと
__blkcache_storageから__blkcache_offsetを計算するのですが、
それっきりなので、_Dmain以降に起こしたスレッドは そのスレッド用に確保
した m_tls領域の先頭アドレスに__blkcache_offsetを足した場所を参照
してる事になっていて、そこっていつメモリ確保したんだっけ?という状況。
この点が以前__blkcache_storageって本当にTLSに
なっているんだろうか? にかかってきます。んじゃ、__blkcache_storageを
直接参照すれば良いのか?というとそういう訳でもなく、__blkcache_offsetの
計算と同様に、__blkcache_storageもメインスレッドの分しか確保していない
ように見えます。
という訳で、特に何も解決せず。
散髪予約。予約満杯のようで日も暮れた頃に行ったり。
昼頃起床。
もそもそと調査。やっぱり全然関係無い場所をアクセスしているように見えるなぁ?
気持ち早めに帰着。
もそもそと調査。例えば、あるメモリアドレスの内容がいつの間にか変わっていた
場合、コードのどこで そのメモリアドレスを触ったのかを知る方法は無いん
だっけ?と思って調べたり。gdbにそういう事を行う方法がありました。
次の様なD言語のコードを例にとってみます。
$ cat -n gdb_memtest.d 1 import std.stdio; 2 import std.string; 3 4 void main(string[] args) 5 { 6 int[] array ; 7 8 array.length=256 ; 9 10 for( int i=0 ; i<array.length ; i++ ){ 11 array[i]=i ; 12 } 13 14 }
(gdb) b _Dmain #いわゆるDのmainにブレークポイント設定 Breakpoint 1 at 0x401361: file gdb_memtest.d, line 6. (gdb) run Starting program: /cygdrive/c/cygwin/home/tane/develop/dlang/test/a.exe [New Thread 5840.0x1504] Breakpoint 1, main (args=...) at gdb_memtest.d:6 #止まった (gdb) n #6行目ステップ実行 (gdb) n #8行目ステップ実行 (gdb) print/x &array #変数arrayのアドレス $1 = 0x22fce4 (gdb) x/16x $1 #arrayをメモリダンプ 0x22fce4: 0x00000100 0x00c95800 0x00425c73 0x0022fdfc #0x22fce4が配列サイズ、0x22fce8が配列実体へのポインタ 0x22fcf4: 0x0022fee4 0x0040dff1 0x0022fee4 0x00000009 0x22fd04: 0x0022fd4c 0x0022fd28 0x0040e00e 0x00000001 0x22fd14: 0x0022fe80 0x00000000 0x0022fee4 0x0040dff1 (gdb) x/16x 0xc95800 #配列実体をメモリダンプ 0xc95800: 0x00000000 0x00000000 0x00000000 0x00000000 #全部0でクリアされている 0xc95810: 0x00000000 0x00000000 0x00000000 0x00000000 0xc95820: 0x00000000 0x00000000 0x00000000 0x00000000 0xc95830: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) watch *(int*)(0xc95810)!=0 #watchポイント設定 Hardware watchpoint 2: *(int*)(0xc95810)!=0 #0xc95810の内容が0で無くなったら止まるハズ (gdb) c #コンティニュー実行 Continuing. Hardware watchpoint 2: *(int*)(0xc95810)!=0 #止まった Old value = 0 New value = 1 0x004013f3 in main (args=...) at gdb_memtest.d:11 (gdb) x/16x 0xc95800 #配列実体をメモリダンプ 0xc95800: 0x00000000 0x00000001 0x00000002 0x00000003 0xc95810: 0x00000004 0x00000000 0x00000000 0x00000000 #0xc95810が0でなくなっている 0xc95820: 0x00000000 0x00000000 0x00000000 0x00000000 0xc95830: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) print i $2 = 4
早くも無く遅くも無く。
もそもそと調査。色々観察したり試しにいじったりしてるのですが、
イマイチ掴めず。
とかやってると意外と大きな揺れが。余震はまだまだ続くなぁ。
気持ち早めに帰着。
もそもそと調査。流れがつかめたようなそうでもないような。
失敗の流れは、core.memory.GC.collect() ⇒ thread_processGCMarks() ⇒ rt_processGCMarks()
と関数呼び出しして最後のrt_processGCMarks()内でSegfaultするという感じ。
Threadクラスの中にはm_tlsというメンバー変数があり、全てのスレッドに対して
rt_processGCMarks(m_tls) という感じでGCMarksなる処理を行っているようです。
m_tlsにはThreadクラスの中で何やらメモリ領域を割り当て(正確には_tlsstart〜_tlsendの範囲をスライシングで
割り当て)ているようです。で、良くわからないのは、各スレッドのm_tlsの
メモリアドレス番地を基準に、__blkcache_storageの領域に辿りつくように
__blkcache_offsetが計算されているようなのですが、__blkcache_offset
がどこで設定されているのかが判りません。一箇所だけ__blkcache_offset
に値を設定するコードがあるのですが、「shared static this()」という
初期化の為の特別なコードで、一度だけ実行されているのですが、生成される
スレッド毎に計算されているような気配はありません。
今の感じで見ると、__blkcache_offsetに値が入っているがそれは(恐らく)
メインスレッドのm_tlsとの距離をセットしているけど、それ以外のスレッド
のm_tlsとの距離では無い?ので、アクセスしてはならない領域が
指されてしまっている?気がしたり。lifetime.dの中に
// note this is TLS, so no need to sync. BlkInfo *__blkcache_storage;
早くも無く遅くも無く。
調査の続き。追いかけたり、ちょっとパッチを当ててみたりするものの、
うまくゆかず。
気持ち遅めに帰着。
先日の調査の続き。ひとまずcore/thread.dの内容については特に今のままで問題無いように
思ったり。そんな訳でデバッガを使いながら変数の中身や動きを調べたり。
どうやらrt/lifetime.d内に原因がありそうな予感がしてみたり。まず、Segfaultの直接
の原因はcacheなる変数の値がなんだか変な感じになっている所です。cacheの元になる
__blkcache_offseにはどこで値が入っているのだろう?と辿ってみると、
「__blkcache_offset = (cast(void *)&__blkcache_storage) - tls.ptr;」なるコードが
ありました。とどのつまり、cache は _blkcache_storage へのポインタと等しいという
事になるようです。何故__blkcache_storageを直接参照してはならないのかが謎ですが、ひとまず
そこはスルーします。更に__blkcache_storageにはどこで値が入っているのだろう?
と辿ってみると、
@property BlkInfo *__blkcache() { if(!__blkcache_storage) { // allocate the block cache for the first time immutable size = BlkInfo.sizeof * N_CACHE_BLOCKS; __blkcache_storage = cast(BlkInfo *)malloc(size); memset(__blkcache_storage, 0, size); } return __blkcache_storage; }
Breakpoint 3, rt_processGCMarks (tls=...) at ../../../libphobos/rt/lifetime.d:430 (gdb) l 425 // might be ready to sweep 426 427 debug(PRINTF) printf("processing GC Marks, %x\n", tls.ptr); 428 int debug_var1 = __blkcache_offset ; 429 uint debug_var2 = cast(uint)(tls.ptr) ; 430 auto cache = *cast(BlkInfo **)(tls.ptr + __blkcache_offset); 431 if(cache) 432 { 433 debug(PRINTF) foreach(i; 0 .. N_CACHE_BLOCKS) 434 { (gdb) print/x (BlkInfo **)(tls.ptr + debug_var1) $7 = 0x3e3344 (gdb) print/x *$7 $8 = 0x9090909 (gdb) set *$7=0 (gdb) print/x *$7 $9 = 0x0 (gdb) delete breakpoints Delete all breakpoints? (y or n) [answered Y; input not from terminal] (gdb) c Continuing. start 0 1 enter Thread leave Thread end Program exited normally. (gdb)
AM中に起床。
GCとスレッドの組み合わせによる不具合の再現プログラム。
なんとなく毎回同じようにSegfaultさせられる感じになってみたり。
$ cat -n thread_test.d 1 import std.stdio; 2 import std.stream; 3 import std.string; 4 5 import core.memory; 6 import core.thread; 7 8 class ThreadEx : Thread { 9 10 this(){ 11 super( &gamethread ) ; 12 } 13 14 private void gamethread() { 15 int[int] array ; 16 17 writef("enter Thread\n") ; 18 for( int i=0 ; i<9 ; i++ ){ 19 array[i]=i*2 ; 20 } 21 for( int j=0 ; j<10 ; j++ ){ 22 if( (j in array)!=null ){ 23 array[j] += 1 ; 24 } 25 } 26 sleep(10_000_000_0) ; // 10sec 27 writef("leave Thread\n") ; 28 } 29 } 30 31 void main(string[] args) 32 { 33 GC.disable(); 34 writef("start\n") ; 35 auto t = new ThreadEx(); 36 writef("%d\n",t.isRunning()) ; 37 t.start(); 38 writef("%d\n",t.isRunning()) ; 39 for( int i=0 ; i<10000000 ; i++ ){} 40 GC.collect(); 41 writef("end\n") ; 42 } $ gdc -g thread_test.d $ gdb ./a.exe GNU gdb (GDB) 7.2 Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "mingw32". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from C:\cygwin\home\tane\develop\dlang\test/./a.exe...done. (gdb) run Starting program: C:\cygwin\home\tane\develop\dlang\test/./a.exe [New Thread 4564.0x1340] [New Thread 4564.0x13cc] Program received signal SIGSEGV, Segmentation fault. rt_processGCMarks (tls=...) at ../../../libphobos/rt/lifetime.d:438 438 if(cache.base != null && gc_isCollecting(cache.base)) (gdb) where #0 rt_processGCMarks (tls=...) at ../../../libphobos/rt/lifetime.d:438 #1 0x00406c63 in thread_processGCMarks () at ../../../libphobos/core/thread.d:2611 #2 0x00429abb in fullcollect (this=..., stackTop=0x22fc1c) at ../../../libphobos/gc/gcx.d:2507 #3 0x0042a054 in fullcollectshell (this=...) at ../../../libphobos/gc/gcx.d:2325 #4 0x0042a18b in fullCollect (this=...) at ../../../libphobos/gc/gcx.d:1257 #5 0x0041d732 in gc_collect () at ../../../libphobos/gc/gc.d:155 #6 0x00401575 in main (args=...) at thread_test.d:40 #7 0x00417cdb in runMain () at ../../../libphobos/rt/dmain2.d:529 #8 0x00417d50 in tryExec (dg=...) at ../../../libphobos/rt/dmain2.d:480 #9 0x00417e64 in runAll () at ../../../libphobos/rt/dmain2.d:544 #10 0x00417d50 in tryExec (dg=...) at ../../../libphobos/rt/dmain2.d:480 #11 0x004185d9 in _d_run_main (argc=1, argv=0x3e4fb8, main_func=0x40148e <main>) at ../../../libphobos/rt/dmain2.d:554 #12 0x004019a8 in main (argc=1, argv=0x3e4fb8) at ../../../libphobos/rt/cmain.d:5 (gdb)
421 : // we expect this to be called with the lock in place 422 : extern(C) void rt_processGCMarks(void[] tls) 423 : { 424 : // called after the mark routine to eliminate block cache data when it 425 : // might be ready to sweep 426 : 427 : debug(PRINTF) printf("processing GC Marks, %x\n", tls.ptr); 428 : int debug_var1 = __blkcache_offset ; 429 : uint debug_var2 = cast(uint)(tls.ptr) ; 430 : auto cache = *cast(BlkInfo **)(tls.ptr + __blkcache_offset); 431 : if(cache) 432 : { 433 : debug(PRINTF) foreach(i; 0 .. N_CACHE_BLOCKS) 434 : { 435 : printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr); 436 : } 437 : auto cache_end = cache + N_CACHE_BLOCKS; 438 : for(;cache < cache_end; ++cache) 439 : { 440 : if(cache.base != null && gc_isCollecting(cache.base)) :
(gdb) print/x debug_var1 $8 = 0x138 (gdb) print/x debug_var2 $9 = 0x3e320c (gdb) print/x cache $10 = 0x9090909 (gdb) print/x cache[0].base Cannot access memory at address 0x9090909
(gdb) print/x *(BlkInfo **)(tls.ptr+debug_var1) $14 = 0x9090909 (gdb) print/x (BlkInfo **)(tls.ptr+debug_var1) $15 = 0x3e3344 (gdb) x/16w $15 0x3e3344: 0x09090909 0x09090909 0x09090909 0x09090909 0x3e3354: 0x09090909 0x09090909 0x09090909 0x09090909 0x3e3364: 0x09090909 0x09090909 0x09090909 0x09090909 0x3e3374: 0x09090909 0x09090909 0x0c0c0c09 0x0c0c0c0c (gdb) x/64w 0x3e3300 0x3e3300: 0x28282828 0x28282828 0x28282828 0x28282828 0x3e3310: 0x28282828 0x28282828 0x08080808 0x0c0c0800 0x3e3320: 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c 0x3e3330: 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c 0x0a0a080c 0x3e3340: 0x090a0a0a 0x09090909 0x09090909 0x09090909 0x3e3350: 0x09090909 0x09090909 0x09090909 0x09090909 0x3e3360: 0x09090909 0x09090909 0x09090909 0x09090909 0x3e3370: 0x09090909 0x09090909 0x09090909 0x0c0c0c09 0x3e3380: 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c 0x3e3390: 0x0c0c0c0c 0x0c0c0c0c 0x00000c0c 0x00000000 0x3e33a0: 0x00000000 0x00000000 0x00000000 0x00000000 0x3e33b0: 0x00000000 0x00000000 0x00000000 0x00000000 0x3e33c0: 0x00000000 0x00000000 0x00000000 0x00000000 0x3e33d0: 0x00000000 0x00000000 0x00000000 0x62610000 0x3e33e0: 0x66656463 0x6a696867 0x6e6d6c6b 0x7271706f 0x3e33f0: 0x76757473 0x7a797877 0x00000000 0x42410000
昼頃起床。
先日のビルドはエラー無く終了。std.stdint.oをlibgphobos2に含めるひと手間を入れて
make install。で、試してみたのですが状況変わらず。そんな訳で、
┌───────────────────────┬─┐ │platform: compiler │RS│ ├───────────────────────┼─┤ │linux: gcc-4.5.2 + goshawk-gdc-79ed94287f94 │OK│ ├───────────────────────┼─┤ │Windows: dmd 2.052 │OK│ ├───────────────────────┼─┤ │MinGW: gcc-4.5.2 + goshawk-gdc-007de89f7694 │NG│ ├───────────────────────┼─┤ │MinGW: gcc-4.5.2 + goshawk-gdc-79ed94287f94 │NG│ └───────────────────────┴─┘
早めに帰着。
先日のうまく動かないコードをdmdのオリジナルのコンパイラで試してみたり。
結果はうまく動いてみたり。
あと、r512:79ed94287f94 というバージョンで再度gdcビルドしてみたり。
......ビルドが終わらないのとあまりの眠さで死亡。