KeSetEventの第三引数について、「WDKプログラミング」のコラムにはTRUEを指定すべき理由は全くない、と言う事が書いてある。また、DDKの説明は混乱を招くとの事で、ここで詳しく動作を解説している。
が、この説明もカーネル同期の内部動作についてわかっている(あるいはなんとなくわかっている)ことが前提のような説明で、結局難解なままだ(翻訳が良くないのか?)。
ユーザーランドでの同期コードを書いていた人なら、イベントオブジェクトをセットして待つという動作を行うのに、SignalObjectAndWaitというAPIがある事を知っていると思う。カーネルAPIには対応するようなものが無いのだが、このKeSetEventの第三引数はまさにそれを実現するためにある。
KEVENT event; KeInitializeEvent(&event, SynchronizationEvent, FALSE); KeSetEvent(&event, IO_NO_INCREMENT, TRUE); assert(KeGetCurrentIrql() == SYNCH_LEVEL); LARGE_INTEGER timeout; timeout.QuadPart = -10000000; KeWaitForSingleObject(&anotherEvent, Executive, KernelMode, FALSE, &timeout);
KeSetEventの第三引数にTRUEを指定すると、APIから戻ってきたときにSYNCH_LEVELというかなり高いIRQLが維持される。これはそのままKeWaitForSingleObjectに引き継ぐことが可能で、この間同じCPUでのプリエンプションは絶対に発生しない。この組み合わせによって、SignalObjectAndWaitと同じことが実現できる。
なお、 SYNCH_LEVELで維持するのが妥当な部分はこの操作だけなので、当然待機しないでなにか別の作業を行うのはやめておいたほうが良い。実際のところ、こんな高いIRQLでは出来ることも限られてくるのだが…
また、はじめからDISPATCH_LEVELで実行すれば、同じことが実現できるような気がするのだが、DISPATCH_LEVELで時間を指定しての待機は「お手付き」なので、やはりこの方法しかない。
(多分TEBに、このモードを実行中でSYNCH_LEVELにしたというフラグか何かがあるのだろう)
いや、「ダサい」と思うよ。WindowsカーネルのAPIは、こういうダサさが至る所に漂っている。
#この本、深い部分を述べている点では良いのだが、どうも説明がわかりにくい。
#より古い「NT Driver」の方が理解しやすい。