Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

変数の volatile 宣言

volatile は、デバイスレジスタを参照する変数を宣言するときに適用する必要があるキーワードです。volatile を使用しないと、コンパイル時のオプティマイザが誤って、重要なアクセスを削除することがあります。volatile を使用しないでいると、追跡するのが困難なバグが発生する可能性があります。

見つけにくいバグを防ぐには、volatile を正しく使用する必要があります。volatile キーワードはコンパイラに、宣言されているオブジェクトの正確なセマンティクスを使用するように指示します。これは特に、オブジェクトへのアクセスの削除や並び替えを行わないようにするためです。デバイスドライバで volatile 修飾子を使う必要があるのは次の 2 つの場合です。

  • データが外部ハードウェアデバイスのレジスタ、つまりストレージのみでない副次的作用を持ったメモリーを参照している場合。ただし、デバイスレジスタにアクセスするために DDI データアクセス関数が使用されている場合は、volatile を使用する必要がないことに注意してください。

  • 複数のスレッドからアクセス可能で、ロックによって保護されておらず、順序付けのメモリーアクセスに依存しているグローバルメモリーをデータが参照している場合。volatile 使用時のリソースの消費はロックを使用する場合より少なくなります。

次の例では volatile を使用しています。デバイスがビジーのときにスレッドが継続しないようにビジーフラグが使用され、フラグはロックによって保護されていません。

while (busy) {
    /* do something else */
}

テストスレッドは、別のスレッドが busy フラグをオフにした場合は続行されます。

busy = 0;

busy はテストスレッドで頻繁にアクセスされるため、コンパイラは毎回のテストの前にメモリー内の busy の値を読み込まずに、busy の値をレジスタに置き、レジスタの内容をテストすることでテストを最適化できる可能性があります。テストスレッドから見ると busy が変化することはなく、ほかのスレッドのみがメモリー内の busy の値を変更することがあるため、デッドロックが発生する結果になります。busy フラグを volatile と宣言することで、各テストの前にフラグの値を強制的に読み取ります。


注 - busy フラグの代わりになる方法は、条件変数を使用することです。スレッド同期における条件変数を参照してください。

volatile 修飾子を使用するときには、不注意による抜けが生じないようにします。たとえば、次のコードの場合を考えます。

struct device_reg {
    volatile uint8_t csr;
    volatile uint8_t data;
};
struct device_reg *regp;

これは、もう 1 つの例よりも推奨される記述方法です。

struct device_reg {
    uint8_t csr;
    uint8_t data;
};
volatile struct device_reg *regp;

2 つの例は機能上は同等ですが、2 つ目の例では、コードの記述者は struct 型の device_reg のすべての宣言で volatile を使用するようにする必要があります。最初の例では、すべての宣言でデータが volatile として処理されることになるため、これが推奨される方法です。前述したように、デバイスレジスタにアクセスするために DDI データアクセス関数を使用すると、volatile などの修飾変数が不要になります。

C++ 5.11 とともに Oracle Solaris Studio 12.2 を使用する場合は、MMX 命令が生成されないように -xvector=no を使用してください。