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