FreeCalypso > hg > fc-selenite
diff src/nucleus/tcs.c @ 7:0f80e1e4dce4
src/nucleus: library C code import from FreeNucleus package
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 20:57:33 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nucleus/tcs.c Sun Jul 15 20:57:33 2018 +0000 @@ -0,0 +1,1154 @@ +/*************************************************************************/ +/* */ +/* 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); +} + + + +