著作一覧 |
インターネットワークは冷戦のたまもの、宇宙開発も冷戦のたまもの、というように戦争(の恐怖なのか、への期待なのか)ってのはテクノロジーの急激な進化をもたらす。
でも、今は大きな、世界を2分するような脅威ってのはないようだ。2つの陣営に結束してそれぞれの陣営が英知を振り絞るみたいなことはない。敵ったって、たった一人の北国の帝王とか、砂漠の狐憑きとかだ。
が、フランスの妙な水浄化の人たちや、アメリカの戦艦が次々やって来るのを見てると、もしかすると、今、新しい戦争というか臨戦態勢になって、そこから何かとんでもないブレークスルーが生まれるんじゃないか、っていう気になってくる。
砂漠の狐を狩れ (新潮文庫)(スティーヴン プレスフィールド)
ウクライナのように急激なカタストロフになるのでも、アメリカのようにどうにか落ち着かせて収束になるのでもなく、どうにか落ち着いているかも知れないが全然収束しない状況というのは、まさに冷戦と同じような臨戦態勢なわけだから。
呼び出しを次のように行うとERROR_INVALID_PARAMETER(87)になる。
ある関数の中で、
・HttpInitialize
・HttpCreateServerSession
まで実行しておき、後から別の関数で
・HttpCreateUrlGroup
を呼ぶ→ERROR_INVALID_PARAMETER。
ここで、session_idはstaticに保存しておいて、HttpCreateServerSessionで返ったものをHttpCreateUrlGroupで与えているのは確認している(もちろん、printfデバッグで、%I64dと、64ビットにしている。というか、最初単なるULONGだと思っていろいろ面倒な目にあったのでそのあたりは問題ない)。
が、
ある関数の中で
・HttpInitialize
・HttpCreateServerSession
・HttpCreateUrlGroup
と、連続して呼び出すとNO_ERRORで走りきる。
どういうマジックなんだろう?(関係ないと思うが、同一スレッドで実行していることは確認してある)。
追記:ああああ、test/unitの仕組みに引っ掛かったのか。また騙されちまった。(つまり、rubyレベルのat_exitでセッションをクローズした後にテストが走るので、その時点では確かにERROR_INVALID_PARAMETERになるのは当然。require順重要)
まだやってたのか、というわけで観て来た。実にしびれる映画だった(映画そのものというよりは題材ってことだが、映画そのものもスピード感があって良い感じだ)。
いきなり早口でぽんぽんザッカーバーグが喋るので、おお、これですなと思う(確か、レヴィンのハッカーズだと思うのだが、サスマンか誰かが回りがみんな早口でぱんぱん喋るので自分もばかだと思われないように早口で喋るようにしたといようなエピソードがあって、このての人は早口なんだろうと想像してたら、本当にそういう演出だったのでなんか気分良い)。で、引き込まれるわけで素晴らしいスタート。
で、ちょっとしたヒントからぼんぼん実装していくのがとてもかっこいい。eduがドメイン名についているとか、彼女につきあってる相手がいるか知らないかとか(でリリースをちょっと遅らせて交際ステータスを追加するとか)、そういったこと。
スクリーンショットがEmacsだなぁと思ったらEmacsがどうのと語っているし(でも字幕にはPerlは出てきてもEmacsは出てこない)、なかなか写実的なのも良い感じだ。
CFOがどっかで見たようなジャンピエールレオーだなと思ったら、多分、先週観たイシグロカズオの映画にも出てた人なのかな。
で、おっかない兄弟とかマフィアを頼もうとか言い出すおっかないその相棒とかが出てきたりするので、どうやっつけるのかと思ったら、実話を元にしているだけに結局彼らも大儲けすることになるオチで少しがっかりした。ビジネスってのはおっかないな。が、兄貴のかっこつけかたはなかなかにかっこ良い。レースも速いやつが勝つという優勝劣敗思考は好きだ。
それにしても、これはいい映画だな。10代のころとかに観たかった。すげぇリアルだ。
CFOとケンカ別れした後、デスクの上にFacebookと書かれた包み紙の2つの箱を置く。ショーンに訊かれてもそれが何かは教えない。100万会員突破の記念日だということ。CFOは何も(資金集めという点では)役に立っていないから、0.3%の保有率に落ちるのは当然であって、それと友情は別ということなのだろうが、特に説明はない。説明しなければ理解できないのであれば説明は無意味だというザッカーバークの思考方法を示した脚本なのだろうが(最初のシーンだけそれを映画的に説明している)、そういうのは他にも結構出てくる(兄弟のことは憎んで(嫌ってかも)いないというところとか、ハーバードを制覇した後にビルゲイツの講演のときにCFOがナンパされたアジア系の女性とデートしている店でエリカを見つけてうまく説明できなくて戻るとCFOに謝ったのはグッドだと言われるところ。
というエピソードがあって、交際ステータスの実装があって、そして2番目の大学としてボストンを選択するところ。(それに対してラストはぐだぐだしていて、結局送信したからステータスを更新しまくっているのだろうが、なんかおかしい)
結局、脚本家と監督の画の作り方がうまいのだろうが(ザッカーバーグは協力していないらしいので)、思考と行動のわかりやすさが映画の明解さに寄与している点は大きい。
観てない人は観といたほうがいいと思う。というか、もうDVD化されてるのか(と思ったら予約受付中か)。
どうやっても解消しなくて閉口したが、オプションーデバッグーシンボルで「除外されていないすべてのモジュール」をチェックして復活。
クラッシュダンプの解析時の設定がグローバルかつ永続化されると気付かなかったのが敗因。
static VALUE ball; static VALUE try() { return ball; } void Init_roulette() { ball = rb_str_new2("start"); rb_define_singleton_method(rb_mKernel, "try", try, 0); }
でもって使う。
require 'roulette' 1.upto(10) { p try } # いろいろ p try # いろいろ p try
わりと、Nodeに関するオブジェクトが出てきたり、inspectが無いと言われて死ぬ率が高いと思う。(もちろん、GCから保護しない(というバグ持ちプログラムの)謎動作を眺めていての経験則からだが)
今作っているおもちゃ。
おれにとってはおもちゃだが、おそらく現存する中では、安定性でも速度でもWindows Serverでは最高のRuby用のHTTPサーバになるはず。理屈の上では。
とりあえず、単独で動くようになった(test_server.rb参照)ので、Rackハンドラを内蔵させてから、マルチプロセス(Windowsなのでspawnを使う)に対応させる予定。
実行にはAdministrator権限が必須。Rubyは、1.9.3devで試している(1.8ではビルドできないし、するつもりもない)。
新国立劇場でばらの騎士。
ドイツ人が指揮者、元帥夫人、オクタヴィアン、ゾフィーとほぼ全員敵前というか原発逃亡(と思うよなぁ)してしまって一体どうなることやらと思ったら、すごく良かった(曲が良いのだからある意味当然だが)。びっくりだ。特に指揮者が変わってしまってどうなるのかと思ったオーケストラが期待以上の出来。新日フィルというのはどうにもがさつな、弦の音が汚い印象があるのだが、そういう感じも受けなかった。(むしろエッジが効いてないないのかも)
元帥夫人は他の2人が弱い分目立ったというか、きれいな声で良かったのではないかな。オクタヴィアンは1幕ではほとんど聴こえないのでこりゃだめだと思ったが、段々良くなってきた。もしかしたら初日ということもあってセーブしてたのかも(元々1幕はオーケストラが鳴り過ぎるきらいがある曲というのもあるかな)。
ゾフィーは特になにも印象がない。
だから、3重唱のところとか、元帥夫人ばかりが目立つ感じがしたが、オーケストラが実に良い音を出していたのではないかと今になって思う。名曲だ。
オックス男爵のフランツハヴラタという人は演技含めて実に良い(この人は元の配役のまま。ということは、オリジナルの配役だったらどれだけ良かったのだろうか)。なんかキャリアをみると魔笛ではザラストロとパパゲーノをやったとか書いてあるので、なんでもできてしまう器用なバリトンなのだろう。オクタヴィアンと元帥夫人の関係を悟るところのすっとんきょうな声の出し方とか。
それにしても、なんとも切ない物語ではある(だが、実にきっぱりと気持ちが良い物語でもある)。
子共がプログラムを読みながら、ホフマンスタールの「この劇のおかしさは魅力的な元帥夫人をころりと忘れてオクタヴィアンが小娘とくっつくところ」とか、シュトラウスの「この劇のおかしさは小娘の(忘れた)」とか、やたらと小娘という書き方してるけどなんでだろう? とか言うので、おそらく、見ての通り、オペラ(楽劇だけど)の観客はじいさんばあさんばかり、つまり元帥夫人のほうに近い人ばかりだからだろうとか答えたが、そういうおれがそうだった。
(実際、ゾフィーはオクタヴィアンのじゅげむのような本名をぺらぺら言えるようなつまらない人生観しか持っていない(貴族名鑑を眺めるのが趣味)のだから、どうでも良い小娘みたいな書かれ方をしてもしょうがないし、そういうふうにホフマンスタールが造形したわけだが。なんか、三顧の礼の最初のときに劉備がそれがしは漢の寿亭候のなんちゃらなんちゃらとかぺらぺら名乗って、小僧にそんなの覚えられるかバカとか言われるのを思わずにはいられないところだ)
経験を積んだ魅力的な女性が自らの老境を悟りそれを受け入れるという表面的な物語の下に、貴族社会の終焉(つまるところはヨーロッパの死ということだ)、純粋芸術(まあ、既にして楽劇や交響詩が純粋かというと微妙なところがあるわけで、それを作曲したり劇作したりしている当人たちがそれをわかっているのは間違いない)の終焉、というのが透けて見えて、しかもそれが歴史的な事実になってしまうということが、この作品の深みというやつだろう。
それにしても名曲だなぁ。
R.シュトラウス:歌劇「ばらの騎士」 [DVD](クライバー(カルロス))
(これを持っているし、演奏は全然次元が異なるといってよいのだろうが、それでも今日の出来具合であれば、おれはDVDのクライバーより新国立劇場を観るほうが好きなようだ。劇場で観るというのはやはり何かが違うのだろう)
最近仕事ではC#のやたら親切な型チェックに親しんでいるせいで、コンパイル言語で型が違っていてもエラーにならないと、そこはスルーしてしまっていた。
というわけで、Rubyのエンコーディングオブジェクトは、たとえばrb_ascii8bit_encoding()とかで取り出せるわけだが、これがVALUEだと信じ込んでしまっていた。(多分、rb_cObjectなどの仲間のような意識でいたらしい)。エンコーディングを使うのは、rb_external_str_new_with_encとかで(これは便利でtaintなStringをエンコーディング指定でいきなり作れる)、VALUE str = rb_external_str_new_with_enc("foobar", 6, rb_utf8_encoding())というように使うので、ますますVALUEっぽい。でも、実際にはrb_encoding*という型なのであった。
で、おそろしいことに、rb_hash_aset(hash, ID2SYM(rb_intern("encoding")), rb_ascii8bit_encoding())とか書いていたのですな。
当然、それはVALUE(つまりRubyのオブジェクト)ではないのでGCされたりするとその場で死ぬ。
というわけで、rb_encodingをC APIで利用してVALUEにするには、rb_enc_from_encoding(rb_encoding* enc);を呼び出す必要がある(encodingがC API用のrb_encoding*で、encがVALUEという名前っぽい。
神戸屋のデニッシュ風食パンがうまいのだが、いかにもカロリー高そうなので気になった。
そこで袋をみると100グラムあたり350キロカロリー(うろ覚え)と書いてある。ということは、今食った1切れではどのくらいなんだと調べても12枚入りとは書いてあるが、重量がわかる情報がどこにもない。バカじゃねぇかと思わず文句たれたら、妻が子供と同じ反応してるとか言う。で続けて量りがあるんだから量りゃいいじゃない。
そんな面倒なことできるけ、と応えてみたが、まさにそういう反応を狙ったパン屋のデブ化計画かもと気づいて量ってみた。(ここで~の計に関する考察が入る)
その結果山型だから多少のぶれはあるだろうが1枚あたり約160キロカロリーとの結果を得た。普通の食パンと1枚あたりではそう変わらない(小さいからだ)。
とりあえず、演能にRackハンドラを組み込んでRailsを実行できるようにした。
CancelIOを呼ばずにタイムアウト処理をしていたら、結果を取れなくなる(キャンセルしていないIOと同一ハンドラ、異なるIDで待っているのだろう)バグがあって、最初何が起きているのかわからなかった。
Railsを動かすには、rackup -s Ennou とする(Rackネイティブなアプリケーションについてはわからない。URIのディレクトリを作るために、configオプションからconfig.ruを読んで、run xxxx::Applicationからxxxxの部分を取り出すようにしているので、Rails以外の場合にconfig.ruがどうなっているか知らないからだ。
後は適当なアプリケーションを作ってJMeterかなにかでwebrickやmongrelと比較してみる予定(で、必要ならばチューニングするが、必要なければマルチプロセス版の実装へ進む)。
2月はなんか忙しかったし、3月は計画停電とか節電でどうにも身動きが取れなかったけど、桜にも葉っぱが出てきたことだし、ということで、子供とナルニアを観に行くかとなった。
なったは良いが、どこもやってないじゃん。とっくに3D上映館はガリバーや気の早いところはラブンツェルになっている。
で、探しに探して豊洲でやっていることを見つけて行ってきた。
なんかこないだ、国際展示場から歩いて帰るときに通ったあたりだなぁと思ったが、それはそれとして、中に入ったら、都内のそれも銀座から数キロ(歩いて余裕で行ける距離だというのは体験済み)のところに、あんなばかでかいショッピングモールがあるのにはたまげた。事前に駐車場は4000台収容(その時点でばかでかいのだろうとは想像はしていたが)と書いてあるので当然車で行こうと思ったが、もし満車だったら映画の時間に間に合わない(インターネットで予約販売ができるのであらかじめ買ったのであった)のでちょっと悩んでいたが、土地勘がありそうなmatarilloさんに訊いたらキッザニアは混んでいるけど(実際にはこれも節電とかの影響かも知れないがそんなには混んでい無そうだったし、外から眺めてもなんだかよくわからない不思議な施設だな)満車で入れないってことは無いよと教えてもらえて、実際にするっと入れた。
で、どーんとショッピングモール(真ん中は吹き抜けで両側に細かい店があるやつ)で、おお、ショッピングモールですなぁと少し感心しながら、飯食ったり本屋(でっかな紀伊国屋が入っている)をぶらぶらしたりしながら、観て来たのであった。
予告編でパイレーツオブカリビアンをやっていて、なんだか3Dというよりも飛び出す絵本のような2次元の板を並べたような不思議な感じで、もしかして実写の3Dってこんな気持ちの悪いやつになるのか、とちょっと慄いたが(ナルニアも実写3Dなわけだし)、本編はそんなことはなくて良い感じだった。
お話は、ナルニアだから説教臭いところはあるのだが、テンポは良いし、キャピバラみたいにどでかいネズミのリーピチープは相変わらず良い演技だしおもしろかった。というよりも唐突に出てくるドラゴンの使い方は実にうまい(子供の頃読んだのだが、ああそういえばそうだったときちんと思い出したのはかさぶたをライオンが剥がす砂浜のシーンからだ)。
・一本足のセリフの最後のパートが、棒読みのイェーイ(家庭内流行語となった)
・ユースティスのオールが丸わかり(で、おもしろい)
・英国王のスピーチ重要
ラストは思わず目に涙(子供が映画館を出てからもしゃくりあげているのにはちょっと閉口したけど)。映画としてのできは3作目がいちばんかも知れないな。オリジナルもそうだったかな? (最後のたたかいが一番好きだったのは覚えているが、リーピチープの印象があるから、確かに朝びらき丸が物語としては一番だったかも知れない)
朝びらき丸 東の海へ (カラー版 ナルニア国物語 3)(C.S. ルイス)
(で、原作はほとんど覚えていないのだが、エンディングロールにオリジナルの挿絵を使っていて、それを観ると、ユースティスとエドマンドの金髪/黒髪が逆転しているらしくて(おれは縄にぶら下がっている画のところで、あれっと思ったが、子供はもう少し前に気付いたみたいだ)そこがちょっとおもしろい)
ただ、邦題は、どうにも好きになれないリュリの曲の名前みたいで今八くらいだ。原訳題のほうが良いと思うのだがな(事前調査で~丸という名前のウケが悪かったから変えたというような記事だかPRだかを読んだので、そういうものかも知れないが)。
魔法の島の悦楽~リュリ:ディヴェルティスマン(クリスティ(ウィリアム))
(パンタというかブリジットフォンテーヌというか、リュリに対する言及がおもしろかったのでつい買ってみたが、何回聴いてもそれほど感心しない魔法の島)
考えてみたら、特にアプリケーションを作らなくても、Railsにindex.htmlを返させるだけでもWEBrickとの比較はできるのだから、JMeter使っていろいろ試してみた。
・500になりまくる→JMeterが受信完了時あるいはタイムアウト時にコネクションを切るとERROR_CONNECTION_INVALIDが返るのだがそれを考慮していなかった→レスポンスボディの送信後であれば無視するように修正。
・終結方法がかっこ悪い→waitでEINTRを見るのように修正→EINTRを先に見られると拾えない→shutdownメソッドで終了フラグを立ててwait前にチェックするように修正。
・WEBrickは作ったスレッドすべての終結をチェック(真似する)→TODO
・ThreadErrorになることがある(ある程度まではスレッドプールを実装すれば回避できるはず)→TODO
・Railsがキャッシュ関係のNoMethodErrorを出すことがある(出ないときが多い。例外をスローすると出やすい感じだがERROR_CONNECTION_INVALIDを直したらほとんど出ることがなくなった)→TODO(再現したら調べる)
という感じ。
100スレッド100回実行(=10000リクエスト)のrailsのindex.htmlを返すだけのシンプルなテストをMBPから実行すると(最初、Rackのデフォルトポートの9292が内部ファイアウォールで遮断されていることに気づかず、なぜ受信しないのかとまどった)、90%Lineが164msec、Throughputが643.3/secとなった。
200スレッド100回実行(=20000リクエスト)では90%Lineが359、Throughputが616.3/sec。
(そもそもMBPから200スレッド本当に同時に動かせているのかは怪しい気もするけど)
同じ100スレッドをWEBrickに適用するとエラーになりまくる。ResponseTimeoutが短すぎてTimeoutになっているからだと気づき(1秒に設定していた)、受信タイムアウトを10秒に変えて(接続タイムアウトは100ミリ秒)みると、90%が4558、Throughputが23.1/secとなった。200スレッドのテストはやる必要もなさそうだ(Mongrelと比較しないと意味ないかも)
100スレッドのテストでは約28倍のスループットということになる。これだけ違うのなら、まだ実装していないUnknownヘッダ変数関係の処理を入れても問題なさそうだ。(実際のアプリケーションだと、スレッド切り替えのタイミングがアプリケーションに相当依存するはずだから、もっと差は縮まる可能性は高いがやってみなければわからない。DBとのやりとりを同期IOにするとそこでスレッドが切り替えできなくなる)
-環境は、ruby 1.9.3dev (2011-04-11) [i386-mswin32_100] + Rails-3.0.6
上野で最終公演。
当初予定していたサラファーノフが膝を痛めたとかで、ゼレンスキーという人が代役。が、この代役が大物だった。一幕の回転しながら飛んで着地してその地点で回転してまた回転しながら飛んでの繰り返しが異様になめらかで、しかも宙でぴたっと停止(というのはあり得ないわけだがうまい人が跳ぶとそう見える)する。ほかに2幕の幕が落ちる瞬間とか。プログラムで経歴を見ると大ベテラン(ロシアの舞踏団の総監督も務めている)で、なるほど、と、納得した(結構来日もしているらしいのだが、おれは知らなかった)。幕間で友人が、普段持ち上げているロシア人に比べて遥かに軽いニキアなので体力が有り余っているんじゃないかとか言っていたが、確かにそんな感じの貫録たっぷりの踊りだった。というわけで良いものを観られてラッキー。
一方、確かに体格を比較すると軽くてしょうがなさそうな小出領子もきびきびとした良い感じ。子供が、そういえば最初に意識的に観たのがドンキホーテのキトリだから、こういうのもうまい人なんだよね、と言っていて、なるほどと思った。
あと、2幕を観ていてつくづく思ったが、東京バレエ団のコールドバレエはうまい。観ていて(おれは白い服着て全員でぞわぞわ踊るやつは大抵退屈で好きではないのだが)きれいだ。
spawnした子プロセスを殺したい。
後先考えなければ次のようにすれば良い。
pid = spawn('command') Process.kill :KILL, pid
だが、コンソール待ちをしているとかいろいろ理由があって、SIGKILLではなく、SIGINTを送りたい。
Process.kill :INT, pid
だが、これはまったく効かない。おかしいなと思って、win32\win32.cを眺めると、
case SIGINT: RUBY_CRITICAL({ if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {となっている。
とか書いているうちにバグを見つけてしまった。
るりまには、「0の場合はカレントプロセス……」とあるし
MSDNには、「パラメータに0を指定すると、……」とある。
しかし、win32/win32.cでは
if (pid <= 0) { errno = EINVAL; return -1; }
と、0を認めない。これ、単なるバグなのか恐るべき意図(Windows95ではどうとかを回避とか)があるのかどっちなんだろう。
今日はじめて気付いたが、Windows版64ビットrubyを作って32ビット版rubyと同じディレクトリへインストールしようとすると、名前が衝突する。
もちろん、普通にruby.exeとすれば名前が衝突するのは自明なので、configure --target=x64_mswin64 --program-suffix=64
として、ruby64.exeという名前でバイナリを作る。当然、32ビット版はruby.exeだし、拡張ライブラリはlib/ruby/1.9.1/i386-mswin32_100とlib/ruby/1.9.1/x64-mswin64_100で分離されるから、問題なさそうに見える。
が、残念。
rubyの本体は、どちらも、msvcr100-ruby191.dllなのですな。
だめじゃん。
ということは、プログラムsuffixをdll名にも反映させる必要がある。
自分でやるのは面倒だからRedmineかなぁ。
追記:
やってみたら、これだけだった。
--- win32/Makefile.sub~ 2011-04-12 00:47:07.000000000 +0900 +++ win32/Makefile.sub 2011-04-24 03:12:39.000000000 +0900 @@ -129,7 +129,7 @@ ruby_version = $(MAJOR).$(MINOR).$(TEENY !endif !ifndef RUBY_SO_NAME -RUBY_SO_NAME = $(RT)-$(RUBY_BASE_NAME)$(MAJOR)$(MINOR)$(TEENY) +RUBY_SO_NAME = $(RT)-$(PROGRAM_PREFIX)$(RUBY_BASE_NAME)$(PROGRAM_SUFFIX)$(MAJOR)$(MINOR)$(TEENY) !endif !ifndef RUBY_PLATFORM RUBY_PLATFORM = $(arch)
でも、名前が大きく変わると互換性の面からやばいのかも。どっかで議論してたりするかな?
今、32ビットRubyと64ビットRubyを同一パッケージで配布することを考えている。おれがそのほうが便利だからだ。
で、DLL名がひっかかったのだが、Gemはそんな生易しいものじゃなかった。
・batファイルのインストールに、program-prefix/sufixを微塵も考慮しない。
(これは致命的)
・extを、同じgemのlib下に直接放り込む(arcを微塵も考慮もしない)
(当然致命的)
全然、だめじゃん。
バグなのか環境なのか判断がつかない。
とりあえず、もう少し追っかけてみよう。
現象:rb_requireでSEGVする。
#include <stdio.h> #include "ruby.h" int main(int argc, char* argv[]) { ruby_init(); rb_require("socket"); return 0; }
コンパイル、実行する。
C:\Users\arton\Documents\ruby\test>cl -DNT -DWIN32 -I%INCDIR%/ruby-1 .9.1 -I%INCDIR%/ruby-1.9.1/i386-mswin32_100 test.c /MD -link /DEFAUL TLIB:%LIBDIR%/msvcr100-ruby191.lib Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. test.c Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe /DEFAULTLIB:/users/arton/lib/msvcr100-ruby191.lib test.obj C:\Users\arton\Documents\ruby\test>test <main>: [BUG] Segmentation fault ruby 1.9.3dev (2011-04-25) [i386-mswin32_100] -- Control frame information ----------------------------------------------- c:0001 p:0000 s:0002 b:0002 l:002324 d:002324 TOP -- C level backtrace information ------------------------------------------- C:\Windows\SysWOW64\ntdll.dll(NtWaitForSingleObject+0x15) [0x77B5F8C1] C:\Windows\syswow64\kernel32.dll(WaitForSingleObjectEx+0x43) [0x770F1194] C:\Windows\syswow64\kernel32.dll(WaitForSingleObject+0x12) [0x770F1148] c:\users\arton\bin\msvcr100-ruby191.dll(rb_vm_bugreport+0x95) [0x6E094614] c:\us ers\arton\documents\ruby\trunk\vm_dump.c:819 c:\users\arton\bin\msvcr100-ruby191.dll(report_bug+0xc7) [0x6E02B1F3] c:\users\a rton\documents\ruby\trunk\error.c:256 c:\users\arton\bin\msvcr100-ruby191.dll(rb_bug+0x1c) [0x6E02B229] c:\users\arton \documents\ruby\trunk\error.c:270 c:\users\arton\bin\msvcr100-ruby191.dll(sigsegv+0x3f) [0x6E0511D0] c:\users\arto n\documents\ruby\trunk\signal.c:624 C:\Windows\system32\MSVCR100.dll(XcptFilter+0x13e) [0x6FFFB9DF] [0x00B811BB] C:\Windows\syswow64\kernel32.dll(BaseThreadInitThunk+0x12) [0x770F33CA] C:\Windows\SysWOW64\ntdll.dll(RtlInitializeExceptionChain+0x63) [0x77B79ED2] -- Other runtime information -----------------------------------------------
rb_requireの中で2回JUMP_TAGを実行していて、2回目にはrb_thread_t*がNULLになっているように見えるのだが、確信が持てないというか、printfをいれてみるかな。
追記:わかった。ruby_process_optionではなく、ruby_optionsの呼び出しが必須なのだ。
#include <stdio.h> #include "ruby.h" static char* dummyargv[] = {"test", "-e", ";", NULL}; int run_node(void* arg) { rb_require("socket"); rb_eval_string("p 32"); return 0; } int main(int argc, char* argv[]) { ruby_sysinit(&argc, &argv); { RUBY_INIT_STACK; ruby_init(); return run_node(ruby_options(3, dummyargv)); } }
WCFデータサービスのウィザードを使ってデータベースからストアドプロシージャを取り込み関数インポートする。
このときパラメータがout属性だとちょっと奇妙な型が設定される。
そこで気付かずにWebGetから単純なデリゲートを記述すると以下となる。
サービスが200を設定したあとにコネクションが切断される。
IIS側のログはレスポンス長ゼロの正常終了を示す。
トレースも200のログとなる(レスポンスに関するモジュールがスキップされているので何か良からぬことが起きているのはログの中を読めばわかる)
単なるHTTPゲートウェイとして利用しようと、機械的デリゲートコードを生成していくと、とんでもない死に方をする。
decimalを与えた場合のように変換不能で例外になってくれれば良いのだが。
x86版は当たり前の日常で利用するからX64版がすべてとは思わないが、やたらめったらとスレッドを作るとX86版では当然だがメモリが確保できなくなって死ぬ。
しかしX64版ではメモリが尽きる前にIO(それでもCPUは余っているのだよなぁ)が飽和する。
ということは、X64版ならあまり物事を考えなくても大量のリクエストがさばける、ということ。
おとといのバグ。
バグ自体はくだらないのだが、原因追究に無駄な時間を使ったのでメモ。
次のようなプログラムを作った。
void Write(string templ, params object[] args) { string msg = string.Format(templ, args); ...//IOを伴ういろいろな処理 } void FooBar(object a, object b, object c, object d) { ... Write("{0} {1} {2} {3}", a, b, c, d); ... }
が、テンプレートのパターンと引数に齟齬があり、例外が投げられるバグが見つかった(たとえば、{}内で特定の型を指定しているのに、引数がそれとは合わないなど)。
そこで、以下のようにした。
void WriteAsABCD(object a, object b, object c, object d) { Write("{0} {1} {2} {3}", a, b, c, d); } void WriteAsABDC(object a, object b, object c, object d) { Write("{0} {1} {3} {2}", a, b, c, d); } void FooBar(object a, object b, object c, object d) { ... WriteAsABCD(a, b, c, d); ... }
ところが、実際にはこの修正では引数の型指定がテンプレートと合わなければ修正前と同じことが起きる道理だ。
したがって(実は予想もつかない引数を与えるやつがいるのが原因でやはり)例外が発生する(このメソッド自体が型をアンマーシャルするので、パラメータの型はobjectにせざるを得ないとか、いろいろ理由があって型はobject以外にできない)。
このときReleaseモードでコンパイルしているため、メソッド名と行番号のみがバックトレースに入る。
ArgumentError: ... Foo::Write ... Foo::FooBar ...
ここですっかりだまされてしまった。
FooBarがWriteを呼び出すのは、修正前のバージョンだ。修正後のバージョンであれば、Foo::FooBarとFoo::Writeの間にFoo::WriteAsABCDが呼ばれているはずだ。したがって、例外を起こしているプログラムは修正前のバージョンに違いない。
だが、どう調べても実行時に呼ばれているのは修正後のバージョンに見える。PATHにも間違いはなさそうだ(多分)。が、実行時にカレントディレクトリを変えているとか、そこがTemporaryでそこにバックアップされた古いプログラムが存在するとかか?
だが、どう実行しても(実行環境は固有の環境で、デバッガなどは使えない。ネットワークから隔離されているのでリモートデバッガもあり得ない。また、開発環境は実行環境固有の環境を持ちえないので、開発環境でテストすることもあまり意味がない(ユニットテストとモックがあるわけだが、ここではそれをしていないのが大間違いだが、後の祭りである)例外になるし、バックトレースは上記の内容だし、実行しているのは修正後としか思えない。
こういうとき、何を疑うべきだろうか?
もちろんソースコードを疑うべきだ。そして修正前のプログラムにバグがあるのはわかっている。
まあ、瞬時にわからなかったのはしょうがないかなぁとは思うが、それにしても数分で気づけよとは思う。(実際には数十分かかった)
これがトライ&エラーが簡単な環境ならば、printfデバッグですぐにわかるわけだが、それができないときは頭だけが頼りだな(いや、その前にユニットテストをちゃんと作っとけというのはあるけど)。
ジェズイットを見習え |
_ ムムリク [奪取はデニッシュと掛かっているのでしょうかw 神戸屋さんのパン、久しく食べていません・・・]
_ arton [何となくクロポトキンのパンの略取をちょっと変えてみました。]