FreeCalypso > hg > fc-tourmaline
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); }