割り込みされずに1命令でやりたかっただけ

割り込み処理で立てたフラグを読んで消すという処理をするのに、

アトミック処理のスワップ命令を使って書いたら便利そうだなと思ったが、

いや、素直に割り込みマスクしてフラグ操作するべきか? となった。


普通にフラグ変数を読んで、消すという操作は複数の命令で構成される。

ロード・分岐・ストアみたいに命令が並ぶんじゃないかな。

で、この処理をしている間に割り込み処理が入る可能性は否定できなくて、

そうすると意図したフラグ操作にならないという懸念がある。

それを回避するためには読んで消すという操作を1命令でできればよい。

これを実現する方法としてアトミック操作があって、

アトミック操作では読んで書き換えるという操作の途中状態を見せずに一息で処理できる。

フラグを読んで消すのにはスワップ命令が適していて、

読んで消すというのは、メモリの値を読んで0に入れ換えるということだからである。


シングルコアのシステムならば読んで書くが1命令というだけだけど、

マルチコアのシステムだと他のコアのアクセスに割り込まれないようにするという意味もある。

予約してメモリを書き換える

Load-Link/Store-Conditional(LL/SC)方式の話を以前紹介している。

この方式は読み出して予約(Load-Link)して、予約後に書換がない場合のみ書き込む(Store-Conditional)というもので、

これにより他のコアに割り込まれていないことが確認出来るわけである。

ARMのAArch32では複数コアで操作する変数を読んで書き換える方法はこれしかないはず。

一方でAArch64では、SWPAL命令を使えばこれが1命令で書ける。

AArch64といってもv8.1以降に限られる新しい命令らしいが。


今回の場合、心配しているのは同じコアの割り込み処理だけで、

その場合にわざわざアトミック命令を使うと他のコアにも影響してしまう?

それでパフォーマンス低下が発生してしまうのは好ましくない気がする。

実際の影響度はよくわからなくて、影響がない可能性もある。

割り込みマスク→ロード→分岐→ストア→割り込み許可というのは、

なかなかまどろっこしい気がするが、他のコアの処理には影響しない。


よくよく考えてみれば、割り込みマスク自体は避けられない気がして、

wfi命令で割り込みを待つ意味

ここで書いたのだけどWFI命令でスリープ状態で割り込みを待つ場合、

割り込みマスク→フラグ確認→フラグがない場合はWFI命令→割り込み許可

という順番でやらないとフラグ確認→WFI命令の間に割り込みが入ってしまう可能性がある。

それなら、この割り込みマスクしている間にフラグのクリアもやってしまえば、

わざわざアトミック処理を使わなくても済みますねと。

アトミック処理を使うためにインラインアセンブラを使う必要もないし。


フラグを読んで書き換えるという操作を複数のコアで行う場合はけっこう重要で、

こういう処理はスピンロックで使われることがあるという。

フラグ変数に0が入っている状態で、複数コアで同時にフラグ変数の値と1をスワップするアトミック処理を行う。

するとその中で一番乗りのコアは 0を読んで1に書き換えることができ、

2番目以降のコアは1を読んで1に書き換えるという結果になる。

このとき0が読めたコアがリソースを獲得できるという仕組みである。


マルチコアになる以前は単純に1命令で書ければいいという話だったが、

マルチコアになってからはそれでは不十分ということで、

他のコアにも途中状態を見せないアトミック処理に発展したという経緯があるようだ。