view src/nucleus/tcs.c @ 14:35f7a1dc9f7d

cdg-hybrid: import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 07:15:38 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/*************************************************************************/
/*                                                                       */
/*               Copyright Mentor Graphics Corporation 2002              */
/*                         All Rights Reserved.                          */
/*                                                                       */
/* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS  */
/* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS   */
/* SUBJECT TO LICENSE TERMS.                                             */
/*                                                                       */
/*************************************************************************/

/*************************************************************************/
/*                                                                       */
/* FILE NAME                                               VERSION       */
/*                                                                       */
/*      tcs.c                                          Nucleus PLUS 1.14 */
/*                                                                       */
/* COMPONENT                                                             */
/*                                                                       */
/*      TC - Thread Control                                              */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This file contains supplemental routines for the Thread Control  */
/*      component.                                                       */
/*                                                                       */
/* DATA STRUCTURES                                                       */
/*                                                                       */
/*      None                                                             */
/*                                                                       */
/* FUNCTIONS                                                             */
/*                                                                       */
/*      TCS_Change_Priority                 Change task's priority       */
/*      TCS_Change_Preemption               Change task's preemption     */
/*      TCS_Change_Time_Slice               Change task's time-slice     */
/*      TCS_Control_Signals                 Control signals              */
/*      TCS_Receive_Signals                 Receive signals              */
/*      TCS_Register_Signal_Handler         Register signal handler      */
/*      TCS_Send_Signals                    Send signals to a task       */
/*                                                                       */
/*                                                                       */
/* DEPENDENCIES                                                          */
/*                                                                       */
/*      cs_extr.h                           Common Service functions     */
/*      tc_extr.h                           Thread Control functions     */
/*      in_extr.h                           Initialization/Interrupt     */
/*                                            functions                  */
/*      tm_extr.h                           Timer Control function       */
/*      er_extr.h                           Error handling function      */
/*      hi_extr.h                           History functions            */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*        DATE                    REMARKS                                */
/*                                                                       */
/*      03-01-1994      Created initial version 1.1 from                 */
/*                      previous version of TCC.C                        */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*      04-04-1996      Modified TCS_Send_Signals,                       */
/*                      resulting in version 1.1+                        */
/*                      (spr 107)                                        */
/*      04-17-1996      updated to version 1.2                           */
/*      03-24-1998      Released version 1.3.                            */
/*      03-26-1999      Released 1.11m (new release                      */
/*                        numbering scheme)                              */
/*      04-17-2002      Released version 1.13m                           */
/*      11-07-2002      Released version 1.14                            */
/*************************************************************************/
#define         NU_SOURCE_FILE


#include        "cs_extr.h"                 /* Common service functions  */
#include        "tc_extr.h"                 /* Thread control functions  */
#include        "in_extr.h"                 /* Initialization/Interrupt  */
                                            /*   functions               */
#include        "tm_extr.h"                 /* Timer control functions   */
#include        "er_extr.h"                 /* Error handling function   */
#include        "hi_extr.h"                 /* History functions         */
#include        "profiler.h"                /* ProView interface         */


/* Define external inner-component global data references.  */

extern CS_NODE         *TCD_Created_Tasks_List;
extern TC_TCB          *TCD_Priority_List[TC_PRIORITIES];
extern UNSIGNED         TCD_Priority_Groups;
extern DATA_ELEMENT     TCD_Sub_Priority_Groups[TC_MAX_GROUPS];
extern UNSIGNED_CHAR    TCD_Lowest_Set_Bit[];
extern INT              TCD_Highest_Priority;
extern TC_TCB          *TCD_Execute_Task;
extern VOID            *TCD_Current_Thread;
extern TC_PROTECT       TCD_System_Protect;
extern INT              TMD_Time_Slice_State;



/* Define external inner-component function calls that are not available to
   other components.  */

