|
|
Do not use local static variables that have dynamic initialization expressions within a C++ device driver, especially for SCO SVR5 2.X. This refers to constructs such as the following, where the initializing expression must be computed at runtime.
int f(); /* DO NOT USE IN C++ DEVICE DRIVERS */An initial expression of a constant, such as 22 is, however, acceptable.void g() { static int i = f(); }
This restriction is necessary because such constructs need protection in multithreaded contexts; the second thread through the function must not be allowed to read the variable until the first thread through has initialized it, and the kernel environment in which device drivers operate is a multithreaded context. However, if you are sure that a function will only be executed within a single-threaded context, such as when a lock always protects calls to the function, it is safe to use this construct.
In SCO SVR5 2.X, the compiled code for this construct is not thread-safe and so cannot be used in a driver context.
In SVR5, the compiled code is thread-safe if compiled with CC -Kthread, but it uses a runtime interface in libC.so that relies on the user-level libthread.so threads library, which is not available to kernel-level code. Drivers that must use this construct can code a replacement for the following C++ runtime support routine:
extern "C" int __static_init_wait(int* addr_guard_variable) { /* The generated code sets up a guard variable for a local static object, with two bits defined: the low-order 'done bit' and the and the next-low-order 'busy bit'.This routine is passed the address of the guard variable. It then loops on the decision table shown below. ... }
Done | Busy | Decision | Notes |
---|---|---|---|
0 | 0 | return 1 in %eax |
reset due to exception in initialization;
will not happen in driver |
1 | 1 | return 0 in %eax | no longer busy |
0 | 1 | continue to wait | still busy |
1 | 0 | internal error | should not happen |