Kernel Applications
INCLUDE_CPLUS_DEMANGLER
6 Multitasking .8 Shared Code and Reentrancy
6.8.1 Dynamic Stack Variables
Many subroutines are pure code, having no data of their own except dynamic stack variables. They work exclusively on data provided by the caller as parameters. The linked-list library, lstLib, is a good example of this. Its routines operate on lists and nodes provided by the caller in each subroutine call.
Subroutines of this kind are inherently reentrant. Multiple tasks can use such routines simultaneously, without interfering with each other, because each task does indeed have its own stack. See Figure 6-5.
6.8.2 Guarded Global and Static Variables
Some libraries encapsulate access to common data. This kind of library requires some caution because the routines are not inherently reentrant. Multiple tasks simultaneously invoking the routines in the library might interfere with access to common variables. Such libraries must be made explicitly reentrant by providing a mutual-exclusion mechanism to prohibit tasks from simultaneously executing critical sections of code. The usual mutual-exclusion mechanism is the mutex semaphore facility provided by semMLib and described in 7.6.4 Mutual-Exclusion Semaphores, p.125.
6.8.3 Task-Specific Variables
Task-specific variables can be used to ensure that shared code is reentrant by providing task-specific variables of the same name that are located in each task’s stack, instead of a standard global or static variables. Each task thereby has its own unique copy of the data item.This allows, for example, several tasks to reference a private buffer of memory and while referring to it with the same global variable
Figure 6-5 Stack Variables and Shared Code
TASKS TASK STACKS COMMON SUBROUTINE
...
Also note that each task has a VxWorks events register, which receives events sent from other tasks, ISRs, semaphores, or message queues. See 7.9 VxWorks Events, p.137 for more information about this register, and the routines used to interact with it.
Thread-Local Variables: __thread Storage Class
Thread-local storage is a compiler facility that allows for allocation of a variable such that there are unique instances of the variable for each thread (or task, in VxWorks terms).
Configure VxWorks with the INLCUDE_TLS component for thread-local storage support.
The __thread storage class instructs the compiler to make the defined variable a thread-local variable. This means one instance of the variable is created for every task in the system. The compiler key word is used as follows:
__thread int i;
extern __thread struct state s;
static __thread char *p;
The __thread specifier may be used alone, with the extern or static specifiers, but with no other storage class specifier. When used with extern or static, __thread must appear immediately after the other storage class specifier.
The __thread specifier may be applied to any global, file-scoped static,
function-scoped static, or static data member of a class. It may not be applied to block-scoped automatic or non-static data member.
When the address-of operator is applied to a thread-local variable, it is evaluated at run-time and returns the address of the current task’s instance of that variable.
The address may be used by any task. When a task terminates, any pointers to thread-local variables in that task become invalid.
No static initialization may refer to the address of a thread-local variable.
In C++, if an initializer is present for a thread-local variable, it must be a constant-expression, as defined in 5.19.2 of the ANSI/ISO C++ standard.
For more information see the tlsLib entry in the VxWorks API reference.
NOTE: The __thread storage class variables can be used for both UP and SMP configurations of VxWorks, and Wind River recommends their use in both cases as the best method of providing task-specific variables. The taskVarLib and tlsOldLib (formerly tlsLib) facilities—for the kernel-space and user-space respectively—are not compatible with VxWorks SMP. They are now obsolete and will be removed from a future release of VxWorks. In addition to being
incompatible with VxWorks SMP, the taskVarLib and tlsOldLib facilities increase task context switch times. For information about migration, see 23.17 Migrating Code to VxWorks SMP, p.558.
! CAUTION: Do not access __thread variables from an ISR. Doing so may have unpredictable results.
6 Multitasking 6.8 Shared Code and Reentrancy
taskVarLib and Task Variables
VxWorks provides a task variable facility (with taskVarLib) that allows 4-byte variables to be added to a task’s context, so that the value of such a variable is switched every time a task switch occurs to or from its owner task.
6.8.4 Multiple Tasks with the Same Main Routine
With VxWorks, it is possible to spawn several tasks with the same main routine.
Each spawn creates a new task with its own stack and context. Each spawn can also pass the main routine different parameters to the new task. In this case, the same rules of reentrancy described in 6.8.3 Task-Specific Variables, p.109 apply to the entire task.
This is useful when the same function must be performed concurrently with different sets of parameters. For example, a routine that monitors a particular kind of equipment might be spawned several times to monitor several different pieces of that equipment. The arguments to the main routine could indicate which particular piece of equipment the task is to monitor.
In Figure 6-6, multiple joints of the mechanical arm use the same code. The tasks manipulating the joints invoke joint( ). The joint number (jointNum) is used to indicate which joint on the arm to manipulate.
NOTE: Wind River recommends using thread-local (__thread) storage class variables instead of task variables. The taskVarLib facility is obsolete and will be removed in a future release.
Figure 6-6 Multiple Tasks Utilizing Same Code
joint_1
joint_2
joint_3
joint (
int jointNum )
{
/* joint code here */
}