VOID            TCT_Build_Signal_Frame(TC_TCB *task_ptr);
VOID            TCT_Protect_Switch(TC_TCB *task);
VOID            TCT_Signal_Exit(VOID);


/* Define internal function calls.  */

VOID            TCC_Signal_Shell(VOID);


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Change_Priority                                              */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function changes the priority of the specified task.  The   */
/*      priority of a suspended or a ready task can be changed.  If the  */
/*      new priority necessitates a context switch, control is           */
/*      transferred back to the system.                                  */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Change_Priority                Error checking shell         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Control_To_System               Transfer control to system   */
/*      TCT_Protect                         Protect scheduling data      */
/*      TCT_Set_Execute_Task                Set TCD_Execute_Task pointer */
/*      TCT_Unprotect                       Release protection of data   */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      task_ptr                            Task control block pointer   */
/*      new_priority                        New priority for task        */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      old_priority                        Original task priority       */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      03-01-1994      Modified function interface,                     */
/*                      added register optimizations,                    */
/*                      modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*      10-4-1999       Bug fixes - return if new                        */
/*                      priority equals old priority                     */
/*                      and don't move the head pointer                  */
/*                      unless the head node is changing                 */
/*************************************************************************/
OPTION   TCS_Change_Priority(NU_TASK *task_ptr, OPTION new_priority)
{

R1 TC_TCB      *task;                       /* Task control block ptr    */
R2 TC_TCB      *head;                       /* Head list pointer         */
R3 INT          index;                      /* Working index variable    */
OPTION          old_priority;               /* Previous priority of task */
DATA_ELEMENT    temp;                       /* Temporary variable        */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

    /* Move task control block pointer into internal pointer.  */
    task =  (TC_TCB *) task_ptr;


#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_CHANGE_PRIORITY_ID, (UNSIGNED) task,
                                        (UNSIGNED) new_priority, (UNSIGNED) 0);

#endif

    /* Protect against multiple access to the scheduling list.  */
    TCT_Protect(&TCD_System_Protect);

    /* Save the old priority of the task.  */
    old_priority =  task -> tc_priority;


    /* BUG FIX  this should probably go into an error checking routine instead of here  */
    if (!(task -> tc_priority == new_priority))
    {


       /* Check to see if the task is currently ready.  */
       if (task -> tc_status == NU_READY)
       {

           /* Remove the task from the ready list.  */

           /* Determine if the task is the only one on the list.  */
           if (task -> tc_ready_next == task)
           {

               /* Only task on the list.  Clear the task's pointers and
               clear the entry in the priority table.  */
               task -> tc_ready_next =        NU_NULL;
               task -> tc_ready_previous =    NU_NULL;
               *(task -> tc_priority_head) =  NU_NULL;

               /* Clear the sub-priority group.  */
               *(task -> tc_sub_priority_ptr) =
                  *(task -> tc_sub_priority_ptr) & ~(task -> tc_sub_priority);

               /* Determine if the main priority group needs to be cleared.
                  This is only true if there are no other bits set in this
                  sub-priority.  */
               if (*(task -> tc_sub_priority_ptr) == 0)

                   /* Clear the main priority group bit.  */
                   TCD_Priority_Groups =
                       TCD_Priority_Groups & ~(task -> tc_priority_group);
           }
           else
           {

               /* Not the only task ready at the same priority level.  */

               /* Remove from the linked-list.  */
               (task -> tc_ready_previous) -> tc_ready_next =
                                                 task -> tc_ready_next;
               (task -> tc_ready_next) -> tc_ready_previous =
                                                 task -> tc_ready_previous;



               /* Update the head pointer.  */
               /* BUG FIX - update head if head is changing priority - leave
                  it alone otherwise! */
               if(*(task -> tc_priority_head) ==  task )
               *(task -> tc_priority_head) =  task -> tc_ready_next;

               /* Clear the next and previous pointers.  */
               task -> tc_ready_next =        NU_NULL;
               task -> tc_ready_previous =    NU_NULL;
           }

           /* Now add in the task at the new priority.  */
           task -> tc_priority =  new_priority;

           /* Build the other priority information.  */
           task -> tc_priority =      new_priority;
           task -> tc_priority_head = &(TCD_Priority_List[new_priority]);
           task -> tc_sub_priority =  (DATA_ELEMENT) (1 << (new_priority & 7));
           task -> tc_priority_group =   ((UNSIGNED) 1) << (new_priority >> 3);
           task -> tc_sub_priority_ptr =
                   &(TCD_Sub_Priority_Groups[(new_priority >> 3)]);

#ifdef INCLUDE_PROVIEW
        _RTProf_DumpTask(task,RT_PROF_CHANGE_PRIORITY);
#endif
           /* Link the task into the new priority list.  */
           head =  *(task -> tc_priority_head);

           /* Determine if the list is non-empty.  */
           if (head)
           {

               /* Add the TCB to the end of the ready list.  */
               task -> tc_ready_previous =      head -> tc_ready_previous;
               (task -> tc_ready_previous) -> tc_ready_next =  task;
               task -> tc_ready_next =          head;
               (task -> tc_ready_next) -> tc_ready_previous =  task;

               /* Note that the priority bit map does not need to be
                  modified since there are other active tasks at the
                  same priority.  */
           }
           else
           {

               /* Add the TCB to an empty list.  */
               task -> tc_ready_previous =  task;
               task -> tc_ready_next =      task;
               *(task -> tc_priority_head)= task;

               /* Update the priority group bit map to indicate that this
                  priority now has a task ready.  */
               TCD_Priority_Groups =
                           TCD_Priority_Groups | (task -> tc_priority_group);

               /* Update the sub-priority bit map to show that this priority
                  is ready.  */
               *(task -> tc_sub_priority_ptr) =
                   (*(task -> tc_sub_priority_ptr)) | task -> tc_sub_priority;
           }

           /* Determine the highest priority task in the system.  */
           if (TCD_Priority_Groups & TC_HIGHEST_MASK)

               /* Base of sub-group is 0.  */
               index =  0;

           else if (TCD_Priority_Groups & TC_NEXT_HIGHEST_MASK)

               /* Base of sub-group is 8.  */
               index =  8;

           else if (TCD_Priority_Groups & TC_NEXT_LOWEST_MASK)

               /* Base of sub-group is 16.  */
               index =  16;
           else

               /* Base of sub-group is 24.  */
               index =  24;

           /* Calculate the highest available priority.  */
           index =  index + TCD_Lowest_Set_Bit[(INT)
                   ((TCD_Priority_Groups >> index) & TC_HIGHEST_MASK)];

           /* Get the mask of the priority within the group of 8 priorities.  */
           temp =  TCD_Sub_Priority_Groups[index];

           /* Calculate the actual priority.  */
           TCD_Highest_Priority =  (index << 3) + TCD_Lowest_Set_Bit[temp];

           /* Check for preemption.  */
           if ((TCD_Highest_Priority <= ((INT) TCD_Execute_Task -> tc_priority))
               && (TCD_Execute_Task -> tc_preemption))
           {

               /* Update the current task pointer.  */
               TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]);

               /* Now, check and see if the current thread is a task.
                  If so, return a status that indicates a context
                  switch is needed.  */
               if ((TCD_Current_Thread) &&
                  (((TC_TCB *) TCD_Current_Thread) -> tc_id == TC_TASK_ID))

                   /* Transfer control to the system.  */
                   TCT_Control_To_System();
           }
       }
       else
       {

           /* Just modify the priority.  */
           task -> tc_priority =  new_priority;

           /* Build the other priority information.  */
           task -> tc_priority =      new_priority;
           task -> tc_priority_head = &(TCD_Priority_List[new_priority]);
           task -> tc_sub_priority =  (DATA_ELEMENT) (1 << (new_priority & 7));
           task -> tc_priority_group =   ((UNSIGNED) 1) << (new_priority >> 3);
           task -> tc_sub_priority_ptr =
                   &(TCD_Sub_Priority_Groups[(new_priority >> 3)]);
       }
#ifdef INCLUDE_PROVIEW
        _RTProf_DumpTask(task,RT_PROF_CHANGE_PRIORITY);
#endif
    }

    /* Release the protection of the scheduling list.  */
    TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return the old priority.  */
    return(old_priority);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Change_Preemption                                            */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function changes the preemption posture of the calling      */
/*      task.  Preemption for a task may be enabled or disabled.  If     */
/*      it is disabled, the task runs until it suspends or relinquishes. */
/*      If a preemption is pending, a call to this function to enable    */
/*      preemption causes a context switch.                              */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Change_Preemption              Error checking function      */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Control_To_System               Transfer control to system   */
/*      TCT_Protect                         Protect scheduling info      */
/*      TCT_Set_Execute_Task                Set TCD_Execute_Task pointer */
/*      TCT_Unprotect                       Release protection of info   */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      preempt                             Preempt selection parameter  */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      old_preempt                         Original preempt value       */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*        DATE                    REMARKS                                */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      03-01-1994      Modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*************************************************************************/
OPTION   TCS_Change_Preemption(OPTION preempt)
{

TC_TCB         *task;                       /* Pointer to task           */
OPTION          old_preempt;
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_CHANGE_PREEMPTION_ID, (UNSIGNED) preempt,
                                        (UNSIGNED) 0, (UNSIGNED) 0);

#endif

    /* Protect the scheduling information.  */
    TCT_Protect(&TCD_System_Protect);

    /* Pickup the current thread and place it in the task pointer.  */
    task =  (TC_TCB *) TCD_Current_Thread;

    /* Save the old preempt value.  */
    if (task -> tc_preemption)

        /* Previously enabled.  */
        old_preempt =  NU_PREEMPT;
    else

        /* Previously disabled.  */
        old_preempt =  NU_NO_PREEMPT;

    /* Process the new value.  */
    if (preempt == NU_NO_PREEMPT)

        /* Disable preemption.  */
        TCD_Execute_Task -> tc_preemption =  NU_FALSE;
    else
    {

        /* Enable preemption.  */
        task -> tc_preemption =  NU_TRUE;

        /* Check for a preemption condition.  */
        if ((task == TCD_Execute_Task) &&
            (TCD_Highest_Priority < ((INT) TCD_Execute_Task -> tc_priority)))
        {

            /* Preempt the current task.  */
            TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]);

            /* Transfer control to the system.  */
            TCT_Control_To_System();
        }
    }

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_CHANGE_PREEMPTION);
#endif

    /* Release protection of information.  */
    TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return the previous preemption posture.  */
    return(old_preempt);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Change_Time_Slice                                            */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function changes the time slice of the specified task.  A   */
/*      time slice value of 0 disables time slicing.                     */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCES_Change_Preemption              Error checking function      */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Protect                         Protect scheduling info      */
/*      TCT_Unprotect                       Release protection of info   */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      task_ptr                            Task control block pointer   */
/*      time_slice                          New time slice value         */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      old_time_slice                      Original time slice value    */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      03-01-1994      Modified function interface,                     */
/*                      added register optimizations,                    */
/*                      modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*************************************************************************/
UNSIGNED   TCS_Change_Time_Slice(NU_TASK *task_ptr, UNSIGNED time_slice)
{

TC_TCB         *task;                       /* Task control block ptr    */
UNSIGNED        old_time_slice;             /* Old time slice value      */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

    /* Move input task control block pointer into internal pointer.  */
    task =  (TC_TCB *) task_ptr;


#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_CHANGE_TIME_SLICE_ID, (UNSIGNED) task,
                                        (UNSIGNED) time_slice, (UNSIGNED) 0);

#endif

    /* Protect the scheduling information.  */
    TCT_Protect(&TCD_System_Protect);

    /* Save the old time slice value.  */
    old_time_slice =  task -> tc_time_slice;

    /* Store the new time slice value.  */
    task -> tc_time_slice =      time_slice;
    task -> tc_cur_time_slice =  time_slice;

    /* Bug fix. Let the system know we have started a new time slice */
    TMD_Time_Slice_State = TM_ACTIVE;

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_CHANGE_TIME_SLICE);
#endif
    /* Release protection of information.  */
    TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return the previous time slice value.  */
    return(old_time_slice);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Control_Signals                                              */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function enables the specified signals and returns the      */
/*      previous enable signal value back to the caller.  If a newly     */
/*      enabled signal is present and a signal handler is registered,    */
/*      signal handling is started.                                      */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Control_Signals                Error checking shell         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      TCC_Signal_Shell                    Task signal execution        */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Protect                         Protect against other access */
/*      TCT_Unprotect                       Release protection           */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      enable_signal_mask                  Enable signal mask           */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      Previous signal enable mask                                      */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      05-15-1993      Corrected problem with a comment                 */
/*      05-15-1993      Verified comment repair                          */
/*      03-01-1994      Added register optimizations,                    */
/*                      modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*************************************************************************/
UNSIGNED  TCS_Control_Signals(UNSIGNED enable_signal_mask)
{

R1 TC_TCB      *task;                      /* Task pointer              */
UNSIGNED        old_enable_mask;            /* Old enable signal mask    */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_CONTROL_SIGNALS_ID,(UNSIGNED) enable_signal_mask,
                                        (UNSIGNED) 0, (UNSIGNED) 0);

#endif

    /* Pickup the task pointer.  */
    task =  (TC_TCB *) TCD_Current_Thread;

    /* Protect against simultaneous access.  */
    TCT_Protect(&TCD_System_Protect);

    /* Pickup the old signal mask.  */
    old_enable_mask =  task -> tc_enabled_signals;

    /* Put the new mask in.  */
    task -> tc_enabled_signals =  enable_signal_mask;

    /* Now, determine if the signal handler needs to be invoked.  */
    if ((enable_signal_mask & task -> tc_signals) &&
        (!task -> tc_signal_active) &&
        (task -> tc_signal_handler))
    {

        /* Signal processing is required.  */

        /* Indicate that signal processing is in progress.  */
        task -> tc_signal_active =  NU_TRUE;

        /* Clear the saved stack pointer to indicate that this is an
           in line signal handler call.  */
        task -> tc_saved_stack_ptr =  NU_NULL;

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_CONTROL_SIGNALS);
#endif

        /* Release protection from multiple access.  */
        TCT_Unprotect();

        /* Call the signal handling shell. */
        TCC_Signal_Shell();
    }
    else
    {

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_CONTROL_SIGNALS);
#endif

        /* Release protection.  */
        TCT_Unprotect();
    }

    /* Return to user mode */
    NU_USER_MODE();

    /* Return the old enable mask.  */
    return(old_enable_mask);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Receive_Signals                                              */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function returns the current signals back to the caller.    */
/*      Note that the signals are cleared automatically.                 */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Receive_Signals                Error checking shell         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Protect                         Protect against other access */
/*      TCT_Unprotect                       Release protection           */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      None                                                             */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      Current signals                                                  */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      03-01-1994      Modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*************************************************************************/
UNSIGNED  TCS_Receive_Signals(VOID)
{

TC_TCB          *task;                      /* Task pointer              */
UNSIGNED        signals;                    /* Current signals           */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_RECEIVE_SIGNALS_ID, (UNSIGNED) 0,
                                        (UNSIGNED) 0, (UNSIGNED) 0);

#endif

    /* Pickup the task pointer.  */
    task =  (TC_TCB *) TCD_Current_Thread;

    /* Protect against simultaneous access.  */
    TCT_Protect(&TCD_System_Protect);

    /* Pickup the current events.  */
    signals =  task -> tc_signals;

    /* Clear the current signals.  */
    task -> tc_signals =  0;

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_RECEIVE_SIGNALS);
#endif

    /* Release protection.  */
    TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return the signals to the caller.  */
    return(signals);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Register_Signal_Handler                                      */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function registers a signal handler for the calling task.   */
/*      Note that if an enabled signal is present and this is the first  */
/*      registered signal handler call, the signal is processed          */
/*      immediately.                                                     */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Register_Signal_Handler        Error checking shell         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      TCC_Signal_Shell                    Signal execution shell       */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Protect                         Protect against other access */
/*      TCT_Unprotect                       Release protection           */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      signal_handler                      Signal execution shell       */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      NU_SUCCESS                                                       */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      05-15-1993      Corrected problem with a comment                 */
/*      05-15-1993      Verified comment repair                          */
/*      03-01-1994      Added register optimizations,                    */
/*                      modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*                                                                       */
/*************************************************************************/
STATUS  TCS_Register_Signal_Handler(VOID (*signal_handler)(UNSIGNED))
{

R1 TC_TCB      *task;                       /* Task pointer              */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_REGISTER_SIGNAL_HANDLER_ID,
                        (UNSIGNED) signal_handler, (UNSIGNED) 0, (UNSIGNED) 0);

#endif

    /* Pickup the task pointer.  */
    task =  (TC_TCB *) TCD_Current_Thread;

    /* Protect against simultaneous access.  */
    TCT_Protect(&TCD_System_Protect);

    /* Put the new signal handler in.  */
    task -> tc_signal_handler =  signal_handler;

    /* Now, determine if the signal handler needs to be invoked.  */
    if ((task -> tc_enabled_signals & task -> tc_signals) &&
        (!task -> tc_signal_active) &&
        (task -> tc_signal_handler))
    {

        /* Signal processing is required.  */

        /* Indicate that signal processing is in progress.  */
        task -> tc_signal_active =  NU_TRUE;

        /* Clear the saved stack pointer to indicate that this is an
           in line signal handler call.  */
        task -> tc_saved_stack_ptr =  NU_NULL;

        /* Release protection from multiple access.  */
        TCT_Unprotect();

        /* Call the signal handling shell. */
        TCC_Signal_Shell();
    }
    else

        /* Release protection.  */
        TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return success.  */
    return(NU_SUCCESS);
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      TCS_Send_Signals                                                 */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      This function sends the specified task the specified signals.    */
/*      If enabled, the specified task is setup in order to process the  */
/*      signals.                                                         */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*      Application                                                      */
/*      TCSE_Send_Signals                   Error checking shell         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      [HIC_Make_History_Entry]            Make entry in history log    */
/*      TCC_Resume_Task                     Resume task that is suspended*/
/*      TCC_Signal_Shell                    Signal execution shell       */
/*      TCT_Build_Signal_Frame              Build a signal frame         */
/*      [TCT_Check_Stack]                   Stack checking function      */
/*      TCT_Control_To_System               Control to system            */
/*      TCT_Protect                         Protect against other access */
/*      TCT_Unprotect                       Release protection           */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/*      task_ptr                            Task pointer                 */
/*      signals                             Signals to send to the task  */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/*      NU_SUCCESS                                                       */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*         DATE                    REMARKS                               */
/*                                                                       */
/*      03-01-1993      Created initial version 1.0                      */
/*      04-19-1993      Verified version 1.0                             */
/*      03-01-1994      Modified function interface,                     */
/*                      added register optimizations,                    */
/*                      modified protection logic,                       */
/*                      resulting in version 1.1                         */
/*                                                                       */
/*      03-18-1994      Verified version 1.1                             */
/*      04-04-1996      On line 995, changed tc_signals                  */
/*                      to tc_enabled_signals,                           */
/*                      resulting in version 1.1+                        */
/*                      (spr 107)                                        */
/*                                                                       */
/*************************************************************************/
STATUS  TCS_Send_Signals(NU_TASK *task_ptr, UNSIGNED signals)
{

R1 TC_TCB      *task;                       /* Task control block ptr    */
NU_SUPERV_USER_VARIABLES

    /* Switch to supervisor mode */
    NU_SUPERVISOR_MODE();

    /* Move input task control block pointer into internal pointer.  */
    task =  (TC_TCB *) task_ptr;


#ifdef  NU_ENABLE_STACK_CHECK

    /* Call stack checking function to check for an overflow condition.  */
    TCT_Check_Stack();

#endif

#ifdef  NU_ENABLE_HISTORY

    /* Make an entry that corresponds to this function in the system history
       log.  */
    HIC_Make_History_Entry(NU_SEND_SIGNALS_ID, (UNSIGNED) signals,
                                        (UNSIGNED) 0, (UNSIGNED) 0);

#endif

    /* Protect against simultaneous access.  */
    TCT_Protect(&TCD_System_Protect);

    /* Or the new signals into the current signals.  */
    task -> tc_signals =  task -> tc_signals | signals;

#ifdef INCLUDE_PROVIEW
    _RTProf_DumpTask(task,RT_PROF_SEND_SIGNALS);
#endif
    /* Now, determine if the signal handler needs to be invoked.  */
    if ((task -> tc_signals & task -> tc_enabled_signals) &&
        (!task -> tc_signal_active) &&
        (task -> tc_status != NU_TERMINATED) &&
        (task -> tc_status != NU_FINISHED) &&
        (task -> tc_signal_handler))
    {

        /* Indicate that signal processing is in progress.  */
        task -> tc_signal_active =  NU_TRUE;

        /* Signal processing is required.  Determine if the task is sending
           signals to itself or if the calling thread is not the current
           task.  */
        if (task == (TC_TCB *) TCD_Current_Thread)
        {

            /* Task sending signals to itself.  */

            /* Clear the saved stack pointer to indicate that this is an
               in line signal handler call.  */
            task -> tc_saved_stack_ptr =  NU_NULL;

            /* Release protection from multiple access.  */
            TCT_Unprotect();

            /* Call the signal handling shell. */
            TCC_Signal_Shell();
        }
        else
        {

            /* Target task must be prepared to receive the signals.  */

            /* First, insure that the target task is not in a protected
               area.  */
            do
            {

                /* Check for protection.  Remember that protection is still
                   in effect.  */
                if (task -> tc_current_protect)
                {

                    /* Yes, target task is in a protected mode.  Release
                       the protection on the scheduling list and transfer
                       control briefly to the target task.  */
                    TCT_Unprotect();

                    /* Switch to the protected task and wait until the
                       task is not protected.  */
                    TCT_Protect_Switch(task);

                    /* Restore protection on the scheduling structures.  */
                    TCT_Protect(&TCD_System_Protect);
                }
            } while (task -> tc_current_protect);

            /* Copy the current status and stack pointer to the signal save
               areas.  */
            task -> tc_saved_status =           task -> tc_status;
            task -> tc_saved_stack_ptr =        task -> tc_stack_pointer;

            /* Build a stack frame for the signal handling shell function. */
            TCT_Build_Signal_Frame(task);

            /* Determine if the target task is currently suspended.  If it is
               suspended for any other reason than a pure suspend, resume
               it.  */
            if ((task -> tc_status != NU_READY) &&
                (task -> tc_status != NU_PURE_SUSPEND))
            {

                /* Resume the target task and check for preemption.  */
                if (TCC_Resume_Task(task_ptr, task -> tc_status))

                    /* Preemption needs to take place.  */
                    TCT_Control_To_System();
            }
        }
    }

    /* Release protection, no signals are currently enabled.  */
    TCT_Unprotect();

    /* Return to user mode */
    NU_USER_MODE();

    /* Return a successful status.  */
    return(NU_SUCCESS);
}