賽の河原で成仏しきれない亡者9名を発見

ゴミ箱の廃棄中メモリブロックカウントの不整合が発生する.メモリブロックカウントはgetmemでヒープからメモリブロックを取得したときにインクリメントされ,delmemで解放されたときにデクリメントされる.getmemはGlobalAllocPtrを呼び出してグローバルメモリを取得し,delmemはGlobalFreePtrでそれを返却する.これら2つの関数以外にGlobalAllocPtrとGlobalFreePtrを使っている場所は存在しない.つまり,入口と出口は完全に押さえられている.にも関わらず,何度数え直しても記録されたカウントと現物個数が一致しない.

nodule::operator deleteでは通常はdelmemを実行する代わりに,そのオブジェクトをゴミ箱に送付する.ゴミ箱が存在しない場合にはどうなるのか?ZTシステムは必ずしもゴミ箱を必要としない.ゴミ箱を設置しないというオプションでも動作するというのが設計上の要件だ.確かに,ゴミ箱廃棄中というのはかなりクリティカルな状況であることは間違いないが,それにしてもこの不一致はどこから生じているのか?

成仏しきれない仏がいるとすれば,それは賽の河原であるに違いない.そこを探してみるしかない.しかし,どうやって?いや,それは至って簡単だ.ThrowTrashCanの中でdeleteを実行している行の前後を監視して,メモリブロックカウントの推移を見ればよい.もし,deleteを通過しているにも関わらず,カウントが変化していないとすれば,そのオブジェクトが探している失踪者であることは間違いない.これで成仏しきれない9名の亡者を特定することができた.あとはトレースするだけだ.

これらの失踪者はアプリ終了時,FAMILYTREE::EraseFamilyTree→ LINKTABLE::ClearTableによって削除されているが,Shadowを持っているためゴミ箱には直行せず,Nringに一時係留された後resetUndoChainでUNDOチェーンがリセットされるタイミングでゴミ箱に移動している.UNDOチェーンのリセットではチェーンに連結されたすべてのUNDONODEが削除されるが,このUNDONODEのデストラクタ→UNDONODE::Disposeで実施している操作に問題がある.

UNDONODE::Disposeはそのノード(UNDONODE)が参照している実ノードのDELETED値をDEADに設定してからゴミ箱に送付しているが,その実ノードがShadowを持っているため,LIFE値はそのままとしている.この操作は,「Shadowを持つオブジェクトは削除してはならない」というUNDO規則による.ゴミ箱が廃棄されたときにこのオブジェクトは閻魔大王(NODULE::operator delete)の前に進み,「LIFEはセットかリセットか?」という大王の尋問に「セット」と答えるため,大王は「帰れ」と宣告し亡者は放免されて賽の河原に戻るという筋書きだ.

この筋書きが正しいとすれば,一つの簡単な解決法として「NODULE:operator deleteでは無条件にdelmemする」という方法がある.多分この解法はそれ自体としては誤っていないと思われるので,実装してみることにしよう.⇒問題なさそうだ.エラーはこれで解消されたが,UNDONODE::Disposeの扱いには問題があるので対策を講じる必要がある.⇒対処した.「Nringとゴミ箱の重複登録を禁止@20201213」という指針に従って,実ノードがShadowを持つ場合にはゴミ箱に入れないようにした.ゴミ箱を廃棄するときには,すべてのUNDONODEが削除されるので,その実ノードのShadowチェーンの最後のUNDONODEが削除されたタイミングでゴミ箱に入ることになる.

修正が大分累積してしまったので,まとめて一掃しておこう.12月10日以降の修正としては以下がある.

  1. Clean仮想関数の導入@20201210 7箇所
  2. METRIXでTREEVIEWを参照しない@20201210 1箇所
  3. 参照リンクを移動してはならない@20201210 3箇所
  4. CHAOTICSTATEでは描画要素を無視@20201211 1箇所
  5. METRIXからのNAMEBOX参照を廃止@20201211 16箇所
  6. metrixからのTREEVIEW参照を廃止@20201211 16箇所
  7. Nringとゴミ箱の重複登録を禁止@20201213 19箇所
  8. BUNSFILE:closeでバッファを解放@20201213 1箇所
  9. ENDOFAPPLICATIONではなくGROUNDZEROで終わる@20201211 2箇所
  10. countゼロの参照リストを削除する@20201214 1箇所
  11. BUNSBUFを廃止する@20201214 8箇所
  12. delmem,_delmem,delmem_を使う@20201215 2箇所
  13. NODULE:operator:deleteでは無条件にdelmemする@20201216 1箇所

