バグに悩まされた。
既にある二つのモジュールから共通部分を切出し、三つのモジュールに分けるという、生産的とは言い兼ねる仕事をしていたのだが、分けた後のモジュールがうまく動かない。原因を調べてたら、自分の経験不足がよく分かった。
一つ目は、if(iState & BM_RUNNING == 0){...}
といった、Bit maskした結果が0であれば(Bitが立っていなければ)処理を行うというもの。
最初はこのコードで正しいと思っていたのだが、デバッガで追ってみると、iState
に何を入れても条件式が成立しない。変に思ってCの文法を調べてみたら、演算子の優先順位を勘違いしていた。私は、(iSate & BM_RUNNING) == 0
のつもりで書いたのだが、&
演算子より==
演算子の方が優先順位が高いため、コンパイラにはiState & (BM_RUNNING == 0)
と解釈され、常に偽となっていた。動かない道理である。
二つ目はMulti Thread環境のThread間通信(というほどのもんではないが)でのミス。
新たなThreadを作成する関数が次のようになっており、新規Threadに渡すParameterを自動変数に置いている(実際に書いたのは、エラー処理も入るのでもう少し複雑)。
void MakeThread(LPTHREAD_START_ROUTINE pfnThreadProc, void* pParam) { // Thread Startup構造体を初期化 THREAD_STARTUP Startup = {pfnThreadProc, // 新規ThreadのMain Procedure pParam, // Main Procedureに渡す引数 ::CreateEvent(NULL, FALSE, FALSE, NULL)}; // 初期化終了通知のEvent hThread = ::CreateThread(NULL, 0, ThreadEntry, &Startup, 0, &dwThreadID); // Threadを作成 ::WaitForSingleObject(Startup.hStartEvent, INFINITE)); // 作成したThreadの初期化処理が終了するまで(EventがSignal状態になるまで)待機 return; // 返る / 自動変数は消滅 }
::CreateThread()
によって作られるThreadの初期化関数ThreadEntry()は、次のようにしていた。
ULONG WINAPI ThreadEntry(void* pParam) { THREAD_STARTUP* pStartup = static_cast<THREAD_STARTUP*>(pParam); ::SetEvent(pStartup->hStartEvent); // 初期化終了を通知 pStartup->pfnThreadProc(pStartup->pThreadParams); // Main Procedure呼び出し ::ExitThread(0); // Threadを終了 return 0; }
ところが、これが動かない。デバッガで見ると、pParamの指すアドレスに妙な値が入っており、動かない理由は分かるのだが、妙な値の入っている理由が分からない。
しばらく考え込んで、pParamの指す領域が、::SetEvent()
の後は不定になる事に気が付いた。::SetEvent()
の呼び出しによって、元Thread(MakeThread()
)の::WaitForSingleObject()
が終了し、関数自体も終了する。すると、元ThreadのStartup変数は消滅し、新ThreadのpStartup変数が指す領域は不定になる。結果、Main Procedureのアドレスが失われ、どこか分からない場所に制御が渡る。
こんなバグ、書いている段階で気付きそうなものだが、それが経験の無さという奴なんだろう。
他にも、基底classでconstと定義した仮想関数を、派生classで非constにしてしまい、動的多態にならなかったという、間抜けなミスもあった。こ〜ゆ〜のに警告を出してくれるコンパイラが欲しくなる。
MSXを起動してみたら、Main RAM 7680KBの表示。
現在の環境は、内蔵(512KB) + うっかりくん(4096KB) + 改造たんせいRAM(4096KB)なので、8704KBが正しいはず。となると、怪しいのはたんせいRAMである。調べてみると案の定、うっかりくんと内蔵RAMは正常である。どうやら、一昨日のパーティション破壊も、これが原因のようである(LunaのメモリをたんせいRAMに割り当てていた)。
で、破壊されたパーティションだが、壊れていたのはブートセクタだけだったようである。DPBに渡される部分のデータに、ASCII文字列らしきデータが入っていたのが原因だったので、他のパーティションからブートセクタだけをコピーして済ませた。Volume IDが同じになってしまうが、特に問題はなさそうである。
パソコン通信やインターネット環境の入っているパーティション(230MB MO)がおかしくなった。
普通に通信を終わらせて要らないファイルを削除したら、いきなりMMの画面が化けまくる。MMのバグかと思い、コマンドプロンプトに下りてディレクトリを取っても、ディレクトリのあるセクタに適当なテキストファイルを書き込んだような状態は変わらない。
もし完全にオシャカだと、各ネットのパスワードや過去ログが消えてしまう。見た感じ、データ部分は大丈夫そうなので、FATとディレクトリを自前で作ればなんとかなりそうではある。
広瀬正のマイナス・ゼロ
を読む。
タイムマシン物の傑作という評価は知っていたのだが、流石にちと古い。それでも、ハインラインの夏への扉
ほどには古びていないし、小説的な仕掛けや描写の巧みさには、古さを吹き飛ばすような面白さがある。
ただ、この作品が作り出した(のだと思われる)時間物の基本構造を使った作品を、既にいくつも読んでいるので、ストーリーがほとんど先読みできてしまう。リアルタイムで読みたかったと思うのはこんな時である。
古本屋で星野之宣のブルーホール全2巻を買う。
シーラカンスの住む海域に、白亜紀へと続く時空を越えた青い穴が見つかるプロローグ、恐竜の闊歩する白亜紀を描く中盤、白亜紀の大絶滅と現代の危機をシンクロさせる終盤と、マンガには珍しい一級のSF作品である。ブルーホールのようなタイムトンネルを扱ったSFは少なくないが、その利用法や現代への影響を示す件は正にSense of wonder。SF者にはたまらない味わいだった。
買い物ついでに本屋に寄ったら、火浦功の新作奥様はマジ
を発見。
あの大遅筆作家がどうした事か、年1冊ペースである(大ハード
が去年の4月1日発行)。次の新作は21世紀になるだろうと思っていただけに、ただただ驚きであった(失礼な)。
中身は、表題作の「奥様はマジ」、若干固茹で「父カエル」、忍者物かも知れない「てなもんや忍法帖」の三つで、相変わらず馬鹿話ばかりである。まぁ、それが好きで読んでいるわけだが。
今回、MO SOFTでお馴染の花見沢Q太郎氏が表紙や挿絵を描いており、MSX者としては妙に嬉しかったりするわけだが、竹本泉が表紙を描いてたひと夏の経験値
のハマリ具合には届かないような気がする(火浦功と竹本泉、小説家と漫画家の違いはあれど、中身はほぼ同じ)。
James Tiptree Jr.の短編集星ぼしの荒野から
を読む。
Tiptree作品は、8年前に読んだ老いたる霊長類の星への賛歌
以来だが、素直に面白いと感じられる。以前は、悪くないと思いつつも、作品世界に入り込めないところがあったのだが、それもほぼ払拭された(Tiptreeが変わったわけではなく、私が変わったのだろう)。8年も経てば、少しは成長するという事か。
Index pageの名前を変えてみた。
だからどうしたという気分を込めた、なんとなくメビウスなタイトルである。たまたま今日になったが、別に冗談でやったわけではない。