view src/nucleus/tcs.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +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);
}