#define OSTSK_C
/******************************************************************************
 *
 *       (C) Copyright 2006, Freescale Semiconductor, Inc. All Rights Reserved.
 *
 *       THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
 *       BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
 *       Freescale Semiconductor, Inc.
 *
 * Filename:     $Source: /u/OSEK/src/os2000/src/osesys/src/ostsk.c,v $
 * Author:       $Author: c-atroshikhin $
 * Revision:     $Revision: 1.10 $
 *
 * Functions:    
 *
 * History:      Use the CVS command rlog to display revision history
 *               information.
 *
 * Description:  OSEK OS task management         
 *
 * Notes:        
 *
 ******************************************************************************/

#if !defined(OSPROPH)
#include "osprop.h"                     /* OS Properties */
#else                                   /* !defined(OSPROPH)    */
#include OSPROPH                        /* OS Properties */
#endif                                  /* !defined(OSPROPH)    */

#include <osapi.h>

/*  Global OS variables */
#if defined(OSECC) || defined(OSRESOURCE) || defined(OSCC2) ||\
  defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE)
OSTSKCB OsTaskTable[OSNTSKS];           /* Task control blocks table    */
#else                                   /* defined(OSECC) || defined(OSRESOURCE) || defined(OSCC2) ||\*/
/* defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) */
OSBYTE OsTaskStatus[OSNTSKS];           /* Tasks status*/
#if defined(OSINRES)
TaskType OsPrio2Task[OSNTSKS];          /* references from priority to task */
#endif                                  /* defined(OSINRES) */

#endif                                  /* defined(OSECC) || defined(OSRESOURCE) || defined(OSCC2) ||\*/
/* defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) */

/*  Task management */

/***************************************************************************
 * Function : ActivateTask
 *
 * Description:
 *
 * Returns: Status E_OK      
 *
 * Notes:
 *
 **************************************************************************/

StatusType ActivateTask( TaskType taskId )
{

  OSIMSAVE                              /* OSINTMASKTYPE save;       */

#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
  OSUSETASK2READYCHECK
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */

  OSOrtiSetServiceWatch( OSServiceId_ActivateTask );
#if defined(OSEXTSTATUS)
  if( OSTASKIDISINVALID )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_ActivateTask, taskId );
  }
#endif                                  /* defined(OSEXTSTATUS) */
  OSDIS( save );
  OSOrtiSetOldServiceID( OSServiceId_ActivateTask );
  if( OSTASKACTEXHAUSTED(taskId) )
  {
    OSRI( save );                       /* attempt to multiply activation */
    OSRETERROR( E_OS_LIMIT, OSServiceId_ActivateTask, taskId );
  }
#if defined(OSECC) || defined(OSRESOURCE) || defined(OSINRES) || defined(OSCC2) ||\
    defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE)
#if defined(OSECC)
#if OSNXTSKS > 0
  if( (OSTASKSTATUS(taskId) & OSTCBEXTENDED) != 0 )
  {
    OsTaskTable[taskId].set_event = OSNOEVENTS;
  }
#endif                                  /* OSNXTSKS > 0 */
#endif                                  /* defined(OSECC) */
  {
    OSTASKSTATUS(taskId) |= OSTCBSTART; /* set flag that task has no valid context yet */
  }
#endif                                  /* defined(OSECC) || defined(OSRESOURCE) || defined(OSINRES) || defined(OSCC2) ||\*/
  /* defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) */

#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
  if( (OSTask2ReadyCheck( OSTASKPRIO(taskId) ) > 0)
#if defined(OSISRNORMAL)
   && (OsIsrLevel == 0 )
#endif                                  /* defined(OSISRNORMAL) */
   )
  {
    OSDISPATCH();
  }
  else
  {
  }
#else                                   /* OSNOPREEMPT */
  OSTask2Ready(OSTASKPRIO(taskId));
  /* no call to dispatcher at all */
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */
  OSOrtiResetIdOnExit();                /* set that the caller service is finished  */
  OSRI( save );
  return( E_OK );
}

#if !(defined(OSBCC1) && !defined(OSNOFASTTERMINATE) && !defined(OSEXTSTATUS))
/***************************************************************************
 * Function : TerminateTask
 *
 * Description: Terminate the running task
 *
 * Returns: function doesn't returns if there are no errors
 *          E_OS_RESOURCE (ext.status) task still occupies resources
 *          E_OS_CALLEVEL (ext.status) call at interrupt level
 *
 * Notes: never returns
 *
 **************************************************************************/

StatusType TerminateTask( void )
{
#if defined(OSEXTSTATUS)
  OSOrtiSetServiceWatch( OSServiceId_TerminateTask );
#if defined(OSRESOURCE)
  if( OsRunning->resources != 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_TerminateTask, 0 );
  }
#endif                                  /* defined(OSRESOURCE)  */
#if defined(OSRES_SCHEDULER)
  if( (OSRUNNINGSTATUS & OSTCBSCHEDULER) != 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_TerminateTask, 0 );
  }
#endif                                  /* defined(OSRES_SCHEDULER) */
#if defined(OSRESOURCEISR)
  if( OsISRLastResource != OSNULLRES )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_TerminateTask, 0 );
  }
#endif                                  /* defined(OSRESOURCEISR) */

#if defined(OSISRENTRYEXIT)
  if( OsIsrLevel != 0 )                 /* check call level */
  {                                     /* call at interrupt level is invalid; call from hooks also checked */
    OSRETERROR( E_OS_CALLEVEL, OSServiceId_TerminateTask, 0 );
  }
#endif                                  /* defined(OSISRENTRYEXIT) */
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_TerminateTask );
#endif                                  /* defined(OSEXTSTATUS) */

  OSDI();
  OSOrtiSetOldServiceID( OSServiceId_TerminateTask );
#if defined(OSHOOKPOSTTASK)
  OSPostTaskHook();                     /* user hook or empty macros */
#endif                                  /* defined(OSHOOKPOSTTASK) */
  {
    OSRUNNINGSTATUS &= (~OSTCBNOSUSPENDED); /* clear "nonsuspended" flag */
  }
  OSRUNNINGSTATUS |= OSTCBFIRST;
  /* set flag that task has no valid context  yet */
#if defined(OSINRES)
  if( OSCLEARRUNPRIOBITISNECESSARY() )
  {                                     /* if there is no ready task of this prio.  */
    OSTask2Suspend( OSTASKRUNPRIO( OsRunning )); /* then clear bit in OsScheduler         */
  }
  OSRESETRUNPRIO();
#endif                                  /* defined(OSINRES) */

  {
    OSREMOVETASK(OsRunning);
  }
  OSTaskTerminateDispatch();            /* force dispatcher for terminate case*/

  /* never return at this point */
  return( E_OK );
}

/***************************************************************************
 * Function : ChainTask
 *
 * Description:
 *
 * Returns: Status E_OK 
 *
 * Notes: never returns
 *
 **************************************************************************/
StatusType ChainTask( TaskType taskId )
{
#if defined(OSEXTSTATUS)
  OSOrtiSetServiceWatch( OSServiceId_ChainTask );
#if defined(OSRESOURCE)
  if( OsRunning->resources != 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_ChainTask, taskId );
  }
#endif                                  /* defined(OSRESOURCE)  */
#if defined(OSRESOURCEISR)
  if( OsISRLastResource != OSNULLRES )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_ChainTask, taskId );
  }
#endif                                  /* defined(OSRESOURCEISR) */

#if defined(OSRES_SCHEDULER)
  if( (OSRUNNINGSTATUS & OSTCBSCHEDULER) != 0 )
  {                                     /* resource is occupied */
    OSRETERROR( E_OS_RESOURCE, OSServiceId_ChainTask, taskId );
  }
#endif                                  /* defined(OSRES_SCHEDULER) */

#if defined(OSISRENTRYEXIT)
  if( OsIsrLevel != 0 )                 /* check call level */
  {                                     /* call at interrupt level is invalid; call from hooks also checked */
    OSRETERROR( E_OS_CALLEVEL, OSServiceId_ChainTask, taskId );
  }
#endif                                  /* defined(OSISRENTRYEXIT) */
  if( OSTASKIDISINVALID )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_ChainTask, taskId );
  }
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_ChainTask );
#endif                                  /* defined(OSEXTSTATUS) */

  OSDI();
  OSOrtiSetOldServiceID( OSServiceId_ChainTask );
#if defined(OSHOOKPOSTTASK)
  OSPostTaskHook();                     /* user hook or empty macros */
#endif                                  /* defined(OSHOOKPOSTTASK) */

  if( ( OSTASKACTEXHAUSTED(taskId) ) && (OSTASKID(OsRunning) != taskId) )
  {                                     /* attempt to multiply activation       */
    OSEI();
    OSRETERROR( E_OS_LIMIT, OSServiceId_ChainTask, taskId );
  }
  else
  {
    /* Called task must be terminated at this point, in this case status already set to OSTCBFIRST see TerminateTask */
#if OSNXTSKS > 0
    if( (OSTASKSTATUS(taskId) & OSTCBEXTENDED) != 0 )
    {
      OsTaskTable[taskId].set_event = OSNOEVENTS;
    }
#endif                                  /* OSNXTSKS > 0 */

    {
      OSRUNNINGSTATUS &= (~OSTCBNOSUSPENDED); /* clear "nonsuspended" flag */
    }
    OSRUNNINGSTATUS |= OSTCBFIRST;
    /* set flag that task has no valid context  yet */
#if defined(OSINRES)
    if( OSCLEARRUNPRIOBITISNECESSARY() )
    {                                   /* if there is no ready task of this prio.  */
      OSTask2Suspend( OSTASKRUNPRIO( OsRunning )); /* then clear bit in OsScheduler         */
    }
    OSRESETRUNPRIO();
#endif                                  /* defined(OSINRES) */

    {
      OSREMOVETASK(OsRunning);
    }
    OSTASKSTATUS(taskId) |= OSTCBSTART; /* set flag that task has no valid context  yet */
    OSTask2Ready(taskId);
  }
  OSTaskTerminateDispatch();            /* force dispatcher for terminate case*/
  /* never return at this point */
  return( E_OK );
}

#endif                                  /* !(defined(OSBCC1) && !defined(OSNOFASTTERMINATE) && !defined(OSEXTSTATUS)) */

/***************************************************************************
 * Function : GetTaskId
 *
 * Description:
 *
 * Returns: Status E_OK 
 *
 * Notes: 
 *
 **************************************************************************/

StatusType GetTaskID( TaskRefType taskId )
{
  OSOrtiSetServiceWatch( OSServiceId_GetTaskID );
  *taskId = OSTASKID(OsRunning);
  OSOrtiServiceWatchOnExit( OSServiceId_GetTaskID );
  /* clean service watch on hook leaving */
  return( E_OK );
}

/***************************************************************************
 * Function : GetTaskState
 *
 * Description:
 *
 * Returns: Status E_OK 
 *
 * Notes: 
 *
 **************************************************************************/

StatusType GetTaskState ( TaskType taskId, TaskStateRefType state )
{
  OSIMSAVE                              /* OSINTMASKTYPE save;       */

  OSOrtiSetServiceWatch( OSServiceId_GetTaskState );
#if defined(OSEXTSTATUS)
  if( OSTASKIDISINVALID )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetTaskState, taskId );
  }
#endif                                  /* defined(OSEXTSTATUS) */

  OSDIS( save );

  if( taskId == OSTASKID(OsRunning) )
  {
    *state = RUNNING;
  }
  /* else if ECC1 , there is WAITING state */
#if defined(OSECC) && (OSNXTSKS > 0)
  else if( (OSTASKSTATUS(taskId) & OSTCBWAIT) != 0 )
  {
    *state = WAITING;
  }
#endif                                  /* defined(OSECC) && (OSNXTSKS > 0) */
  else
  {
    if( OSISTASKNOSUSPEND(taskId) )
    {
      *state = READY;
    }
    else
    {
      *state = SUSPENDED;
    }
  }

  OSRI( save );

  OSOrtiServiceWatchOnExit( OSServiceId_GetTaskState );
  /* clean service watch on hook leaving */
  return( E_OK );
}

#if defined(OSSTKCHECK) && defined(OSECC) && defined(OSHOOKERROR)
/***************************************************************************
 * Function:    OSCheckStack
 *
 * Description: Check task stack overflow for preempt context
 *
 * Returns:
 *
 * Notes:
 *
 **************************************************************************/
void OSCheckStack( void )
{
  if( ((OsRunning->status) & OSTSKEXTENDED ) != 0 ) /* Basic task has single stack*/
  {
    if( OSSTKINVALID( (OsRunning->bos) ) )
    {                                   /* call user's hook */
      OSErrorHook_noPar( E_OS_SYS_STACK );
    }
#if defined(OSSTKCHECK_U)
    if( OSSTKINVALID( (OsRunning->tos + OSSTKADDS) ) )
    {                                   /* call user's hook */
      OSErrorHook_noPar( E_OS_SYS_STACKUNDERFLOW );
    }
#endif
  }
}

#endif                                  /* defined(OSSTKCHECK) && defined(OSECC) && defined(OSHOOKERROR) */

#if defined(OSSYSSTKCHECK) && defined(OSHOOKERROR)
/***************************************************************************
 * Function:    OSCheckMainStack
 *
 * Description: Check main stack overflow 
 *
 * Returns:
 *
 * Notes:
 *
 **************************************************************************/
void OSCheckMainStack( void )
{
  if( OSSTKINVALID(OSSTACKEND) )
  {
    OSErrorHook_noPar( E_OS_SYS_MAINSTACK );
  }
#if defined(OSSTKCHECK_U)
  if( OSSTKINVALID(OsMainTOS) )
  {                                     /* call user's hook */
    OSErrorHook_noPar( E_OS_SYS_STACKUNDERFLOW );
  }
#endif
}
#if defined(OSISRNORMAL) && defined(OSECC) && defined(OSISRSTACKSIZE)
/***************************************************************************
 * Function:    OSCheckIsrStack
 *
 * Description: Check ISR stack overflow 
 *
 * Returns:
 *
 * Notes:
 *
 **************************************************************************/
void OSCheckIsrStack( void )
{
  if( OSSTKINVALID(OSISRSTKEND) )
  {
    OSErrorHook_noPar( E_OS_SYS_ISRSTACK );
  }
#if defined(OSSTKCHECK_U)
  if( OSSTKINVALID(OSISRTOS) )
  {                                     /* call user's hook */
    OSErrorHook_noPar( E_OS_SYS_STACKUNDERFLOW );
  }
#endif
}
#endif                                  /* defined(OSISRNORMAL) && defined(OSECC) && defined(OSISRSTACKSIZE) */
#endif                                  /* defined(OSSYSSTKCHECK) && defined(OSHOOKERROR) */

#if defined(OSSTKCHECK) || (OSORTIDEBUGLEVEL > 0)

/***************************************************************************
 * Function:   OSGetUsedBytes
 *
 * Description: Calculates number of used bytes
 *
 * inp:  start stack pointer, size
 *
 * Returns: number of bytes
 *
 * Notes:   num - number of long words
 *
 **************************************************************************/
OSWORD OSGetUsedBytes( const OSDWORD* _start, OSWORD num )
{
  for(; num > 0; num--, _start++ )
  {
    if( *_start != OSORTISTACKPATTERN )
    break;
  }

  return num*4;
}

/***************************************************************************
 * Function:   GetRunningStackUsage
 *
 * Description: Calculates task stack usage
 *
 * Returns:
 *
 * Notes:
 *
 **************************************************************************/
OSWORD GetRunningStackUsage( void )
{
#if defined(OSBCC) || (OSNXTSKS == 0)

  return ( OSSTKNOASSIGNED );           /* single stack */
#else                                   /* defined(OSBCC) || (OSNXTSKS == 0) */

  if( OSTASKID(OsRunning) == OSNULLTASK ) /* No running task */
  return ( OSSTKNOASSIGNED );

  if( (OSRUNNINGSTATUS & OSTCBEXTENDED) == 0 ) /* Basic task has single stack*/
  return ( OSSTKNOASSIGNED );

  return( OSGetUsedBytes( OsRunning->bos, (OSWORD)(OsRunning->tos -
     OsRunning->bos) ) );
#endif                                  /* defined(OSBCC) || (OSNXTSKS == 0) */
}

/***************************************************************************
 * Function:    GetStackUsage
 *
 * Description: Calculates task stack usage
 *
 * inp:  task ID
 *
 * Returns: number of bytes, OSSTKNOASSIGNED if task does not have assigned
 *          stack or task have single stack
 *
 * Notes:
 *
 **************************************************************************/
OSWORD GetStackUsage( TaskType taskId )
{
#if defined(OSBCC) || (OSNXTSKS == 0)

  return ( OSSTKNOASSIGNED );           /* single stack */
#else                                   /* defined(OSBCC) || (OSNXTSKS == 0) */

  if( taskId == OSNULLTASK )            /* No running task */
  return ( OSSTKNOASSIGNED );

  if( (OSTASKSTATUS(taskId) & OSTCBEXTENDED) == 0 ) /* Basic task has single stack*/
  return ( OSSTKNOASSIGNED );

  return( OSGetUsedBytes( OsTaskTable[taskId].bos,
    (OSWORD)(OsTaskTable[taskId].tos - OsTaskTable[taskId].bos) ) );
#endif                                  /* defined(OSBCC) || (OSNXTSKS == 0) */
}
#endif                                  /* defined(OSSTKCHECK) || (OSORTIDEBUGLEVEL > 0) */

#if defined(OSUSERSTKCHECK)
/***************************************************************************
 * Function:    CheckMainStack
 *
 * Description: Check main stack overflow 
 *
 * Returns:     check status
 *
 **************************************************************************/

StatusType CheckMainStack( void )
{

  if( OSSTKINVALID(OSSTACKEND) )
  {
    return E_OS_SYS_MAINSTACK;
  }
#if defined(OSSTKCHECK_U)
  if( OSSTKINVALID(OsMainTOS) )
  {
    return E_OS_SYS_STACKUNDERFLOW;
  }
#endif
  return E_OK;
}

#if (OSNXTSKS > 0)
/***************************************************************************
 * Function:    CheckTaskStack
 *
 * Description: Check task stack overflow for preempt context
 *
 * Returns:     check status
 *
 **************************************************************************/

StatusType CheckTaskStack( TaskType taskId )
{
  if( taskId > OSNXTSKS )
  {                                     /* if task is Basic */
    return CheckMainStack();
  }
  if( OSSTKINVALID( OSTASKBOS(taskId) ) )
  {
    return E_OS_SYS_STACK;
  }
#if defined(OSSTKCHECK_U)
  if( OSSTKINVALID( OSTASKTOS(taskId) ) )
  {
    return E_OS_SYS_STACKUNDERFLOW;
  }
#endif
  return E_OK;
}
#endif                                  /* (OSNXTSKS > 0) */

#if defined(OSISRNORMAL) && defined(OSECC) && defined(OSISRSTACKSIZE)
/***************************************************************************
 * Function:    CheckIsrStack
 *
 * Description: Check ISR stack overflow 
 *
 * Returns:     check status
 *
 **************************************************************************/

StatusType CheckISRStack( void )
{

  if( OSSTKINVALID(OSISRSTKEND) )
  {
    return E_OS_SYS_ISRSTACK;
  }
#if defined(OSSTKCHECK_U)
  if( OSSTKINVALID(OSISRTOS) )
  {
    return E_OS_SYS_STACKUNDERFLOW;
  }
#endif
  return E_OK;
}

#endif                                  /* defined(OSISRNORMAL) && defined(OSECC) && defined(OSISRSTACKSIZE) */
#endif                                  /* defined(OSUSERSTKCHECK) */
