编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

将变量声明为可变变量

volatile 是声明任何引用设备寄存器的变量时必须应用的一个关键字。如果不使用 volatile,编译时优化程序可能会意外删除重要访问。省略使用 volatile 可能会生成很难跟踪的错误。

要防止出现难懂的错误,必须正确使用 volatilevolatile 关键字指示编译器对已声明的对象使用精确语义,特别指示不能删除或重新排序对对象的访问。设备驱动程序必须使用 volatile 限定符的两个实例为:

  • 当数据引用外部硬件设备寄存器(即除了存储功能之外还具有负面影响的内存)时。但请注意,如果使用 DDI 数据访问函数访问设备寄存器,则无需使用 volatile

  • 当数据引用的全局内存可由多个线程访问、不受锁定保护并且依赖于内存访问的序列时。与使用锁定相比,使用 volatile 使用的资源较少。

以下示例使用 volatile。忙标志用于防止线程在设备忙时继续执行,该标志不受锁定保护:

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

测试线程将在另一个线程关闭 busy 标志时继续执行:

busy = 0;

由于 busy 会在测试线程中被频繁地访问,因此编译器可能通过将 busy 的值放在寄存器中来优化测试,并测试寄存器的内容,而无需在每次测试前都读取内存中的 busy 值。测试线程将永远无法看到 busy 的更改,其他线程将只更改内存中的 busy 值,从而导致死锁。将 busy 标志声明为 volatile 会强制在每次测试前读取其值。


注 - busy 标志的一种替代方法是使用条件变量。请参见Condition Variables in Thread Synchronization

使用 volatile 限定符时,请避免意外省略的风险。例如,以下代码

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

比下一个示例更可取:

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

尽管这两个示例在功能上等效,但第二个示例要求编写人员确保类型 struct device_reg 的每个声明中都使用 volatile。第一个示例将导致所有声明中都将数据视为可变数据,因此首选该示例。如上所述,如果使用 DDI 数据访问函数访问设备寄存器,就不必将变量限定为 volatile

如果您使用的带有 C++ 5.11 的 Oracle Solaris Studio 12.2,请使用 -xvector=no 以避免生成 MMX 指令。