この他以下のオプションがOFFになっている.

  1. COMMONHEADERSHORTの改訂@20201210
  2. Disposeの設置を義務化@20201211
  3. ゴミ箱なしの動作を確認@20201214
  4. NODULE:operator:deleteを廃止する@20201214
  5. DoublePtrで親リンク空の場合NULLSPOTを返さない@20201215

このうち,(3)のみ保留とし,それ以外はすべて廃止する.この他仮修正が11箇所ある.⇒すべてクリアした.

ZTシステム構成図7.ZELの全体図を#1 couplingで開いて,このカードを削除→UNDOでUNDOSYSTEM::UndoProcessのエラーが発生する.UNDONODEの参照する実ノードの親リンク空というエラーだ.⇒これはあり得る状態だ.この実ノードは削除され,フロート状態でNring上にある.つまり,これは「Nringとゴミ箱の重複登録を禁止」によって起きるようになった事象で,状態としてはノーマルだ.

同上操作で,FAMILYTREE::GetCardBase中(k >= hubo->margbase.kids)で停止した.huboのkids配列にカードが存在しないというエラーだ.このカードは#5 pagesetupで削除されたcouplingに代わる基準ノードで,5人兄弟の2番目.カード削除前は,coupling+COUPLINGの子どもで4人兄弟の先頭だった.母親のCOUPLINGが単身になり,単身婚の子ども1人を加えて5人兄弟になっている.

UNDOで戻ったときに親の結婚ページで兄弟4人というのは正しいが,リンクがすべて空ではどうしようもない.⇒この結婚リンクは夫が削除されたために妻の単身婚と併合され,削除されているはずなのにUNDOで<再生>されていない.⇒UNDOシステムでIsInTrashCanという関数が4箇所で使われている.UNDOはゴミ箱の存否と関わりなく動作しなくてはならないのだから,IsInTrashCanを使うことは許されない.⇒代わりに(Deleted() != EXISTING)で判定するようにした.⇒この修正だけで完全に元通り動作するようになった.

「ゴミ箱なしの動作を確認@20201214」オプションを復活させて動作を確認してみよう.今回は少し厳格に,TRASHCANのクラス定義それ自体を止めてみる.⇒確立できた.「DEFINETRASHCAN」というマクロで切り分けた.このオプションをSPECIFICATIONとすれば,「ゴミ箱なしの動作を確認@20201214」は廃止してもよいだろう.元々あった「USERECYCLESYSTEM」も廃止でよいと思う.このオプションでは「描画オブジェクトのリサイクルシステム」ということが意識されているようだが,現在のリサイクルシステムは基本的にZTのすべてのオブジェクトクラスをカバーするものとなっている.

TRASHCANのコードがどの程度アプリケーションに依存しているか,あるいはどの程度までアプリケーションから独立しているかを見てみよう.これを調べるにはnodule.hだけをインクルードしてみればよい.⇒TRASHCAN::ReuseWasteではCOMPLISTとCARDLINKの情報が必要となっている.しかし,これは多分不要だと思う.これらのクラスのコンストラクタの中でやればよいだけの話だから… 実際それは実行されているから,このコードは不要だ.⇒TRASHCAN::CleanSansyoにもNAMEBOXを参照しているコードが入っていたが,まったく不用なのでカットした.これでTRASHCANは完全にnoduleネイティブなクラスとして確立された.UNDOシステムを切り離すのも難しくないと思われるのでやってみよう.⇒実装した.

▲リサイクルシステム,UNDOシステム,参照リスト管理を止めたシステムを起動→カードを3枚一括削除してFAMILYTREE::GetCardBaseで(PHASE < DRAWSTAGE)エラーが出た.フェーズはINITIALIZEDになっている.UNDOの中で実行していた系統並び替えが実行されていないためだろう.カード削除処理中にMARGBOX::getGenerationが実行され,(coordinate() == ABSOLUTE)で停止するという事象も起きる.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA