Esempio n. 1
0
ADI_OSAL_STATUS adi_osal_ThreadCreate(ADI_OSAL_THREAD_HANDLE *phThread, const ADI_OSAL_THREAD_ATTR *pThreadAttr)
{
    INT8U    nErr;
    INT8U    nRetValue;
#pragma diag(push)
#pragma diag(suppress:misra_rule_6_3 : "uCOS definition gives a MISRA error, in theory OS_STK should by INT32U and not 'unsigned int'")
    OS_STK   *pStackStart;
    OS_STK   *pStackTop;
#pragma diag(pop)
    uint32_t nStkSize;
    uint32_t nAlignment;
    ADI_OSAL_STATUS eRetStatus;
    ADI_OSAL_THREAD_INFO_PTR hThreadNode;
    uint32_t  nAssignedPrio;
    ADI_OSAL_STATUS eHeapResult;

#pragma diag(push)
#pragma diag(suppress:misra_rule_13_7 : "while checking compile time errors, having boolean operation that result is an invariant is necessary")
    /* check that typecasting pThreadAttr->pStackBase is valid */
    COMPILE_TIME_ASSERT((sizeof(void*)==sizeof(uint32_t)), pointer_size_mismatch);
#pragma diag(pop)

    if (phThread == NULL)
    {
        return(ADI_OSAL_FAILED);
    }

    /* verify that the given structure is not NULL before starting to access the fields */
    if (pThreadAttr == NULL)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_FAILED);
    }

#ifdef OSAL_DEBUG
#pragma diag(push)
#pragma diag(suppress:misra_rule_1_1 : "typecasting is not allowed otherwise, notified compiler team")
    nAlignment = ((uint32_t) (pThreadAttr->pStackBase) & 0x3u);   /* an address is 32-bits on a Blackfin processor */
#pragma diag(pop)
    if((nAlignment) !=0u)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
         return(ADI_OSAL_BAD_STACK_ADDR);
    }

    if (CALLED_FROM_AN_ISR)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_CALLER_ERROR);
    }

    if (pThreadAttr->pThreadFunc == NULL)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_BAD_THREAD_FUNC);
    }

    if ((pThreadAttr->nStackSize == 0u) || ((pThreadAttr->nStackSize & 0x3u) != 0u))
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return (ADI_OSAL_BAD_STACK_SIZE);
    }

    if (strlen(pThreadAttr->szThreadName) > ADI_OSAL_MAX_THREAD_NAME)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return ( ADI_OSAL_BAD_THREAD_NAME);
    }
#endif /* OSAL_DEBUG */

/* It is assumed here that the OS is setup to have its stack to grow downward (OS_STK_GROWTH==1)
    which is the way it is setup in the Blackfin port.
    We also make the assumption that OS_STK is fixed and won't change on the user's machine which is true
    because it's also part of the Blackfin port */
#ifndef __ADSPBLACKFIN__
#warning "the following code makes some assumptions that the code runs on a blackfin because of its stack operations"
#endif
   /*Convert the stack size in bytes to elements of OS_STK */
    nStkSize = pThreadAttr->nStackSize/sizeof(OS_STK);


#pragma diag(push)
#pragma diag(suppress:misra_rule_17_1 : "Allow pointer arithmetic on non-array types")
    pStackStart = (OS_STK*) pThreadAttr->pStackBase;
    pStackTop =   &pStackStart[nStkSize-1u];
#pragma diag(pop)


    /*  OS reserve some priority level for itself. uCOS reserves
        priority level 0,1,2,3.  ADI_OSAL_UCOS_BASE_PRIO is defined to offset
        OS reserved priorities.
    */
    nAssignedPrio= pThreadAttr->nPriority + ADI_OSAL_UCOS_BASE_PRIO;

    PAUSE_PROFILING();
    /* Because the OSAL operates on thread handles rather than priority we need to maintain
       a mapping. This is done via the ADI_OSAL_THREAD_INFO structure.
       Create a object of type ADI_OSAL_THREAD_INFO which will serve as the handle */
       eHeapResult = _adi_osal_MemAlloc((void*) &hThreadNode, sizeof(ADI_OSAL_THREAD_INFO));
    RESUME_PROFILING();
    if (ADI_OSAL_SUCCESS != eHeapResult)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return (ADI_OSAL_MEM_ALLOC_FAILED);
    }
    else
    {
        ADI_OSAL_SLOT_VALUE *pTLSBuffer;

        /* save information about the thread into its structure */
        hThreadNode->nThreadPrio = (uint8_t) nAssignedPrio;

        PAUSE_PROFILING();
#pragma diag(push)
#pragma diag(suppress:misra_rule_11_4 : "typecasting is necessary to convert the local structure type in to a generic void** type required by malloc")
        eHeapResult = _adi_osal_MemAlloc((void**) &pTLSBuffer, sizeof(ADI_OSAL_SLOT_VALUE) * _adi_osal_gnNumSlots);
#pragma diag(pop)
        RESUME_PROFILING();
        if (ADI_OSAL_SUCCESS != eHeapResult )
        {
            *phThread = ADI_OSAL_INVALID_THREAD;
            
            /* Free the previously allocated memory because of a failure case */
            _adi_osal_MemFree(hThreadNode);
            return (ADI_OSAL_MEM_ALLOC_FAILED);
        }
        hThreadNode->pThreadLocalStorageBuffer = pTLSBuffer;
    }

    /* Creating a task  by calling native OS call.*/

    /* The scheduler needs to be locked so that the TaskCreation and the Name assignement
       can be done atomically. It is important because the OSTaskNameSet takes the priority
       as an argument, and the priority could have been changed within the task itself which
       starts right after OSTaskCreateExt is called */
    PAUSE_PROFILING();
    OSSchedLock();
    RESUME_PROFILING();


    PAUSE_PROFILING();
    /* the OSTCBExtPtr TCB entry (pext) is used for storing the pointer to the ADI_OSAL_THREAD_INFO structure so that
       it can be found when given the Thread Priority (uCOS task handle) */
    nRetValue = OSTaskCreateExt (pThreadAttr->pThreadFunc,
                                 pThreadAttr->pParam,
                                 pStackTop,
                                 (INT8U)  (nAssignedPrio & 0xFFu),
                                 (INT16U) nAssignedPrio,
                                 pStackStart,
                                 nStkSize,
                                 (void *)hThreadNode,
                                 (OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR) ) ;
    RESUME_PROFILING();

    switch (nRetValue)
    {
        case  OS_ERR_NONE:
            /* set the Name of the task. Maximum characters in the
              name of the task  allowed is "OS_TASK_NAME_SIZE".
              If it exceeds, it will be truncated to OS_TASK_NAME_SIZE*/
#pragma diag(push)
#pragma diag(suppress:misra_rule_11_4 : "typecasting to the type expexted by uC/OS is necessary, also necessary for the return value")
#pragma diag(suppress:misra_rule_11_5 : "the API between the OSAL and uCOS force a const --> non-const conversion.")
/* converting from a const to non-const variable could be a risk, but since the data is getting 
   copied anyway it's not an issue here.*/
/* Supression since  typecasting "szTaskName" which is char_t to INT8U */
            PAUSE_PROFILING();
            OSTaskNameSet((INT8U) nAssignedPrio,(INT8U*) pThreadAttr->szThreadName, &nErr);
            RESUME_PROFILING();
            if(nErr == OS_ERR_NONE)
            {
                /* The ADI_OSAL_THREAD_INFO structure is used as the thread handle */
               *phThread = (ADI_OSAL_THREAD_HANDLE) hThreadNode;
                eRetStatus = ADI_OSAL_SUCCESS;
            }
            else
            {
                eRetStatus = ADI_OSAL_FAILED;
            }
            break;
#pragma diag(pop)

        /* Priority of the specified task is already exists */
        case  OS_ERR_PRIO_EXIST:
            eRetStatus= ADI_OSAL_PRIORITY_IN_USE;
            break;
        /* Specified priority is out of range */
        case  OS_ERR_PRIO_INVALID:
            eRetStatus = ADI_OSAL_BAD_PRIORITY;
            break;
        /* Not enough memory to create task */
        case  OS_ERR_TASK_NO_MORE_TCB:
            eRetStatus = ADI_OSAL_MEM_ALLOC_FAILED;
            break;
        default:
            eRetStatus = ADI_OSAL_FAILED;
            break;
    }

    PAUSE_PROFILING();
    OSSchedUnlock();
    RESUME_PROFILING();
    
    if(eRetStatus != ADI_OSAL_SUCCESS)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        if (hThreadNode != NULL)
        {
            _adi_osal_MemFree(hThreadNode->pThreadLocalStorageBuffer);
            _adi_osal_MemFree(hThreadNode);
        }
    }

    return(eRetStatus);
}
Esempio n. 2
0
ADI_OSAL_STATUS adi_osal_ThreadGetName(ADI_OSAL_THREAD_HANDLE const hThread,
                                       char_t *pTaskName,
                                       uint32_t nNumBytesToCopy)
{
    char_t *sThreadName = NULL;
    INT8U nErr;
    INT8U nUcosNameSize;
    ADI_OSAL_STATUS eRetStatus;
#pragma diag(push)
#pragma diag(suppress:misra_rule_11_4 : "typecasting is necessary to convert the handle type into a useful type")
        ADI_OSAL_THREAD_INFO_PTR hThreadNode = (ADI_OSAL_THREAD_INFO_PTR) hThread;
#pragma diag(pop)
    INT16U nUcosVersion = OSVersion();

#ifdef OSAL_DEBUG
    /* check validity of the handle */
    if ((hThreadNode==NULL) || (hThread==ADI_OSAL_INVALID_THREAD))
    {
        return (ADI_OSAL_BAD_HANDLE);
    }
    if (hThreadNode->pThreadLocalStorageBuffer==NULL)
    {
        return (ADI_OSAL_BAD_HANDLE);
    }
#endif

   /* In version 2.92 or later the task stores a pointer and GetName returns it
    * so we don't  need to allocate memory for this variable because the uCOS
    * code does not copy the string to it, it simply sets the pointer 
    *
    * In older versions the maximum Task name size (OSTaskNameSize) is only set
    * in uCOS in debug mode so we cannot use it. We use UCHAR_MAX as the max
    * length because the return value is an INT8U.  
    *
    * Note that the prototype of OSTaskNameGet has changed and the pointer is
    * different.
    */

    #pragma diag(push)
    #pragma diag(suppress:misra_rule_11_4 : "typecasting is necessary to convert the char_t type into INT8U type")
    if (nUcosVersion < 292u) 
    {

    /* allocate memory to get the task name based on the maximum task name size
     */

        if (ADI_OSAL_SUCCESS != _adi_osal_MemAlloc((void*) &sThreadName, UCHAR_MAX))
        {
            return (ADI_OSAL_MEM_ALLOC_FAILED);
        }
        PAUSE_PROFILING();
        nUcosNameSize = OSTaskNameGet(hThreadNode->nThreadPrio, 
                                      (void*) sThreadName, &nErr);
        RESUME_PROFILING();

     }
     else
     {
        PAUSE_PROFILING();
        nUcosNameSize = OSTaskNameGet(hThreadNode->nThreadPrio, 
                                      (void*) &sThreadName, &nErr);
        RESUME_PROFILING();
     }

#pragma diag(pop)

    switch(nErr)
    {
        case OS_ERR_NONE:
            strncpy(pTaskName, sThreadName, nNumBytesToCopy - 1u);
            /* We zero-terminate the string in either the last element or 
               where the uCOS name finished
             */
            if (nUcosNameSize < (nNumBytesToCopy) )
            {
                pTaskName[nUcosNameSize + 1u] ='\0';

            }
            else
            {
                pTaskName[nNumBytesToCopy] ='\0';
            }

            eRetStatus = ADI_OSAL_SUCCESS;
            break;
        case OS_ERR_TASK_NOT_EXIST:
        case OS_ERR_PRIO_INVALID:
            eRetStatus = ADI_OSAL_BAD_HANDLE;
            break;
        case OS_ERR_NAME_GET_ISR:
            eRetStatus = ADI_OSAL_CALLER_ERROR;
            break;
        case OS_ERR_PNAME_NULL:
        default:
            eRetStatus = ADI_OSAL_FAILED;
            break;
    }

    if (nUcosVersion < 292u) 
    {
        _adi_osal_MemFree(sThreadName);
    }

    return (eRetStatus);
}
ADI_OSAL_STATUS adi_osal_ThreadCreate(ADI_OSAL_THREAD_HANDLE *phThread, const ADI_OSAL_THREAD_ATTR *pThreadAttr)
{
    INT8U    nErr;
    INT8U    nRetValue;
#pragma diag(push)
#pragma diag(suppress:misra_rule_6_3 : "uCOS definition gives a MISRA error, in theory OS_STK should by INT32U and not 'unsigned int'")
    OS_STK   *pStackStart;
    OS_STK   *pStackTop;
#pragma diag(pop)
    uint32_t nStkSize;
    ADI_OSAL_STATUS eRetStatus;
    ADI_OSAL_THREAD_INFO_PTR hThreadNode;
    uint32_t  nAssignedPrio;
    ADI_OSAL_STATUS eHeapResult;


#ifdef OSAL_DEBUG
    if (NULL == phThread)
    {
        return(ADI_OSAL_FAILED);
    }

    /* verify that the given structure is not NULL before starting to access the fields */
    if (NULL == pThreadAttr)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_FAILED);
    }

    if ( !_adi_osal_IsMemoryAligned(pThreadAttr->pStackBase) )
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_BAD_STACK_ADDR);
    }

    if (CALLED_FROM_AN_ISR)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_CALLER_ERROR);
    }

    if (NULL == pThreadAttr->pThreadFunc)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return(ADI_OSAL_BAD_THREAD_FUNC);
    }

    if (0u == pThreadAttr->nStackSize)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return (ADI_OSAL_BAD_STACK_SIZE);
    }

    if (!_adi_osal_IsMemoryAligned((void*) pThreadAttr->nStackSize))
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return (ADI_OSAL_BAD_STACK_SIZE);
    }

    if (strlen(pThreadAttr->szThreadName) > ADI_OSAL_MAX_THREAD_NAME)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return ( ADI_OSAL_BAD_THREAD_NAME);
    }

