FreeCalypso > hg > fc-tourmaline
view src/nucleus/tcc.c @ 222:c336ed5691a5
FCHG: clear BCICTL2 on boot for extra safety
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 26 Apr 2021 22:04:10 +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 */ /* */ /* tcc.c Nucleus PLUS 1.14 */ /* */ /* COMPONENT */ /* */ /* TC - Thread Control */ /* */ /* DESCRIPTION */ /* */ /* This file contains the core routines for the Thread Control */ /* component. */ /* */ /* DATA STRUCTURES */ /* */ /* None */ /* */ /* FUNCTIONS */ /* */ /* TCC_Create_Task Create a task */ /* TCC_Delete_Task Delete a task */ /* TCC_Create_HISR Create HISR */ /* TCC_Delete_HISR Delete HISR */ /* TCC_Reset_Task Reset the specified task */ /* TCC_Terminate_Task Terminate the specified task */ /* TCC_Resume_Task Resume a task */ /* TCC_Resume_Service Resume a task service call */ /* TCC_Suspend_Task Suspend a task */ /* TCC_Suspend_Service Suspend a task service call */ /* TCC_Task_Timeout Task timeout function */ /* TCC_Task_Sleep Task sleep request */ /* TCC_Relinquish Relinquish task execution */ /* TCC_Time_Slice Process task time-slice */ /* TCC_Current_Task_Pointer Retrieve current task pointer*/ /* TCC_Current_HISR_Pointer Retrieve current HISR pointer*/ /* TCC_Task_Shell Task execution shell */ /* TCC_Signal_Shell Signal execution shell */ /* TCC_Dispatch_LISR Dispatch LISR routine */ /* TCC_Register_LISR Register an LISR */ /* */ /* 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-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 05-15-1993 Corrected comment problems in */ /* TCC_Control_Signals and */ /* TCC_Register_Signal_Handler, */ /* making version 1.0a */ /* 05-15-1993 Verified version 1.0a */ /* 06-01-1993 Modified a multi-line comment */ /* after a #include directive */ /* that gave some compilers a */ /* problem, making version 1.0b */ /* 06-01-1993 Verified version 1.0b */ /* 08-09-1993 Corrected pointer retrieval */ /* loop, resulting in version 1.0c */ /* 08-09-1993 Verified version 1.0c */ /* 09-19-1993 Corrected an initialization */ /* problem of de-referencing a */ /* NULL pointer, resulting in */ /* version 1.0d */ /* 09-19-1993 Verified version 1.0d */ /* 11-01-1993 Added logic to save unhandled */ /* interrupt vector number in */ /* a global variable, resulting */ /* in version 1.0e */ /* 11-01-1993 Verified version 1.0e */ /* 02-01-1994 Corrected a suspension with */ /* timeout problem that caused */ /* unconditional task suspension */ /* for timeouts and sleeps for 1 */ /* tick, resulting in version 1.0f */ /* 02-01-1994 Verified version 1.0f */ /* 03-01-1994 Added another routine that */ /* validates resume calls with */ /* the appropriate protection and */ /* added code to clear cleanup */ /* information at task create and */ /* task resume time, resulting in */ /* version 1.0g */ /* 03-01-1994 Verified version 1.0g */ /* 03-01-1994 Moved non-core functions into */ /* supplemental files, changed */ /* function interfaces to match */ /* those in prototype, added */ /* register options, fixed bug */ /* in suspending current task from */ /* a HISR, added a system protect */ /* structure to reduce overhead */ /* in protection, moved resume */ /* validate to error checking */ /* file, resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* 12-18-1995 Modified TCC_Resume_Service, */ /* resulting in version 1.1+ */ /* (SPR 36, 64, 66, 77) */ /* 04-17-1996 updated to version 1.2 */ /* 06-01-1996 Modified TCC_Suspend_Task */ /* (SPR152) creating version 1.2a */ /* 10-29-1997 Modified TCC_Resume_Task */ /* (SPR115) creating vresion 1.2b */ /* 01-23-1998 Released version 1.2b */ /* 03-20-1998 Corrected problem where tasks */ /* created with NU_NO_PREEMPT in */ /* Application_Initialize would */ /* start in the order of creation */ /* and not in priority order. */ /* SPR455 creates version 1.2c */ /* 03-24-1998 Released version 1.3. */ /* 10-02-1998 Another protect problem (1.3a) */ /* 10-02-1998 Corrected a problem where a */ /* a timer expiration occurs */ /* during signal handler execution */ /* and causes the task to never */ /* run again (SPR 923) creating */ /* version 1.3b. */ /* 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 "in_defs.h" /* Initialization defines */ #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" /* Nucleus Profiling header */ #if ((defined(NU_MODULE_SUPPORT)) && (NU_MODULE_SUPPORT > 0)) #include "module/inc/ms_defs.h" /* MS_Module typedef */ #endif /* Define external inner-component global data references. */ extern INT INC_Initialize_State; extern CS_NODE *TCD_Created_Tasks_List; extern UNSIGNED TCD_Total_Tasks; 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 UNSIGNED_CHAR TCD_Registered_LISRs[NU_MAX_VECTORS+1]; extern VOID (*TCD_LISR_Pointers[NU_MAX_LISRS+1])(INT vector); extern INT TCD_Interrupt_Count; extern INT TCD_Stack_Switched; extern TC_PROTECT TCD_List_Protect; extern TC_PROTECT TCD_System_Protect; extern TC_PROTECT TCD_LISR_Protect; extern CS_NODE *TCD_Created_HISRs_List; extern UNSIGNED TCD_Total_HISRs; extern TC_PROTECT TCD_HISR_Protect; extern INT TCD_Unhandled_Interrupt; /* Define external inner-component function calls that are not available to other components. */ VOID TCT_Build_Task_Stack(TC_TCB *task_ptr); VOID TCT_Build_HISR_Stack(TC_HCB *hisr_ptr); 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); #if defined(NU_MODULE_SUPPORT) && (NU_MODULE_SUPPORT > 0) /* Define service routines "privately" imported from other components */ extern MS_MODULE* msd_current_module; STATUS MSC_Bind_Module_HISR(MS_MODULE* module, TC_HCB* hisr); STATUS MSC_Bind_Module_Task(MS_MODULE* module, TC_TCB* task); #endif /* NU_MODULE_SUPPORT */ /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Create_Task */ /* */ /* DESCRIPTION */ /* */ /* This function creates a task and then places it on the list of */ /* created tasks. All the resources necessary to create the task */ /* are supplied to this routine. If specified, the newly created */ /* task is started. Otherwise, it is left in a suspended state. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Create_Task Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Add TCB to linked-list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Resume_Task Start the created task */ /* TCT_Build_Task_Stack Build an initial task stack */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Protect Protect created task list */ /* TCT_Unprotect Release protection of list */ /* TMC_Init_Task_Timer Initialize the task's timer */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* name Task name */ /* task_entry Entry function of the task */ /* argc Optional task parameter */ /* argv Optional task parameter */ /* stack_address Pointer to start of stack */ /* stack_size Size of task stack in bytes */ /* priority Task priority */ /* time_slice Task time slice */ /* preempt Task preemptability flag */ /* auto_start Automatic task start */ /* */ /* 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, */ /* added system protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Create_Task(NU_TASK *task_ptr, CHAR *name, VOID (*task_entry)(UNSIGNED, VOID *), UNSIGNED argc, VOID *argv, VOID *stack_address, UNSIGNED stack_size, OPTION priority, UNSIGNED time_slice, OPTION preempt, OPTION auto_start) { R1 TC_TCB *task; /* Task control block ptr */ R2 INT i; /* Working index variable */ STATUS status = NU_SUCCESS; NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input task 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_CREATE_TASK_ID, (UNSIGNED) task, (UNSIGNED) name, (UNSIGNED) task_entry); #endif /* First, clear the task ID just in case it is an old Task Control Block. */ task -> tc_id = 0; /* Fill in the task name. */ for (i = 0; i < NU_MAX_NAME; i++) task -> tc_name[i] = name[i]; /* Fill in the basic task information. */ task -> tc_entry = task_entry; task -> tc_argc = argc; task -> tc_argv = argv; task -> tc_status = NU_PURE_SUSPEND; task -> tc_delayed_suspend = NU_FALSE; task -> tc_scheduled = 0; task -> tc_time_slice = time_slice; task -> tc_cur_time_slice = time_slice; task -> tc_current_protect = NU_NULL; task -> tc_suspend_protect = NU_NULL; task -> tc_cleanup = NU_NULL; task -> tc_cleanup_info = NU_NULL; /* Setup task's preemption posture. */ if (preempt == NU_PREEMPT) task -> tc_preemption = NU_TRUE; else task -> tc_preemption = NU_FALSE; /* Fill in information about the task's stack. */ task -> tc_stack_start = stack_address; task -> tc_stack_end = 0; task -> tc_stack_size = stack_size; task -> tc_stack_minimum = stack_size; /* Setup priority information for the task. There are two bit maps associated with each task. The first bit map indicates which group of 8-priorities it is. The second bit map indicates the actual priority within the group. */ task -> tc_priority = priority; task -> tc_priority_head = &(TCD_Priority_List[priority]); task -> tc_sub_priority = (DATA_ELEMENT) (1 << (priority & 7)); priority = priority >> 3; task -> tc_priority_group = ((UNSIGNED) 1) << priority; task -> tc_sub_priority_ptr = &(TCD_Sub_Priority_Groups[priority]); /* Initialize link pointers. */ task -> tc_created.cs_previous = NU_NULL; task -> tc_created.cs_next = NU_NULL; task -> tc_ready_previous = NU_NULL; task -> tc_ready_next = NU_NULL; /* Build a stack frame for this task by calling TCT_Build_Task_Stack. */ TCT_Build_Task_Stack(task); /* Initialize the signal information of the task. */ task -> tc_signals = 0; task -> tc_enabled_signals = 0; task -> tc_signal_handler = 0; task -> tc_signal_active = NU_FALSE; /* Initialize additional kernel options data */ #if (NU_SUPERV_USER_MODE == 1) task->tc_su_mode = 0; /* Initially in User mode */ task->tc_module = 0; /* Not initially bound to a module */ #endif /* Initialize the task timer. */ task -> tc_timer_active = NU_FALSE; TMC_Init_Task_Timer(&(task -> tc_timer_control), (VOID *) task); /* Protect the list of created tasks. */ TCT_Protect(&TCD_List_Protect); /* At this point the task is completely built. The ID can now be set and it can be linked into the created task list. */ task -> tc_id = TC_TASK_ID; #if defined(NU_MODULE_SUPPORT) && (NU_MODULE_SUPPORT > 0) /* If executing in a thread's context, bind to that thread's module */ if(TCD_Current_Thread != NU_NULL) { status = MSC_Bind_Module_Task( (MS_MODULE*)(((TC_TCB*)(TCD_Current_Thread))->tc_module), task); } else /* It must be initialization time, so use the current module */ { status = MSC_Bind_Module_Task(msd_current_module, task); } #endif /* NU_MODULE_SUPPORT */ /* Link the task into the list of created tasks and increment the total number of tasks in the system. */ CSC_Place_On_List(&TCD_Created_Tasks_List, &(task -> tc_created)); TCD_Total_Tasks++; #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_CREATE_TASK); #endif /* Release the protection. */ TCT_Unprotect(); /* Determine if the task should be automatically started. */ if (auto_start == NU_START) { /* Protect the system data structures. */ TCT_Protect(&TCD_System_Protect); /* Start the task by resuming it. If the preemption is required, leave the current task. */ if (TCC_Resume_Task(task_ptr, NU_PURE_SUSPEND)) /* Transfer control back to the system. */ TCT_Control_To_System(); else /* Release the protection. */ TCT_Unprotect(); } /* Return to user mode */ NU_USER_MODE(); /* Return successful completion. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Create_HISR */ /* */ /* DESCRIPTION */ /* */ /* This function creates a High-Level Interrupt Service Routine */ /* (HISR) and then places it on the list of created HISRs. All */ /* the resources necessary to create the HISR are supplied to this */ /* routine. HISRs are always created in a dormant state. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Create_HISR Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Add TCB to linked-list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCT_Build_HISR_Stack Build an initial HISR stack */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect created HISR list */ /* TCT_Unprotect Release protection of list */ /* */ /* INPUTS */ /* */ /* hisr_ptr HISR control block pointer */ /* name HISR name */ /* hisr_entry Entry function of the HISR */ /* priority Task priority */ /* stack_address Pointer to start of stack */ /* stack_size Size of HISR stack in bytes */ /* */ /* 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, */ /* added more control block */ /* initialization, resulting in */ /* version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Create_HISR(NU_HISR *hisr_ptr, CHAR *name, VOID (*hisr_entry)(VOID), OPTION priority, VOID *stack_address, UNSIGNED stack_size) { R1 TC_HCB *hisr; /* HISR control block ptr */ R2 INT i; /* Working index variable */ STATUS status = NU_SUCCESS; NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input HISR pointer into internal pointer. */ hisr = (TC_HCB *) hisr_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_CREATE_HISR_ID, (UNSIGNED) hisr, (UNSIGNED) name, (UNSIGNED) hisr_entry); #endif /* First, clear the HISR ID just in case it is an old HISR Control Block. */ hisr -> tc_id = 0; /* Fill in the HISR name. */ for (i = 0; i < NU_MAX_NAME; i++) hisr -> tc_name[i] = name[i]; /* Fill in the basic HISR information. */ hisr -> tc_entry = hisr_entry; hisr -> tc_scheduled = 0; hisr -> tc_activation_count = 0; hisr -> tc_cur_time_slice = 0; /* Fill in information about the HISR's stack. */ hisr -> tc_stack_start = stack_address; hisr -> tc_stack_end = 0; hisr -> tc_stack_size = stack_size; hisr -> tc_stack_minimum = stack_size; /* Setup priority information for the HISR. Priorities range from 0 to TC_HISR_PRIORITIES - 1. */ hisr -> tc_priority = priority & 3; /* Initialize link pointers. */ hisr -> tc_created.cs_previous = NU_NULL; hisr -> tc_created.cs_next = NU_NULL; hisr -> tc_active_next = NU_NULL; /* Clear protect pointer. */ hisr -> tc_current_protect = NU_NULL; /* Initialize additional kernel options data */ #if (NU_SUPERV_USER_MODE == 1) hisr->tc_su_mode = 1; /* TCT_HISR_Shell in Supervisor mode */ hisr->tc_module = 0; /* Not initially bound to a module */ #endif /* Build a stack frame for this HISR by calling TCT_Build_HISR_Stack. */ TCT_Build_HISR_Stack(hisr); /* Protect the list of created HISRs. */ TCT_Protect(&TCD_HISR_Protect); /* At this point the HISR is completely built. The ID can now be set and it can be linked into the created HISR list. */ hisr -> tc_id = TC_HISR_ID; #if defined(NU_MODULE_SUPPORT) && (NU_MODULE_SUPPORT > 0) /* If executing in a thread's context, bind to that thread's module */ if(TCD_Current_Thread != NU_NULL) { status = MSC_Bind_Module_HISR( (MS_MODULE*)(((TC_TCB*)(TCD_Current_Thread))->tc_module), hisr); } else /* It must be initialization time, so use the current module */ { status = MSC_Bind_Module_HISR(msd_current_module, hisr); } #endif /* NU_MODULE_SUPPORT */ /* Link the HISR into the list of created HISRs and increment the total number of HISRs in the system. */ CSC_Place_On_List(&TCD_Created_HISRs_List, &(hisr -> tc_created)); TCD_Total_HISRs++; #ifdef INCLUDE_PROVIEW _RTProf_DumpHisr(hisr,RT_PROF_CREATE_HISR); #endif /* Release the protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return successful completion. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Delete_Task */ /* */ /* DESCRIPTION */ /* */ /* This function deletes a task and removes it from the list of */ /* created tasks. It is assumed by this function that the task is */ /* in a finished or terminated state. Note that this function */ /* does not free memory associated with the task's control block or */ /* its stack. This is the responsibility of the application. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Delete_Task Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Remove_From_List Remove node from list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect created task list */ /* TCT_Unprotect Release protection of list */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* */ /* 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, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Delete_Task(NU_TASK *task_ptr) { R1 TC_TCB *task; /* Task control block ptr */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input task 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_DELETE_TASK_ID, (UNSIGNED) task, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect the list of created tasks. */ TCT_Protect(&TCD_List_Protect); #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_DELETE_TASK); #endif /*INCLUDE_PROVIEW*/ /* Remove the task from the list of created tasks. */ CSC_Remove_From_List(&TCD_Created_Tasks_List, &(task -> tc_created)); /* Decrement the total number of created tasks. */ TCD_Total_Tasks--; /* Clear the task ID just in case. */ task -> tc_id = 0; /* Release protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return a successful completion. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Delete_HISR */ /* */ /* DESCRIPTION */ /* */ /* This function deletes a HISR and removes it from the list of */ /* created HISRs. It is assumed by this function that the HISR is */ /* in a non-active state. Note that this function does not free */ /* memory associated with the HISR's control block or its stack. */ /* This is the responsibility of the application. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Delete_HISR Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Remove_From_List Remove node from list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect created HISR list */ /* TCT_Unprotect Release protection of list */ /* */ /* INPUTS */ /* */ /* hisr_ptr HISR control block pointer */ /* */ /* 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, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Delete_HISR(NU_HISR *hisr_ptr) { R1 TC_HCB *hisr; /* HISR control block ptr */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input HISR pointer into internal pointer. */ hisr = (TC_HCB *) hisr_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_DELETE_HISR_ID, (UNSIGNED) hisr, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect the list of created HISRs. */ TCT_Protect(&TCD_HISR_Protect); #ifdef INCLUDE_PROVIEW _RTProf_DumpHisr(hisr,RT_PROF_DELETE_HISR); #endif /*INCLUDE_PROVIEW*/ /* Remove the HISR from the list of created HISRs. */ CSC_Remove_From_List(&TCD_Created_HISRs_List, &(hisr -> tc_created)); /* Decrement the total number of created HISRs. */ TCD_Total_HISRs--; /* Clear the HISR ID just in case. */ hisr -> tc_id = 0; /* Release protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return a successful completion. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Reset_Task */ /* */ /* DESCRIPTION */ /* */ /* This function resets the specified task. Note that a task reset */ /* can only be performed on tasks in a finished or terminated state.*/ /* The task is left in an unconditional suspended state. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Reset_Task Error checking shell */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCT_Build_Task_Stack Build an initial task stack */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect created task list */ /* TCT_Unprotect Release protection of list */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* argc Optional task parameter */ /* argv Optional task parameter */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS Indicates successful request */ /* NU_NOT_TERMINATED Indicates task was not */ /* finished or terminated */ /* */ /* 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, */ /* added system protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Reset_Task(NU_TASK *task_ptr, UNSIGNED argc, VOID *argv) { R1 TC_TCB *task; /* Task control block ptr */ STATUS status; /* Status of the request */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input task 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_RESET_TASK_ID, (UNSIGNED) task, (UNSIGNED) argc, (UNSIGNED) argv); #endif /* Protect system structures. */ TCT_Protect(&TCD_System_Protect); /* Determine if the task is in the proper state. */ if ((task -> tc_status == NU_FINISHED) || (task -> tc_status == NU_TERMINATED)) { /* Yes, a valid reset is present. Indicate this in the status. */ status = NU_SUCCESS; /* Fill in the new argument information and reset some of the other fields. */ task -> tc_argc = argc; task -> tc_argv = argv; task -> tc_status = NU_PURE_SUSPEND; task -> tc_delayed_suspend = NU_FALSE; task -> tc_scheduled = 0; task -> tc_stack_minimum = task -> tc_stack_size; #if (NU_SUPERV_USER_MODE == 1) /* Since we are doing a complete reset we need to ensure that this field is 0 since the task will be started in user mode. TCC_Task_Shell can not return and therefore left the task in supervisor mode when the task completed. If we were to not re-initialize this field the task would become locked in user mode and API would fail. */ task -> tc_su_mode = 0; #endif /* Build a stack frame for this task by calling TCT_Build_Task_Stack. */ TCT_Build_Task_Stack(task); } else /* The requested task is not in a finished or terminated state. */ status = NU_NOT_TERMINATED; #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_RESET_TASK); #endif /*INCLUDE_PROVIEW*/ /* Release the protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return completion status. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Terminate_Task */ /* */ /* DESCRIPTION */ /* */ /* This function terminates the specified task. If the task is */ /* already terminated, this function does nothing. If the task */ /* to terminate is currently suspended, the specified cleanup */ /* routine is also invoked to cleanup suspension data structures. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Terminate_Task Error checking shell */ /* */ /* CALLS */ /* */ /* Cleanup routine Task's suspend cleanup funct */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Suspend_Task Suspend a ready task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect created task list */ /* TCT_Unprotect Release protection of list */ /* TCT_Unprotect_Specific Specific unprotection */ /* TMC_Stop_Task_Timer Stop a task timer */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* */ /* 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, */ /* added system protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Terminate_Task(NU_TASK *task_ptr) { R1 TC_TCB *task; /* Task control block ptr */ TC_PROTECT *suspend_protect; /* Suspension protection ptr */ DATA_ELEMENT status; /* Task status */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move task 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_TERMINATE_TASK_ID, (UNSIGNED) task, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Determine if the calling task is the current task. */ if (task == (TC_TCB *) TCD_Current_Thread) { /* Protect system data structures. */ TCT_Protect(&TCD_System_Protect); #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_TERMINATE_TASK); #endif /*INCLUDE_PROVIEW*/ /* Suspend the calling task with the NU_TERMINATED status. */ TCC_Suspend_Task(task_ptr, NU_TERMINATED, NU_NULL, NU_NULL, NU_SUSPEND); /* No need to un-protect, since control never comes back to this point and the protection is cleared in TCT_Control_To_System. */ } else { /* Protect scheduling structures. */ TCT_Protect(&TCD_System_Protect); #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_TERMINATE_TASK); #endif /*INCLUDE_PROVIEW*/ /* Keep trying to terminate the specified task until its status indicates that it is terminated or finished. */ while ((task -> tc_status != NU_FINISHED) && task -> tc_status != NU_TERMINATED) { /* Is the task in a ready state? */ if (task -> tc_status == NU_READY) { /* Terminate the specified task. */ TCC_Suspend_Task(task_ptr, NU_TERMINATED, NU_NULL, NU_NULL,NU_SUSPEND); /* Clear system protection. */ TCT_Unprotect(); } else { /* Task is suspended currently. Pickup the suspension protection. */ suspend_protect = task -> tc_suspend_protect; /* Save the current status. */ status = task -> tc_status; /* Release protection on system structures. */ TCT_Unprotect(); /* Determine if there was a suspension protection. If so protect it first before the scheduling list protection. This avoids a deadlock situation. */ if (suspend_protect) /* Protect the terminated task's last suspension structures. */ TCT_Protect(suspend_protect); /* Protect the system structures again. */ TCT_Protect(&TCD_System_Protect); /* Now determine if the same suspension is in force. */ if ((task -> tc_status == status) && (task -> tc_suspend_protect == suspend_protect)) { /* Yes, same suspension is in force. */ /* Call cleanup routine, if there is one. */ if (task -> tc_cleanup) /* Call cleanup function. */ (*(task -> tc_cleanup)) (task -> tc_cleanup_info); /* Status the task as terminated. */ task -> tc_status = NU_TERMINATED; /* Determine if there is a timer active. */ if (task -> tc_timer_active) { /* Call the stop timer function. */ TMC_Stop_Task_Timer(&(task -> tc_timer_control)); /* Clear the timer active flag. */ task -> tc_timer_active = NU_FALSE; } } /* Cleanup the protection. */ if (suspend_protect) { /* Release specific protection. */ TCT_Unprotect_Specific(suspend_protect); /* Clear the suspend protect field. */ task -> tc_suspend_protect = NU_NULL; } /* Release current protection. */ TCT_Unprotect(); } /* Protect the scheduling list again. */ TCT_Protect(&TCD_System_Protect); } /* Release the protection. */ TCT_Unprotect(); } /* Return to user mode */ NU_USER_MODE(); /* Return successful completion. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Resume_Task */ /* */ /* DESCRIPTION */ /* */ /* This function resumes a previously suspended task. The task */ /* task must currently be suspended for the same reason indicated */ /* by this request. If the task resumed is higher priority than */ /* the calling task and the current task is preemptable, this */ /* function returns a value of NU_TRUE. Otherwise, if no */ /* preemption is required, a NU_FALSE is returned. This routine */ /* must be called from Supervisor mode in a Supervisor/User mode */ /* switching kernel. */ /* */ /* CALLED BY */ /* */ /* Other Components */ /* TCC_Resume_Service Resume service function */ /* */ /* CALLS */ /* */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Set_Current_Protect Set current protection field */ /* TCT_Set_Execute_Task Set TCD_Execute_Task pointer */ /* TMC_Stop_Task_Timer Stop task timer */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* suspend_type Type of suspension to lift */ /* */ /* OUTPUTS */ /* */ /* NU_TRUE A higher priority task is */ /* ready to execute */ /* NU_FALSE No change in the task to */ /* execute */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 09-19-1993 Corrected an initialization */ /* problem of de-referencing a */ /* NULL pointer, resulting in */ /* version 1.0d */ /* 09-19-1993 Verified version 1.0d */ /* 03-01-1994 Modified function interface, */ /* added register optimizations, */ /* modified protection logic to */ /* assume that system protection */ /* is already in force, resulting */ /* in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* 10-29-1997 Changed so that tc_cleanup, */ /* tc_cleanup_info, and */ /* tc_suspend_protect are cleared */ /* only if a signal is not active */ /* (SPR115) */ /* 03-20-1998 Corrected SPR455. */ /* */ /*************************************************************************/ STATUS TCC_Resume_Task(NU_TASK *task_ptr, OPTION suspend_type) { R1 TC_TCB *task; /* Task control block ptr */ R2 TC_TCB *head; /* Pointer to priority list */ STATUS status = NU_FALSE; /* Status variable */ /* Move task 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 /* Check to see if the task is suspended for the reason that this resume is attempting to clear. */ if (task -> tc_status == suspend_type) { /* Yes, this resume call is valid. */ /* If signals are not active, clear any suspend or cleanup information (SPR115). */ if (!task -> tc_signal_active) { task -> tc_suspend_protect = NU_NULL; task -> tc_cleanup = NU_NULL; task -> tc_cleanup_info = NU_NULL; } /* Determine if there is a timer active and the task is not being resumed to handle a signal. */ if ((task -> tc_timer_active) && (!task -> tc_signal_active)) { /* Call the stop timer function. */ TMC_Stop_Task_Timer(&(task -> tc_timer_control)); /* Clear the timer active flag. */ task -> tc_timer_active = NU_FALSE; } /* Check to see if there is a pending pure suspension. If so, change the cause of the suspension and leave in a suspended state. */ if (task -> tc_delayed_suspend) { /* Leave suspended but change the task's status and clear the delayed suspension flag. */ task -> tc_delayed_suspend = NU_FALSE; task -> tc_status = NU_PURE_SUSPEND; } else { /* Lift the suspension of the specified task. */ /* Clear the status of the task. */ task -> tc_status = NU_READY; #ifdef INCLUDE_PROVIEW _RTProf_TaskStatus(task,RT_TASK_READY); #endif /*INCLUDE_PROVIEW*/ /* Link the task into the appropriate priority list. */ head = *(task -> tc_priority_head); /* Determine if the list is non-empty. */ if (head) { /* Add the new 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 new 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 if this newly ready task is higher priority than the current task. */ if ((INT) (task -> tc_priority) < TCD_Highest_Priority) { /* Update the highest priority field. */ TCD_Highest_Priority = (INT) task -> tc_priority; /* See if there is a task to execute. */ if (TCD_Execute_Task == NU_NULL) /* Make this task the current. */ TCT_Set_Execute_Task(task); /* Check to see if the task to execute is preemptable. */ /* SPR455 checks if we are in Application_Initialize */ else if ((TCD_Execute_Task -> tc_preemption) || (INC_Initialize_State == INC_START_INITIALIZE)) { /* Yes, the task to execute is preemptable. Replace it with the new task. */ TCT_Set_Execute_Task(task); /* 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)) /* Yes, a context switch is needed. */ status = NU_TRUE; } } } } } else { /* Check for a resumption of a delayed pure suspend. */ if (suspend_type == NU_PURE_SUSPEND) /* Clear the delayed suspension. */ task -> tc_delayed_suspend = NU_FALSE; /* Check for a signal active and the saved status the same as the resume request. */ if ((suspend_type == task -> tc_saved_status) && (task -> tc_signal_active)) { /* Indicate the saved status as ready. */ task -> tc_saved_status = NU_READY; /* Determine if the task's timer is active. */ if (task -> tc_timer_active) { /* Stop the timer. */ TMC_Stop_Task_Timer(&(task -> tc_timer_control)); /* Clear the timer active flag. */ task -> tc_timer_active = NU_FALSE; } } } #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_RESUME_TASK); #endif /*INCLUDE_PROVIEW*/ /* Return back the status. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Resume_Service */ /* */ /* DESCRIPTION */ /* */ /* This function provides an interface identical to the application */ /* service call to resume a task. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Resume_Service Error checking function */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Resume_Task Resume a task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Protect Protect system structures */ /* TCT_Unprotect Release system protection */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS Always returns 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, */ /* added system protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* 12-19-1995 Changed the "task" parameter to */ /* "task_ptr" in the */ /* HIC_Make_History_Entry call, */ /* resulting in version 1.1+ */ /* (SPR 36, 64, 66, 77) */ /* 10-02-1998 Another protect problem (1.3a) */ /* */ /*************************************************************************/ STATUS TCC_Resume_Service(NU_TASK *task_ptr) { TC_PROTECT *save_protect; /* Save current protection */ 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_RESUME_TASK_ID, (UNSIGNED) task_ptr, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Save current protection. */ if (TCD_Current_Thread != NU_NULL) { save_protect = TCT_Get_Current_Protect(); } else { save_protect = NU_NULL; } /* Protect system structures. */ TCT_Protect(&TCD_System_Protect); /* Call the actual resume task function. If the function returns a NU_TRUE, context switching is needed. */ if (TCC_Resume_Task(task_ptr, NU_PURE_SUSPEND)) { /* Transfer control back to the system for a context switch. */ TCT_Control_To_System(); } /* Determine how to get out of protection. */ if (save_protect) { /* Restore current protection. */ TCT_Set_Current_Protect(save_protect); /* Release system protect. */ TCT_Unprotect_Specific(&TCD_System_Protect); } else /* Release protection of system structures. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Always return a successful status. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Suspend_Task */ /* */ /* DESCRIPTION */ /* */ /* This function suspends the specified task. If the specified */ /* task is the calling task, control is transferred back to the */ /* system. */ /* */ /* CALLED BY */ /* */ /* Other Components */ /* TCC_Suspend_Service Task suspend service */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Protect Protect system structures */ /* TCT_Set_Execute_Task Set TCD_Execute_Task pointer */ /* TCT_Protect_Switch Allow protected task to run */ /* briefly */ /* TCT_Unprotect Release system protection */ /* TMC_Start_Task_Timer Start a task timer */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* suspend_type Type of suspension to lift */ /* cleanup Cleanup routine */ /* information Information for cleanup */ /* timeout Timeout on the suspension */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 02-01-1994 Corrected a suspension with */ /* timeout problem that caused */ /* unconditional task suspension */ /* for timeouts and sleeps for 1 */ /* tick, resulting in version 1.0f */ /* 02-01-1994 Verified version 1.0f */ /* 03-01-1994 Modified function interface, */ /* added register optimizations, */ /* fixed a possible suspending an */ /* executing task from a HISR, */ /* removed excessive protection */ /* logic since protection is now */ /* in force upon function entry, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* 06-01-1996 Checked to see whether */ /* task == TCD_Current_Thread */ /* regardless of whether task == */ /* TCD_Execute_Task (SPR152) */ /* */ /*************************************************************************/ VOID TCC_Suspend_Task(NU_TASK *task_ptr, OPTION suspend_type, VOID (*cleanup) (VOID *), VOID *information, UNSIGNED timeout) { R1 TC_TCB *task; /* Task control block ptr */ R2 INT index; /* Working index variable */ DATA_ELEMENT temp; /* Temporary variable */ /* Move input task 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 /* Determine if there is a timeout to initiate. */ if (timeout != NU_SUSPEND) { /* Indicate that a task timer is active. */ task -> tc_timer_active = NU_TRUE; /* Start a timeout on the suspension. */ TMC_Start_Task_Timer(&(task -> tc_timer_control),timeout); } /* Check for a non self-suspension. In such cases, the target task cannot have any type of protection in force. */ if (task != (TC_TCB *) TCD_Current_Thread) { do { /* Check for protection. Remember that system protection is 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 of the system structures. */ TCT_Protect(&TCD_System_Protect); } } while (task -> tc_current_protect); } /* Check to see if the task is currently ready. */ if (task -> tc_status == NU_READY) { /* Mark the task with the appropriate suspension code. */ task -> tc_status = suspend_type; /* Store off termination information in the tasks control block. */ task -> tc_cleanup = cleanup; task -> tc_cleanup_info = information; /* 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); /* Determine if this priority group was the highest in the system. */ if (task -> tc_priority == (DATA_ELEMENT) TCD_Highest_Priority) { /* Determine the highest priority task in the system. */ if (TCD_Priority_Groups == 0) { /* Re-initialize the highest priority variable and clear the current task pointer. */ TCD_Highest_Priority = TC_PRIORITIES; } else { /* Find the next highest priority task. */ 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]; } } } 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; /* See if the task being suspended is the current. */ if (*(task -> tc_priority_head) == task) /* Update the head of this priority list. */ *(task -> tc_priority_head) = task -> tc_ready_next; /* Clear the task's pointers. */ task -> tc_ready_next = NU_NULL; task -> tc_ready_previous = NU_NULL; } /* Determine if this task the highest priority task. */ if (task == TCD_Execute_Task) { /* Determine the next task to execute. */ if (TCD_Highest_Priority < TC_PRIORITIES) /* Put the next task to execute in TCD_Execute_Task. */ TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]); else /* No other task is ready for execution. */ TCT_Set_Execute_Task(NU_NULL); } #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_SUSPEND_TASK); if (suspend_type == NU_SLEEP_SUSPEND) { _RTProf_TaskStatus(task,RT_TASK_SLEEPING); } else if (suspend_type == NU_PURE_SUSPEND) { _RTProf_TaskStatus(task,RT_TASK_SUSPENDED); } else { _RTProf_TaskStatus(task,RT_TASK_WAITING); } #endif /*INCLUDE_PROVIEW*/ /* See if the suspending task is the current thread. (SPR152) */ if (task == (TC_TCB *) TCD_Current_Thread) /* Leave the task, transfer control to the system. */ TCT_Control_To_System(); } else { /* Check for a pure suspension request. If present, the delayed suspension flag is set. */ if (suspend_type == NU_PURE_SUSPEND) /* Setup the delayed suspension flag. */ task -> tc_delayed_suspend = NU_TRUE; #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_SUSPEND_TASK); #endif /*INCLUDE_PROVIEW*/ } } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Suspend_Service */ /* */ /* DESCRIPTION */ /* */ /* This function provides a suitable interface to the actual */ /* service to suspend a task. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Suspend_Service Error checking function */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Suspend_Task Suspend a task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect system structures */ /* TCT_Unprotect Release system structures */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS Always a successful status */ /* */ /* 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, */ /* added system protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Suspend_Service(NU_TASK *task_ptr) { 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_SUSPEND_TASK_ID, (UNSIGNED) task_ptr, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect system data structures. */ TCT_Protect(&TCD_System_Protect); /* Call the actual routine to suspend the task. */ TCC_Suspend_Task(task_ptr, NU_PURE_SUSPEND, NU_NULL, NU_NULL, NU_SUSPEND); /* Release system protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Always return a successful status. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Task_Timeout */ /* */ /* DESCRIPTION */ /* */ /* This function processes task suspension timeout conditions. */ /* Note that task sleep requests are also considered a timeout */ /* condition. This routine must be called from Supervisor mode in */ /* a Supervisor/User mode switching kernel. */ /* */ /* CALLED BY */ /* */ /* TMC_Timer_Task Timer expiration task */ /* */ /* CALLS */ /* */ /* Caller's cleanup function */ /* TCC_Resume_Task Resume a suspended task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect scheduling list */ /* TCT_Set_Current_Protect Setup current protection */ /* TCT_Unprotect Release protection */ /* TCT_Unprotect_Specific Release specific protection */ /* */ /* INPUTS */ /* */ /* task_ptr Task control block pointer */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 02-01-1994 Added logic to clear the timer */ /* active flag when the target */ /* task is already in a ready */ /* state, resulting in */ /* version 1.0f */ /* 02-01-1994 Verified version 1.0f */ /* 03-01-1994 Modified function interface, */ /* added register optimizations, */ /* removed logic for timeout */ /* before suspension because new */ /* protection logic eliminates */ /* the possibility, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ VOID TCC_Task_Timeout(NU_TASK *task_ptr) { R1 TC_TCB *task; /* Task control block ptr */ TC_PROTECT *suspend_protect; /* Suspension protect ptr */ DATA_ELEMENT task_status; /* Task status variable */ /* 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 /* Protect system data structures. */ TCT_Protect(&TCD_System_Protect); /* Pickup the suspension protection saved-off when the task was suspended. */ suspend_protect = task -> tc_suspend_protect; /* Is a signal handler currently running? */ if (task -> tc_signal_active) /* Use the saved status for current task status */ task_status = task -> tc_saved_status; else /* Just use the current task status */ task_status = task -> tc_status; /* Release protection of the scheduling list. */ TCT_Unprotect(); /* Determine if there is a suspend protect. */ if (suspend_protect) /* Protect the suspended protection. */ TCT_Protect(suspend_protect); /* Now protect the system structures again. Note that the order the protections are made prevents deadlocks. */ TCT_Protect(&TCD_System_Protect); /* Determine if the task is still suspended in the same manner. */ if ((task -> tc_status == task_status) || ((task -> tc_signal_active) && (task -> tc_saved_status == task_status))) { /* Make sure that this timeout processing is still valid. */ if ((task -> tc_timer_active) && (task -> tc_timer_control.tm_remaining_time == 0)) { /* Clear the timer active flag. */ task -> tc_timer_active = NU_FALSE; /* Call the cleanup function, if there is one. */ if (task -> tc_cleanup) /* Call cleanup function. */ (*(task -> tc_cleanup)) (task -> tc_cleanup_info); /* Resume the task. */ TCC_Resume_Task(task_ptr, task_status); } } /* Determine if a suspend protection was in force. */ if (suspend_protect) { /* Set the current protection to the suspend protect. */ TCT_Set_Current_Protect(suspend_protect); TCT_Unprotect_Specific(&TCD_System_Protect); } /* Release current protection. */ TCT_Unprotect(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Task_Sleep */ /* */ /* DESCRIPTION */ /* */ /* This function provides task sleep suspensions. Its primary */ /* purpose is to interface with the actual task suspension function.*/ /* */ /* CALLED BY */ /* */ /* Application */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Suspend_Task Suspend a task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect system structures */ /* TCT_Unprotect Release system structures */ /* */ /* INPUTS */ /* */ /* ticks Number of timer ticks */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Modified call to suspend the */ /* calling task, resulting in */ /* version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ VOID TCC_Task_Sleep(UNSIGNED ticks) { 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_SLEEP_ID, (UNSIGNED) ticks, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect system data structures. */ TCT_Protect(&TCD_System_Protect); #ifdef INCLUDE_PROVIEW _RTProf_DumpTask((TC_TCB *)TCD_Current_Thread,RT_PROF_SLEEP); #endif /*INCLUDE_PROVIEW*/ /* Call the actual routine to suspend the task. */ TCC_Suspend_Task((NU_TASK *) TCD_Current_Thread, NU_SLEEP_SUSPEND, NU_NULL, NU_NULL, ticks); /* Release system protection. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Relinquish */ /* */ /* DESCRIPTION */ /* */ /* This function moves the calling task to the end of other tasks */ /* at the same priority level. The calling task does not execute */ /* again until all the other tasks of the same priority get a */ /* chance to execute. */ /* */ /* CALLED BY */ /* */ /* Application */ /* TCCE_Relinquish 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 system structures */ /* TCT_Set_Execute_Task Set TCD_Execute_Task pointer */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* None */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* 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 */ /* */ /*************************************************************************/ VOID TCC_Relinquish(VOID) { TC_TCB *task; /* Pointer to task */ 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_RELINQUISH_ID, (UNSIGNED) 0, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect against multiple access to the system structures. */ TCT_Protect(&TCD_System_Protect); /* Pickup the current thread and place it in the task pointer. */ task = (TC_TCB *) TCD_Current_Thread; #ifdef INCLUDE_PROVIEW _RTProf_DumpTask(task,RT_PROF_RELINQUISH); #endif /*INCLUDE_PROVIEW*/ /* Determine if another task is ready to run. */ if ((task -> tc_ready_next != task) || (task -> tc_priority != (DATA_ELEMENT) TCD_Highest_Priority)) { /* Move the executing task to the end of tasks having the same priority. */ *(task -> tc_priority_head) = task -> tc_ready_next; /* Setup the next task to execute. */ TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]); /* Transfer control back to the system. */ TCT_Control_To_System(); } /* Release protection of system structures. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Time_Slice */ /* */ /* DESCRIPTION */ /* */ /* This function moves the specified task to the end of the other */ /* tasks at the same priority level. If the specified task is no */ /* longer ready, this request is ignored. This routine must be */ /* called from Supervisor mode in a Supervisor/User mode */ /* switching kernel. */ /* */ /* CALLED BY */ /* */ /* TMC_Timer_HISR Time-slice interrupt */ /* */ /* CALLS */ /* */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect the scheduling data */ /* TCT_Set_Execute_Task Set TCD_Execute_Task pointer */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* task Task control block pointer */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* 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, */ /* slightly modified protection */ /* logic, resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ VOID TCC_Time_Slice(NU_TASK *task_ptr) { R1 TC_TCB *task; /* Task control block ptr */ /* 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 /* Protect against multiple access to the system structures. */ TCT_Protect(&TCD_System_Protect); /* Determine if another task is ready to run. */ if (((task -> tc_status == NU_READY) && (task -> tc_preemption)) && ((task -> tc_ready_next != task) || (task -> tc_priority != (DATA_ELEMENT) TCD_Highest_Priority))) { /* Move the executing task to the end of tasks having the same priority. */ *(task -> tc_priority_head) = task -> tc_ready_next; /* Setup the next task to execute. */ TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]); } /* Release protection of the system structures. */ TCT_Unprotect(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Current_Task_Pointer */ /* */ /* DESCRIPTION */ /* */ /* This function returns the pointer of the currently executing */ /* task. If the current thread is not a task thread, a NU_NULL */ /* is returned. */ /* */ /* CALLED BY */ /* */ /* Application */ /* Other Components */ /* */ /* CALLS */ /* */ /* None */ /* */ /* INPUTS */ /* */ /* None */ /* */ /* OUTPUTS */ /* */ /* Task Pointer Active tasks pointer or */ /* NU_NULL if not a task */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Modified function interface, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ NU_TASK *TCC_Current_Task_Pointer(VOID) { /* Determine if a task thread is executing. */ if ((TCD_Current_Thread) && (((TC_TCB *) TCD_Current_Thread) -> tc_id == TC_TASK_ID)) /* Task thread is running, return the pointer. */ return((NU_TASK *) TCD_Current_Thread); else /* No, task thread is not running, return a NU_NULL. */ return(NU_NULL); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Current_HISR_Pointer */ /* */ /* DESCRIPTION */ /* */ /* This function returns the pointer of the currently executing */ /* HISR. If the current thread is not a HISR thread, a NU_NULL */ /* is returned. */ /* */ /* CALLED BY */ /* */ /* Application */ /* Other Components */ /* */ /* CALLS */ /* */ /* None */ /* */ /* INPUTS */ /* */ /* None */ /* */ /* OUTPUTS */ /* */ /* HISR Pointer Active HISR pointer or */ /* NU_NULL if not a HISR */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Modified function interface, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ NU_HISR *TCC_Current_HISR_Pointer(VOID) { /* Determine if a HISR thread is executing. */ if ((TCD_Current_Thread) && (((TC_HCB *) TCD_Current_Thread) -> tc_id == TC_HISR_ID)) /* HISR thread is running, return the pointer. */ return((NU_HISR *) TCD_Current_Thread); else /* No, HISR thread is not running, return a NU_NULL. */ return(NU_NULL); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Task_Shell */ /* */ /* DESCRIPTION */ /* */ /* This function is shell from which all application tasks are */ /* initially executed. The shell causes the task to finish when */ /* control is returned from the application task. Also, the shell */ /* passes argc and argv arguments to the task's entry function. */ /* */ /* CALLED BY */ /* */ /* TCC_Control_To_Task Control to task routine */ /* */ /* CALLS */ /* */ /* Task Entry Function */ /* TCC_Suspend_Task Suspend task when finished */ /* TCT_Protect Protect system structures */ /* */ /* INPUTS */ /* */ /* None */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Added protection logic prior to */ /* suspending the task, resulting */ /* in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ VOID TCC_Task_Shell(VOID) { NU_SUPERV_USER_VARIABLES /* Call the task's entry function with the argc and argv parameters supplied during task creation or reset. */ (*(TCD_Execute_Task -> tc_entry)) (TCD_Execute_Task -> tc_argc, TCD_Execute_Task -> tc_argv); /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Protect system data structures. */ TCT_Protect(&TCD_System_Protect); /* If the task returns, suspend it in a finished state. Note that the task cannot execute again until it is reset. Therefore, this call never returns. */ TCC_Suspend_Task((NU_TASK *) TCD_Execute_Task, NU_FINISHED, NU_NULL, NU_NULL, NU_SUSPEND); /* Return to user mode */ NU_USER_MODE(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Signal_Shell */ /* */ /* DESCRIPTION */ /* */ /* This function processes signals by calling the task supplied */ /* signal handling function. When signal handling is completed, */ /* the task is placed in the appropriate state. */ /* */ /* CALLED BY */ /* */ /* TCC_Control_Signals Control task's signals */ /* TCC_Register_Signal_Handler Register a signal handler */ /* */ /* CALLS */ /* */ /* task's signal handling routine */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Signal_Exit Signal handling exit routine */ /* TCT_Protect Protect against other access */ /* TCT_Set_Execute_Task Set TCD_Execute_Task pointer */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* None */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Added register optimizations, */ /* modified protection logic, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ VOID TCC_Signal_Shell(VOID) { R2 UNSIGNED signals; /* Signals to send to task */ INT index; /* Working index variable */ DATA_ELEMENT temp; /* Temporary variable */ R1 TC_TCB *task; /* Task pointer */ #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif /* Point at the current task. */ task = (TC_TCB *) TCD_Current_Thread; /* Protect against simultaneous access. */ TCT_Protect(&TCD_System_Protect); /* Process while there are signals to handle. */ while (task -> tc_signals & task -> tc_enabled_signals) { /* Pickup the signals and clear them. */ signals = task -> tc_signals; task -> tc_signals = 0; /* Release protection. */ TCT_Unprotect(); /* Call the application signal handling function, if there still is one. */ if (task -> tc_signal_handler) { NU_SUPERV_USER_VARIABLES #if (defined(NU_SUPERV_USER_MODE)) && (NU_SUPERV_USER_MODE > 0) UNSIGNED savedMode = task->tc_su_mode; task->tc_su_mode = 1; /* Force transition to User mode */ #endif /* Switch to user mode */ NU_USER_MODE(); /* Call signal handler. (always in User mode) */ (*(task -> tc_signal_handler))(signals); /* Return to supervisor mode */ NU_SUPERVISOR_MODE(); #if (defined(NU_SUPERV_USER_MODE)) && (NU_SUPERV_USER_MODE > 0) task->tc_su_mode = savedMode; /* Restore original nesting count */ #endif } /* Protect against simultaneous access again. */ TCT_Protect(&TCD_System_Protect); } /* At this point, signals have been exhausted and protection is in force. */ /* Clear the signal in process flag. */ task -> tc_signal_active = NU_FALSE; /* Determine how the signal handler was called. Either in a solicited or an unsolicited manner. */ if (task -> tc_saved_stack_ptr) { /* Determine if the saved status still indicates that the task should be suspended. */ if (task -> tc_saved_status != NU_READY) { /* Suspend the task. */ task -> tc_status = task -> tc_saved_status; /* 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); /* Determine if this priority group was the highest in the system. */ if (task -> tc_priority == (DATA_ELEMENT) TCD_Highest_Priority) { /* Determine the highest priority task in the system. */ if (TCD_Priority_Groups == 0) { /* Re-initialize the highest priority variable and clear the current task pointer. */ TCD_Highest_Priority = TC_PRIORITIES; } else { /* Find the next highest priority task. */ 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]; } } } 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; /* See if the task being suspended is the current. */ if (*(task -> tc_priority_head) == task) /* Update the head of this priority list. */ *(task -> tc_priority_head) = task -> tc_ready_next; /* Clear the task's pointers. */ task -> tc_ready_next = NU_NULL; task -> tc_ready_previous = NU_NULL; } /* Determine the next task to execute. */ if (TCD_Highest_Priority < TC_PRIORITIES) /* Put the next task to execute in TCD_Execute_Task. */ TCT_Set_Execute_Task(TCD_Priority_List[TCD_Highest_Priority]); else /* No other task is ready for execution. */ TCT_Set_Execute_Task(NU_NULL); } /* At this point, just exit back to the system. Note that the signal exit routine clears the scheduling protection. */ TCT_Signal_Exit(); } /* A signal handler was called from the current task. Nothing needs to be done except to release protection. */ TCT_Unprotect(); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Dispatch_LISR */ /* */ /* DESCRIPTION */ /* */ /* This function dispatches the LISR associated with the specified */ /* interrupt vector. Note that this function is called during */ /* the interrupt thread. This routine must be called from */ /* Supervisor mode in a Supervisor/User mode switching kernel. */ /* */ /* CALLED BY */ /* */ /* INT_Interrupt_Shell Shell of interrupt routine */ /* */ /* CALLS */ /* */ /* application LISR */ /* ERC_System_Error Unhandled interrupt error */ /* */ /* INPUTS */ /* */ /* vector Vector number of interrupt */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 11-01-1993 Added logic to save unhandled */ /* interrupt vector number in */ /* a global variable, resulting */ /* in version 1.0e */ /* 11-01-1993 Verified version 1.0e */ /* */ /*************************************************************************/ VOID TCC_Dispatch_LISR(INT vector) { INT index; /* Working index variable */ /* Determine if the specified vector has an LISR registered to it. */ index = (INT) TCD_Registered_LISRs[vector]; if (index <= NU_MAX_LISRS) { #ifdef INCLUDE_PROVIEW _RTProf_Dispatch_LISR_No_INT_Lock(vector); #endif /*INCLUDE_PROVIEW*/ /* Yes, an LISR is associated with this vector. Call the actual registered LISR routine. */ (*(TCD_LISR_Pointers[index])) (vector); } else { /* Save interrupt vector number in TCD_Unhandled_Interrupt. */ TCD_Unhandled_Interrupt = vector; /* System error, unhandled interrupt. */ ERC_System_Error(NU_UNHANDLED_INTERRUPT); } } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* TCC_Register_LISR */ /* */ /* DESCRIPTION */ /* */ /* This function registers the supplied LISR with the supplied */ /* vector number. If the supplied LISR is NU_NULL, the supplied */ /* vector is de-registered. The previously registered LISR is */ /* returned to the caller, along with the completion status. This */ /* routine must be called from Supervisor mode in a Supervisor/ */ /* User mode switching kernel. */ /* */ /* CALLED BY */ /* */ /* Application */ /* */ /* CALLS */ /* */ /* [HIC_Make_History_Entry] Make entry in history log */ /* INT_Retrieve_Shell Retrieve vector shell pointer*/ /* INT_Setup_Vector Setup the actual vector */ /* INT_Vectors_Loaded Determine if interrupt shell */ /* routines are loaded */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Protect LISR registration */ /* TCT_Unprotect Release LISR protection */ /* */ /* INPUTS */ /* */ /* vector Vector number of interrupt */ /* new_lisr New LISR function */ /* old_lisr Previous LISR function ptr */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS Successful registration */ /* NU_INVALID_VECTOR Invalid interrupt vector */ /* NU_NO_MORE_LISRS LISR registration table is */ /* full */ /* NU_NOT_REGISTERED LISR was not registered */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Added appropriate casting, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS TCC_Register_LISR(INT vector, VOID (*new_lisr)(INT), VOID (**old_lisr)(INT)) { INT index; /* Working index variable */ STATUS status; /* Completion status */ #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_LISR_ID, (UNSIGNED) vector, (UNSIGNED) new_lisr, (UNSIGNED) old_lisr); #endif /* Determine if the vector is legal. */ if (vector > NU_MAX_VECTORS) return(NU_INVALID_VECTOR); /* Initialize the completion status to successful. */ status = NU_SUCCESS; /* Protect against LISR registration list access. */ TCT_Protect(&TCD_LISR_Protect); /* Determine if a registration or deregistration is requested. This is determined by the value of new_lisr. A NULL value indicates deregistration. */ if (new_lisr) { /* Register the new LISR. */ /* Determine if the vector already has a registration. */ if (TCD_Registered_LISRs[vector]) { /* Yes, a registration exists. */ /* Pickup the index into the LISR pointer list. */ index = (INT) TCD_Registered_LISRs[vector]; /* Temporarily indicate that the LISR is not registered. */ TCD_Registered_LISRs[vector] = 0; /* Copy the currently registered LISR into the old_lisr return area. */ *old_lisr = TCD_LISR_Pointers[index]; /* Place the new LISR into the list. */ TCD_LISR_Pointers[index] = new_lisr; /* Indicate the LISR is registered again. */ TCD_Registered_LISRs[vector] = (UNSIGNED_CHAR) index; } else { /* An empty slot needs to be found in the LISR pointers list. */ index = 0; while ((index <= NU_MAX_LISRS) && (TCD_LISR_Pointers[index] != NU_NULL)) index++; /* Determine if an empty slot was found. */ if (index <= NU_MAX_LISRS) { /* Yes, an empty slot was found. */ /* Place the new LISR in the LISR pointers list. */ TCD_LISR_Pointers[index] = new_lisr; /* Associate the index into the pointers list to the actual vector. */ TCD_Registered_LISRs[vector] = (UNSIGNED_CHAR) index; /* Indicate that there was no previous LISR registered. */ *old_lisr = NU_NULL; /* Determine if the actual vector needs to be stolen. */ if (!INT_Vectors_Loaded()) /* Actual vector needs to be replaced with the appropriate ISR shell. */ INT_Setup_Vector(vector, INT_Retrieve_Shell(vector)); } else /* Return the completion status that indicates that there is no more room in the LISR pointers list. */ status = NU_NO_MORE_LISRS; } } else { /* De-register the specified vector. */ /* Determine if the vector has a registration current. */ if (TCD_Registered_LISRs[vector]) { /* Pickup the index into the LISR pointer list. */ index = (INT) TCD_Registered_LISRs[vector]; /* Clear the registration table. */ TCD_Registered_LISRs[vector] = 0; /* Return the previously registered LISR. */ *old_lisr = TCD_LISR_Pointers[index]; /* Clear the LISR pointer list entry. */ TCD_LISR_Pointers[index] = NU_NULL; } else /* The vector is not registered. Return an error completion status. */ status = NU_NOT_REGISTERED; } #ifdef INCLUDE_PROVIEW _RTProf_RegisterLisr(vector); #endif /*INCLUDE_PROVIEW*/ /* Release protection on the LISR registration list. */ TCT_Unprotect(); /* Return the completion status. */ return(status); }