mod_dosdetector 改造版。共有メモリの初期化処理を改善した。かなり試行錯誤を繰り返すことになったが、自分なりに理解をした上で修正できたと思う。
共有メモリ機構においては、セグメントの「名前」が共有の鍵となる。名前の衝突にはくれぐれも注意しなければならない。
- 新たに共有メモリ・セグメントを作成する際、既にその名前が使用されていると、作成に失敗する
- 同じ名前を指定して attach すれば、どんなプロセスでも共有に参加できる。異なるソフトウェアに属する異なるプロセスが、異なる意図を持って同じメモリにアクセスすれば、メモリ内容は破壊されプロセスはクラッシュする
名前の衝突を防ぐための一つの工夫として、共有メモリ・セグメントの名前を”捨てて”しまう方法がある。名前を捨てることで、新たに別のプロセスが共有に参加することはできなくなる(既に共有に参加しているプロセスからは変わらずアクセスできる)。また名前を捨てた後なら、新たに同じ名前で共有メモリを作ることができるようになる。
APR では apr_shm_remove を使うことで名前を捨てることができる。上に挙げた2つの問題は、それぞれ次のようにして回避できる:
- apr_shm_create を実行する前に、その名前で apr_shm_remove を実行する
- 共有メモリの作成と初期化が終わった時点で apr_shm_remove を実行する
(もちろん厳密に言えば remove と create の間で他のプロセスが create する可能性とか、remove を実行する前にプロセスがクラッシュする可能性とかも考えられるわけだが、大部分のトラブルは回避できるはずである)。
mod_dosdetector ではバージョン0.2からこれらの対策が施されたのだが、(多分古いコードの名残で?)remove/create を実行する前に、まず既存の共有メモリ・セグメントに attach を試みるコードが入っていた。これだと偶然に同じ名前のセグメントが存在した場合にクラッシュする危険性がある。
多分もともとは、Apache が不正終了するなどして共有メモリが破棄されなかった → 再起動の際の apr_shm_create が名前の衝突でコケる、という事態に備えてこのような手順を導入したのではないかと思う。しかし対策1と2によって名前衝突の危険性はほとんどなくなったはずなので、この処理はもう役目を終えたのではないか、と考える。
参考:
- 共有メモリをAPRで使用するには
- コンパクトに必要な情報がまとめられている
- apr_shm_attach() and APR_EEXIST
- apr_shm_remove が追加されるに至った議論