#endif

    /* This code assumes the following
        * The OS is setup to have its stack to grow downward (OS_STK_GROWTH==1)
        * OS_STK is fixed in a per-platform basis and not per-application. This is
          true because it is part of the Micrium port
     */

    /* Convert the stack size in bytes to elements of OS_STK */
    nStkSize = pThreadAttr->nStackSize/sizeof(OS_STK);

#pragma diag(push)
#pragma diag(suppress:misra_rule_17_1 : "Allow pointer arithmetic on non-array types")
    pStackStart = (OS_STK*) pThreadAttr->pStackBase;
    pStackTop =   &pStackStart[nStkSize-1u];
#pragma diag(pop)

    /*  OS reserve some priority level for itself. uCOS reserves
     *  priority level 0,1,2,3.  ADI_OSAL_UCOS_BASE_PRIO is defined to offset
     *  OS reserved priorities.
     */

    nAssignedPrio= pThreadAttr->nPriority + ADI_OSAL_UCOS_BASE_PRIO;

    /* Because the OSAL operates on thread handles rather than priority we need
     * to maintain a mapping. This is done via the ADI_OSAL_THREAD_INFO
     * structure.  Create a object of type ADI_OSAL_THREAD_INFO which will serve
     * as the handle
     */

    eHeapResult = _adi_osal_MemAlloc((void**) &hThreadNode, sizeof(ADI_OSAL_THREAD_INFO));

    if (ADI_OSAL_SUCCESS != eHeapResult)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        return (eHeapResult);
    }

    /* save information about the thread into its structure */
    hThreadNode->nThreadPrio = (ADI_OSAL_PRIORITY) nAssignedPrio;

    /* Creating a task  by calling native OS call.*/

    /* The scheduler needs to be locked so that the TaskCreation and the Name
       assignement can be done atomically. It is important because the
       OSTaskNameSet takes the priority as an argument, and the priority could
       have been changed within the task itself which starts right after
       OSTaskCreateExt is called */

    OSSchedLock();


    /* the OSTCBExtPtr TCB entry (pext) is used for storing the pointer to the
     * ADI_OSAL_THREAD_INFO structure so that
     * it can be found when given the Thread Priority (uCOS task handle)
     */
    nRetValue = OSTaskCreateExt (pThreadAttr->pThreadFunc,
                                 pThreadAttr->pTaskAttrParam,
                                 pStackTop,
                                 (INT8U)  (nAssignedPrio & 0xFFu),
                                 (INT16U) nAssignedPrio,
                                 pStackStart,
                                 nStkSize,
                                 (void *)hThreadNode,
                                 (OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR) ) ;

    switch (nRetValue)
    {
    case  OS_ERR_NONE:
        /* set the Name of the task. Maximum characters in the
          name of the task  allowed is "OS_TASK_NAME_SIZE".
          If it exceeds, it will be truncated to OS_TASK_NAME_SIZE*/
#pragma diag(push)
#pragma diag(suppress:misra_rule_11_4 : "typecasting to the type expexted by uC/OS is necessary, also necessary for the return value")
#pragma diag(suppress:misra_rule_11_5 : "the API between the OSAL and uCOS force a const --> non-const conversion.")

        hThreadNode->nThreadSignature = ADI_OSAL_THREAD_SIGNATURE;

        /* converting from a const to non-const variable could be a risk, but since the
           data is getting copied anyway it's not an issue here.*/
        /* Supression since  typecasting "szTaskName" which is char_t to INT8U */
        OSTaskNameSet((INT8U) nAssignedPrio,
                      (INT8U*) pThreadAttr->szThreadName,
                      &nErr);
        if(nErr == OS_ERR_NONE)
        {
            /* The ADI_OSAL_THREAD_INFO structure is used as the thread handle */
            *phThread = (ADI_OSAL_THREAD_HANDLE) hThreadNode;
            eRetStatus = ADI_OSAL_SUCCESS;
        }
        else
        {
            eRetStatus = ADI_OSAL_FAILED;
        }
        break;
#pragma diag(pop)

#ifdef OSAL_DEBUG
    /* Priority of the specified task is already exists */
    case  OS_ERR_PRIO_EXIST:
        eRetStatus= ADI_OSAL_PRIORITY_IN_USE;
        break;
    /* Specified priority is out of range */
    case  OS_ERR_PRIO_INVALID:
        eRetStatus = ADI_OSAL_BAD_PRIORITY;
        break;
    case  OS_ERR_TASK_CREATE_ISR:
        eRetStatus = ADI_OSAL_CALLER_ERROR;
        break;
    /* Not enough memory to create task */
    case  OS_ERR_TASK_NO_MORE_TCB:
        eRetStatus = ADI_OSAL_MEM_ALLOC_FAILED;
        break;
#endif
    default:
        eRetStatus = ADI_OSAL_FAILED;
        break;
    } /* end of switch */

    OSSchedUnlock();

    if(eRetStatus != ADI_OSAL_SUCCESS)
    {
        *phThread = ADI_OSAL_INVALID_THREAD;
        if (NULL != hThreadNode)
        {
            hThreadNode->nThreadSignature=ADI_OSAL_INVALID_THREAD_SIGNATURE;
            _adi_osal_MemFree(hThreadNode);
        }
    }

    return(eRetStatus);
}