...
When OS_TLS_TBL_SIZE
is set to 1 or greater, each task’s OS_TCB
will contain a new array called .OSTCBTLSTbl[]
as shown below. Each array element is of type OS_TLS
which is actually a pointer to void. This allows an OS_TCB
to be extended so that it can have as many TLS areas as needed.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
The number of entries (i.e., the value to set OS_TLS_TBL_SIZE
to) depends on the compiler being supported as well as whether TLS storage is needed for other purposes.
...
Finally, each .OSTCBTLSTbl[]
entry can have a ‘destructor’ associated with it. A destructor is a function that is called when the task is deleted. Destructors are common to all tasks. This means that if a destructor is assigned for a TLS ID, the same destructor will be called for all the tasks for that entry. Also, when a task is deleted, the destructor for all of the TLS IDs will be called – assuming, of course, that a destructor was assigned to the corresponding TLS ID. You set a destructor function by calling OS_TLS_SetDestruct()
and specify the TLS ID associated with the destructor as well as a pointer to the function that will be called. Note that a destructor function must be declared as follows:
Code Block | ||
---|---|---|
| ||
void MyDestructFunction (OS_TCB *p_tcb,
OS_TLS_ID id,
OS_TLS value); |
The drawing below shows the global destructor table. Note that not all implementations of os_tls.c
will have destructors for the TLS.
...
OS_TLS_TaskCreate()
should check that TLS is a feature enabled for the task being created. This is done by examining the OS_TCB
’s option field (i.e., p_tcb->Opt
) as follows:
Code Block | ||
---|---|---|
| ||
void OS_TLS_TaskCreate (OS_TCB *p_tcb)
{
OS_TLS p_tls;
if ((p_tcb->Opt & OS_OPT_TASK_NO_TLS) == OS_OPT_NONE) {
p_tls = /* Allocate storage for TLS */
p_tcb->TLS_Tbl[MyTLS_ID] = p_tls;
}
} |
void OS_TLS_TaskDel (OS_TCB *p_tcb)
...
The code below shows how OS_TLS_TaskDel()
can be implemented.
Code Block | ||
---|---|---|
| ||
void OS_TLS_TaskDel (OS_TCB *p_tcb)
{
OS_TLS_ID id;
OS_TLS_DESTRUCT_PTR *p_tbl;
for (id = 0; id < OS_TLS_NextAvailID; id++) {
p_tbl = &OS_TLS_DestructPtrTbl[id];
if (*p_tbl != (OS_TLS_DESTRUCT_PTR)0) {
(*p_tbl)(p_tcb, id, p_tcb->TLS_Tbl[id]);
}
}
} |
OS_TLS_TaskDel()
should actually check that TLS was used by the task being deleted. This is done by examining the OS_TCB
’s option field (i.e., p_tcb->Opt
) as follows:
Code Block | ||
---|---|---|
| ||
void OS_TLS_TaskDel (OS_TCB *p_tcb)
{
OS_TLS_ID id;
OS_TLS_DESTRUCT_PTR *p_tbl;
for (id = 0; id < OS_TLS_NextAvailID; id++) {
p_tbl = &OS_TLS_DestructPtrTbl[id];
if (*p_tbl != (OS_TLS_DESTRUCT_PTR)0) {
(*p_tbl)(p_tcb, id, p_tcb->TLS_Tbl[id]);
}
}
} |
An alternate implementation is shown below where OS_TLS_TaskDel()
needs to deallocate storage for the task is shown below.
...
OS_TLS_TaskSw()
should check that TLS is desired for the task being switched in. This is done by examining the OS_TCB’s option field (i.e. p_tcb->Opt) as follows:
Code Block | ||
---|---|---|
| ||
if ((p_tcb->Opt & OS_OPT_TASK_NO_TLS) == OS_OPT_NONE) {
/* TLS option enabled for this task */
} |
Compiler-Specific Lock APIs
As previously mentioned, some compilers may already have declared API functions that are called to ensure exclusive access to shared resources. For example, APIs such as _mutex_lock_file_system()
and _mutex_unlock_file_system()
could be required by the compiler to ensure exclusive access to the file system. os_tls.c might then implement these using µC/OS-III as shown below. Note that we also included the code to initialize the mutex in OS_TLS_Init()
.
Code Block | ||
---|---|---|
| ||
OS_EVENT *OS_TLS_FS_Sem; /* Needed to ensure exclusive access to the FS */
void OS_TLS_Init (INT8U *p_err)
{
OS_TLS_NextAvailID = 0u;
OS_TLS_NewLibID = OS_TLS_GetID(p_err);
if (*p_err != OS_ERR_NONE) {
return;
}
OS_TLS_FS_Sem = OSSemCreate(1);
}
void _mutex_lock_file_system (void)
{
INT8U os_err;
if (OSRunning == 0) {
return;
}
OSSemPend((OS_EVENT *)OS_TLS_FS_Sem,
(INT32U )0u,
(INT8U *)&os_err);
}
void _mutex_unlock_file_system (void)
{
INT8U err;
if (OSRunning == 0) {
return;
}
OSSemPost((OS_SEM *)OS_TLS_FS_Sem);
} |
The compiler may require the implementation of many such API functions to ensure exclusive access to the heap, environment variables, etc. These would all be found in os_tls.c
.
...