forked from gary/BCU
2
0
Fork 0
BCU/library/ucos/uC-OS2/TLS/CCES/os_tls.c

425 lines
18 KiB
C

/*
*********************************************************************************************************
* uC/OS-II
* The Real-Time Kernel
*
* Copyright 1992-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* THREAD LOCAL STORAGE (TLS) MANAGEMENT
* Cross Core Embedded Studio (CCES) IMPLEMENTATION
*
* Filename : os_tls.c
* Version : V2.93.01
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#include <ucos_ii.h>
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
const char *os_tls__c = "$Id: $";
#endif
#if OS_TASK_CREATE_EXT_EN > 0u
#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u)
/*
************************************************************************************************************************
* LOCAL VARIABLES
************************************************************************************************************************
*/
static OS_TLS_ID OS_TLS_NextAvailID; /* Next available TLS ID */
static OS_TLS_DESTRUCT_PTR OS_TLS_DestructPtrTbl[OS_TLS_TBL_SIZE];
/*
************************************************************************************************************************
* ALLOCATE THE NEXT AVAILABLE TLS ID
*
* Description: This function is called to obtain the ID of the next free TLS (Task Local Storage) register 'id'
*
* Arguments : perr is a pointer to a variable that will hold an error code related to this call.
*
* OS_ERR_NONE if the call was successful
* OS_ERR_TLS_NO_MORE_AVAIL if you are attempting to assign more TLS than you declared
* available through OS_TLS_TBL_SIZE.
*
* Returns : The next available TLS 'id' or OS_TLS_TBL_SIZE if an error is detected.
************************************************************************************************************************
*/
OS_TLS_ID OS_TLS_GetID (INT8U *perr)
{
OS_TLS_ID id;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_TLS_ID)OS_TLS_TBL_SIZE);
}
#endif
OS_ENTER_CRITICAL();
if (OS_TLS_NextAvailID >= OS_TLS_TBL_SIZE) { /* See if we exceeded the number of IDs available */
*perr = OS_ERR_TLS_NO_MORE_AVAIL; /* Yes, cannot allocate more TLS */
OS_EXIT_CRITICAL();
return ((OS_TLS_ID)OS_TLS_TBL_SIZE);
}
id = OS_TLS_NextAvailID;
OS_TLS_NextAvailID++;
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (id);
}
/*
************************************************************************************************************************
* GET THE CURRENT VALUE OF A TLS REGISTER
*
* Description: This function is called to obtain the current value of a TLS register
*
* Arguments : ptcb is a pointer to the OS_TCB of the task you want to read the TLS register from. If 'ptcb' is
* a NULL pointer then you will get the TLS register of the current task.
*
* id is the 'id' of the desired TLS register. Note that the 'id' must be less than
* 'OS_TLS_NextAvailID'
*
* perr is a pointer to a variable that will hold an error code related to this call.
*
* OS_ERR_NONE if the call was successful
* OS_ERR_OS_NOT_RUNNING if the kernel has not started yet
* OS_ERR_TLS_ID_INVALID if the 'id' is greater or equal to OS_TLS_NextAvailID
* OS_ERR_TLS_NOT_EN if the task was created by specifying that TLS support was not
* needed for the task
*
* Returns : The current value of the task's TLS register or 0 if an error is detected.
*
* Note(s) : 1) ptcb->OSTCBOpt contains options passed to OSTaskCreateExt(). One of these options (OS_OPT_TASK_NO_TLS)
* is used to specify that the user doesn't want TLS support for the task being created. In other words,
* by default, TLS support is enabled if OS_TLS_TBL_SIZE is defined and > 0 so the user must
* specifically indicate that he/she doesn't want TLS supported for a task.
************************************************************************************************************************
*/
OS_TLS OS_TLS_GetValue (OS_TCB *ptcb,
OS_TLS_ID id,
INT8U *perr)
{
OS_TLS value;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_TLS)0);
}
#endif
#if OS_ARG_CHK_EN > 0u
if (id >= OS_TLS_NextAvailID) { /* Caller must specify an ID that's been assigned */
*perr = OS_ERR_TLS_ID_INVALID;
return ((OS_TLS)0);
}
#endif
OS_ENTER_CRITICAL();
if (ptcb == (OS_TCB *)0) { /* Does caller want to use current task's TCB? */
ptcb = OSTCBCur; /* Yes */
if (OSTCBCur == (OS_TCB *)0) { /* Is the kernel running? */
OS_EXIT_CRITICAL(); /* No, then caller cannot specify NULL */
*perr = OS_ERR_OS_NOT_RUNNING;
return ((OS_TLS)0);
}
}
if ((ptcb->OSTCBOpt & OS_TASK_OPT_NO_TLS) == OS_TASK_OPT_NONE) {/* See if TLS is available for this task */
value = ptcb->OSTCBTLSTbl[id]; /* Yes */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return ((OS_TLS)value);
} else {
OS_EXIT_CRITICAL(); /* No */
*perr = OS_ERR_TLS_NOT_EN;
return ((OS_TLS)0);
}
}
/*
************************************************************************************************************************
* DEFINE TLS DESTRUCTOR FUNCTION
*
* Description: This function is called by the user to assign a 'destructor' function to a specific TLS. When a task is
* deleted, all the destructors are called for all the task's TLS for which there is a destructor function
* defined. In other when a task is deleted, all the non-NULL functions present in OS_TLS_DestructPtrTbl[]
* will be called.
*
* Arguments : id is the ID of the TLS destructor to set
*
* pdestruct is a pointer to a function that is associated with a specific TLS register and is called when
* a task is deleted. The prototype of such functions is:
*
* void MyDestructFunction (OS_TCB *ptcb,
* OS_TLS_ID id,
* OS_TLS value);
*
* you can specify a NULL pointer if you don't want to have a fucntion associated with a TLS
* register. A NULL pointer (i.e. no function associated with a TLS register) is the default
* value placed in OS_TLS_DestructPtrTbl[].
*
* perr is a pointer to an error return code. The possible values are:
*
* OS_ERR_NONE The call was successful.
* OS_ERR_TLS_ID_INVALID You you specified an invalid TLS ID
* OS_ERR_TLS_DESTRUCT_ASSIGNED If a destructor has already been assigned to the TLS ID
*
* Returns : none
*
* Note : none
************************************************************************************************************************
*/
void OS_TLS_SetDestruct (OS_TLS_ID id,
OS_TLS_DESTRUCT_PTR pdestruct,
INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
if (id >= OS_TLS_NextAvailID) { /* See if we exceeded the number of TLS IDs available */
*perr = OS_ERR_TLS_ID_INVALID;
return;
}
if (OS_TLS_DestructPtrTbl[id] != (OS_TLS_DESTRUCT_PTR)0) { /* Can only assign a destructor once */
*perr = OS_ERR_TLS_DESTRUCT_ASSIGNED;
return;
}
OS_ENTER_CRITICAL();
OS_TLS_DestructPtrTbl[id] = pdestruct;
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
}
/*
************************************************************************************************************************
* SET THE CURRENT VALUE OF A TASK TLS REGISTER
*
* Description: This function is called to change the current value of a task TLS register.
*
* Arguments : ptcb is a pointer to the OS_TCB of the task you want to set the task's TLS register for. If 'ptcb'
* is a NULL pointer then you will change the TLS register of the current task.
*
* id is the 'id' of the desired task TLS register. Note that the 'id' must be less than
* 'OS_TLS_NextAvailID'
*
* value is the desired value for the task TLS register.
*
* perr is a pointer to a variable that will hold an error code related to this call.
*
* OS_ERR_NONE if the call was successful
* OS_ERR_OS_NOT_RUNNING if the kernel has not started yet
* OS_ERR_TLS_ID_INVALID if you specified an invalid TLS ID
* OS_ERR_TLS_NOT_EN if the task was created by specifying that TLS support was not
* needed for the task
*
* Returns : none
*
* Note(s) : 1) ptcb->OSTCBOpt contains options passed to OSTaskCreateExt(). One of these options (OS_TASK_OPT_NO_TLS) is
* used to specify that the user doesn't want TLS support for the task being created. In other words,
* by default, TLS support is enabled if OS_TLS_TBL_SIZE is defined and > 0 so the user must
* specifically indicate that he/she doesn't want TLS supported for a task.
************************************************************************************************************************
*/
void OS_TLS_SetValue (OS_TCB *ptcb,
OS_TLS_ID id,
OS_TLS value,
INT8U *perr)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#if OS_ARG_CHK_EN > 0u
if (id >= OS_TLS_NextAvailID) { /* Caller must specify an ID that's been assigned */
*perr = OS_ERR_TLS_ID_INVALID;
return;
}
#endif
OS_ENTER_CRITICAL(); /* Does caller want to use current task's TCB? */
if (ptcb == (OS_TCB *)0) { /* Yes */
ptcb = OSTCBCur; /* Is the kernel running? */
if (OSTCBCur == (OS_TCB *)0) { /* No, then caller cannot specify NULL */
OS_EXIT_CRITICAL();
*perr = OS_ERR_OS_NOT_RUNNING;
return;
}
}
if ((ptcb->OSTCBOpt & OS_TASK_OPT_NO_TLS) == OS_TASK_OPT_NONE) { /* See if TLS is available for this task */
ptcb->OSTCBTLSTbl[id] = value; /* Yes */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
} else {
OS_EXIT_CRITICAL(); /* No */
*perr = OS_ERR_TLS_NOT_EN;
}
}
/*
************************************************************************************************************************
************************************************************************************************************************
* uC/OS-III INTERNAL FUNCTIONS
* DO NOT CALL FROM THE APPLICATION CODE
************************************************************************************************************************
************************************************************************************************************************
*/
/*
************************************************************************************************************************
* INITIALIZE THE TASK LOCAL STORAGE SERVICES
*
* Description: This function is called by uC/OS-III to initialize the TLS id allocator.
*
* This function also initializes an array containing function pointers. There is one function associated
* to each task TLS register and all the functions (assuming non-NULL) will be called when the task is
* deleted.
*
* Arguments : perr is a pointer to an error return value. Current error can be:
*
* OS_ERR_NONE if the call was successful
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/
void OS_TLS_Init (INT8U *perr)
{
OS_TLS_ID i;
OS_TLS_NextAvailID = 0u;
for (i = 0u; i < OS_TLS_TBL_SIZE; i++) {
OS_TLS_DestructPtrTbl[i] = (OS_TLS_DESTRUCT_PTR)0;
}
*perr = OS_ERR_NONE;
}
/*
************************************************************************************************************************
* TASK CREATE HOOK
*
* Description: This function is called by OSTaskCreateExt()
*
* Arguments : ptcb is a pointer to the OS_TCB of the task being created.
*
* Returns : none
*
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
*
* 2) OSTaskCreateExt() clears all entries in ptcb->OSTCBTLSTbl[] before calling OS_TLS_TaskCreate() so no
* need to this here.
************************************************************************************************************************
*/
void OS_TLS_TaskCreate (OS_TCB *ptcb)
{
(void)&ptcb;
}
/*
************************************************************************************************************************
* TASK DELETE HOOK
*
* Description: This function is called by OSTaskDel()
*
* Arguments : ptcb is a pointer to the OS_TCB of the task being deleted.
*
* Returns : none
*
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/
void OS_TLS_TaskDel (OS_TCB *ptcb)
{
OS_TLS_ID id;
OS_TLS_DESTRUCT_PTR *p_tbl;
for (id = 0; id < OS_TLS_NextAvailID; id++) { /* Call all the destructors associated with the TLS IDs */
p_tbl = &OS_TLS_DestructPtrTbl[id];
if (*p_tbl != (OS_TLS_DESTRUCT_PTR)0) {
(*p_tbl)(ptcb, id, ptcb->OSTCBTLSTbl[id]);
}
}
}
/*
************************************************************************************************************************
* TASK SWITCH HOOK
*
* Description: This function is called by OSSched() and OSIntExit() just prior to calling the context switch code
*
* Arguments : none
*
* Returns : none
*
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
*
* 2) It's assumed that OSTCBCur points to the task being switched out and OSTCBHighRdyPtr points to the
* task being switched in.
************************************************************************************************************************
*/
void OS_TLS_TaskSw (void)
{
}
#endif
#endif