| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- |
| -- -- |
| -- S Y S T E M . T A S K I N G . R E S T R I C T E D . S T A G E S -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 1999-2014, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNARL is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. -- |
| -- -- |
| -- As a special exception under Section 7 of GPL version 3, you are granted -- |
| -- additional permissions described in the GCC Runtime Library Exception, -- |
| -- version 3.1, as published by the Free Software Foundation. -- |
| -- -- |
| -- You should have received a copy of the GNU General Public License and -- |
| -- a copy of the GCC Runtime Library Exception along with this program; -- |
| -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- |
| -- <http://www.gnu.org/licenses/>. -- |
| -- -- |
| -- GNARL was developed by the GNARL team at Florida State University. -- |
| -- Extensive contributions were provided by Ada Core Technologies, Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| pragma Style_Checks (All_Checks); |
| -- Turn off subprogram alpha order check, since we group soft link |
| -- bodies and also separate off subprograms for restricted GNARLI. |
| |
| -- This is a simplified version of the System.Tasking.Stages package, |
| -- intended to be used in a restricted run time. |
| |
| -- This package represents the high level tasking interface used by the |
| -- compiler to expand Ada 95 tasking constructs into simpler run time calls. |
| |
| pragma Polling (Off); |
| -- Turn off polling, we do not want ATC polling to take place during |
| -- tasking operations. It causes infinite loops and other problems. |
| |
| with Ada.Exceptions; |
| |
| with System.Task_Primitives.Operations; |
| with System.Soft_Links.Tasking; |
| with System.Storage_Elements; |
| |
| with System.Secondary_Stack; |
| pragma Elaborate_All (System.Secondary_Stack); |
| -- Make sure the body of Secondary_Stack is elaborated before calling |
| -- Init_Tasking_Soft_Links. See comments for this routine for explanation. |
| |
| with System.Soft_Links; |
| -- Used for the non-tasking routines (*_NT) that refer to global data. They |
| -- are needed here before the tasking run time has been elaborated. used for |
| -- Create_TSD This package also provides initialization routines for task |
| -- specific data. The GNARL must call these to be sure that all non-tasking |
| -- Ada constructs will work. |
| |
| package body System.Tasking.Restricted.Stages is |
| |
| package STPO renames System.Task_Primitives.Operations; |
| package SSL renames System.Soft_Links; |
| package SSE renames System.Storage_Elements; |
| package SST renames System.Secondary_Stack; |
| |
| use Ada.Exceptions; |
| |
| use Parameters; |
| use Task_Primitives.Operations; |
| use Task_Info; |
| |
| Tasks_Activation_Chain : Task_Id; |
| -- Chain of all the tasks to activate |
| |
| Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock; |
| -- This is a global lock; it is used to execute in mutual exclusion |
| -- from all other tasks. It is only used by Task_Lock and Task_Unlock. |
| |
| ----------------------------------------------------------------- |
| -- Tasking versions of services needed by non-tasking programs -- |
| ----------------------------------------------------------------- |
| |
| function Get_Current_Excep return SSL.EOA; |
| -- Task-safe version of SSL.Get_Current_Excep |
| |
| procedure Task_Lock; |
| -- Locks out other tasks. Preceding a section of code by Task_Lock and |
| -- following it by Task_Unlock creates a critical region. This is used |
| -- for ensuring that a region of non-tasking code (such as code used to |
| -- allocate memory) is tasking safe. Note that it is valid for calls to |
| -- Task_Lock/Task_Unlock to be nested, and this must work properly, i.e. |
| -- only the corresponding outer level Task_Unlock will actually unlock. |
| |
| procedure Task_Unlock; |
| -- Releases lock previously set by call to Task_Lock. In the nested case, |
| -- all nested locks must be released before other tasks competing for the |
| -- tasking lock are released. |
| |
| ----------------------- |
| -- Local Subprograms -- |
| ----------------------- |
| |
| procedure Task_Wrapper (Self_ID : Task_Id); |
| -- This is the procedure that is called by the GNULL from the |
| -- new context when a task is created. It waits for activation |
| -- and then calls the task body procedure. When the task body |
| -- procedure completes, it terminates the task. |
| |
| procedure Terminate_Task (Self_ID : Task_Id); |
| -- Terminate the calling task. |
| -- This should only be called by the Task_Wrapper procedure. |
| |
| procedure Create_Restricted_Task |
| (Priority : Integer; |
| Stack_Address : System.Address; |
| Size : System.Parameters.Size_Type; |
| Task_Info : System.Task_Info.Task_Info_Type; |
| CPU : Integer; |
| State : Task_Procedure_Access; |
| Discriminants : System.Address; |
| Elaborated : Access_Boolean; |
| Task_Image : String; |
| Created_Task : Task_Id); |
| -- Code shared between Create_Restricted_Task (the concurrent version) and |
| -- Create_Restricted_Task_Sequential. See comment of the former in the |
| -- specification of this package. |
| |
| procedure Activate_Tasks (Chain : Task_Id); |
| -- Activate the list of tasks started by Chain |
| |
| procedure Init_RTS; |
| -- This procedure performs the initialization of the GNARL. |
| -- It consists of initializing the environment task, global locks, and |
| -- installing tasking versions of certain operations used by the compiler. |
| -- Init_RTS is called during elaboration. |
| |
| ----------------------- |
| -- Get_Current_Excep -- |
| ----------------------- |
| |
| function Get_Current_Excep return SSL.EOA is |
| begin |
| return STPO.Self.Common.Compiler_Data.Current_Excep'Access; |
| end Get_Current_Excep; |
| |
| --------------- |
| -- Task_Lock -- |
| --------------- |
| |
| procedure Task_Lock is |
| Self_ID : constant Task_Id := STPO.Self; |
| |
| begin |
| Self_ID.Common.Global_Task_Lock_Nesting := |
| Self_ID.Common.Global_Task_Lock_Nesting + 1; |
| |
| if Self_ID.Common.Global_Task_Lock_Nesting = 1 then |
| STPO.Write_Lock (Global_Task_Lock'Access, Global_Lock => True); |
| end if; |
| end Task_Lock; |
| |
| ----------------- |
| -- Task_Unlock -- |
| ----------------- |
| |
| procedure Task_Unlock is |
| Self_ID : constant Task_Id := STPO.Self; |
| |
| begin |
| pragma Assert (Self_ID.Common.Global_Task_Lock_Nesting > 0); |
| Self_ID.Common.Global_Task_Lock_Nesting := |
| Self_ID.Common.Global_Task_Lock_Nesting - 1; |
| |
| if Self_ID.Common.Global_Task_Lock_Nesting = 0 then |
| STPO.Unlock (Global_Task_Lock'Access, Global_Lock => True); |
| end if; |
| end Task_Unlock; |
| |
| ------------------ |
| -- Task_Wrapper -- |
| ------------------ |
| |
| -- The task wrapper is a procedure that is called first for each task |
| -- task body, and which in turn calls the compiler-generated task body |
| -- procedure. The wrapper's main job is to do initialization for the task. |
| |
| -- The variable ID in the task wrapper is used to implement the Self |
| -- function on targets where there is a fast way to find the stack base |
| -- of the current thread, since it should be at a fixed offset from the |
| -- stack base. |
| |
| procedure Task_Wrapper (Self_ID : Task_Id) is |
| ID : Task_Id := Self_ID; |
| pragma Volatile (ID); |
| pragma Warnings (Off, ID); |
| -- Variable used on some targets to implement a fast self. We turn off |
| -- warnings because a stand alone volatile constant has to be imported, |
| -- so we don't want warnings about ID not being referenced, and volatile |
| -- having no effect. |
| -- |
| -- DO NOT delete ID. As noted, it is needed on some targets. |
| |
| use type SSE.Storage_Offset; |
| |
| Secondary_Stack : aliased SSE.Storage_Array |
| (1 .. Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size * |
| SSE.Storage_Offset (Parameters.Sec_Stack_Percentage) / 100); |
| for Secondary_Stack'Alignment use Standard'Maximum_Alignment; |
| -- This is the secondary stack data. Note that it is critical that this |
| -- have maximum alignment, since any kind of data can be allocated here. |
| |
| pragma Warnings (Off); |
| Secondary_Stack_Address : System.Address := Secondary_Stack'Address; |
| pragma Warnings (On); |
| -- Address of secondary stack. In the fixed secondary stack case, this |
| -- value is not modified, causing a warning, hence the bracketing with |
| -- Warnings (Off/On). |
| |
| Cause : Cause_Of_Termination := Normal; |
| -- Indicates the reason why this task terminates. Normal corresponds to |
| -- a task terminating due to completing the last statement of its body. |
| -- If the task terminates because of an exception raised by the |
| -- execution of its task body, then Cause is set to Unhandled_Exception. |
| -- Aborts are not allowed in the restricted profile to which this file |
| -- belongs. |
| |
| EO : Exception_Occurrence; |
| -- If the task terminates because of an exception raised by the |
| -- execution of its task body, then EO will contain the associated |
| -- exception occurrence. Otherwise, it will contain Null_Occurrence. |
| |
| begin |
| if not Parameters.Sec_Stack_Dynamic then |
| Self_ID.Common.Compiler_Data.Sec_Stack_Addr := |
| Secondary_Stack'Address; |
| SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last)); |
| end if; |
| |
| -- Initialize low-level TCB components, that |
| -- cannot be initialized by the creator. |
| |
| Enter_Task (Self_ID); |
| |
| -- Call the task body procedure |
| |
| begin |
| -- We are separating the following portion of the code in order to |
| -- place the exception handlers in a different block. In this way we |
| -- do not call Set_Jmpbuf_Address (which needs Self) before we set |
| -- Self in Enter_Task. |
| |
| -- Note that in the case of Ravenscar HI-E where there are no |
| -- exception handlers, the exception handler is suppressed. |
| |
| -- Call the task body procedure |
| |
| Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg); |
| |
| -- Normal task termination |
| |
| Cause := Normal; |
| Save_Occurrence (EO, Ada.Exceptions.Null_Occurrence); |
| |
| exception |
| when E : others => |
| |
| -- Task terminating because of an unhandled exception |
| |
| Cause := Unhandled_Exception; |
| Save_Occurrence (EO, E); |
| end; |
| |
| -- Look for a fall-back handler |
| |
| -- This package is part of the restricted run time which supports |
| -- neither task hierarchies (No_Task_Hierarchy) nor specific task |
| -- termination handlers (No_Specific_Termination_Handlers). |
| |
| -- As specified in ARM C.7.3 par. 9/2, "the fall-back handler applies |
| -- only to the dependent tasks of the task". Hence, if the terminating |
| -- tasks (Self_ID) had a fall-back handler, it would not apply to |
| -- itself. This code is always executed by a task whose master is the |
| -- environment task (the task termination code for the environment task |
| -- is executed by SSL.Task_Termination_Handler), so the fall-back |
| -- handler to execute for this task can only be defined by its parent |
| -- (there is no grandparent). |
| |
| declare |
| TH : Termination_Handler := null; |
| |
| begin |
| if Single_Lock then |
| Lock_RTS; |
| end if; |
| |
| Write_Lock (Self_ID.Common.Parent); |
| |
| TH := Self_ID.Common.Parent.Common.Fall_Back_Handler; |
| |
| Unlock (Self_ID.Common.Parent); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| |
| -- Execute the task termination handler if we found it |
| |
| if TH /= null then |
| TH.all (Cause, Self_ID, EO); |
| end if; |
| end; |
| |
| Terminate_Task (Self_ID); |
| end Task_Wrapper; |
| |
| ----------------------- |
| -- Restricted GNARLI -- |
| ----------------------- |
| |
| ----------------------------------- |
| -- Activate_All_Tasks_Sequential -- |
| ----------------------------------- |
| |
| procedure Activate_All_Tasks_Sequential is |
| begin |
| pragma Assert (Partition_Elaboration_Policy = 'S'); |
| |
| Activate_Tasks (Tasks_Activation_Chain); |
| Tasks_Activation_Chain := Null_Task; |
| end Activate_All_Tasks_Sequential; |
| |
| ------------------------------- |
| -- Activate_Restricted_Tasks -- |
| ------------------------------- |
| |
| procedure Activate_Restricted_Tasks |
| (Chain_Access : Activation_Chain_Access) is |
| begin |
| if Partition_Elaboration_Policy = 'S' then |
| |
| -- In sequential elaboration policy, the chain must be empty. This |
| -- procedure can be called if the unit has been compiled without |
| -- partition elaboration policy, but the partition has a sequential |
| -- elaboration policy. |
| |
| pragma Assert (Chain_Access.T_ID = Null_Task); |
| null; |
| else |
| Activate_Tasks (Chain_Access.T_ID); |
| Chain_Access.T_ID := Null_Task; |
| end if; |
| end Activate_Restricted_Tasks; |
| |
| -------------------- |
| -- Activate_Tasks -- |
| -------------------- |
| |
| -- Note that locks of activator and activated task are both locked here. |
| -- This is necessary because C.State and Self.Wait_Count have to be |
| -- synchronized. This is safe from deadlock because the activator is always |
| -- created before the activated task. That satisfies our |
| -- in-order-of-creation ATCB locking policy. |
| |
| procedure Activate_Tasks (Chain : Task_Id) is |
| Self_ID : constant Task_Id := STPO.Self; |
| C : Task_Id; |
| Activate_Prio : System.Any_Priority; |
| Success : Boolean; |
| |
| begin |
| pragma Assert (Self_ID = Environment_Task); |
| pragma Assert (Self_ID.Common.Wait_Count = 0); |
| |
| if Single_Lock then |
| Lock_RTS; |
| end if; |
| |
| -- Lock self, to prevent activated tasks from racing ahead before we |
| -- finish activating the chain. |
| |
| Write_Lock (Self_ID); |
| |
| -- Activate all the tasks in the chain. Creation of the thread of |
| -- control was deferred until activation. So create it now. |
| |
| C := Chain; |
| while C /= null loop |
| if C.Common.State /= Terminated then |
| pragma Assert (C.Common.State = Unactivated); |
| |
| Write_Lock (C); |
| |
| Activate_Prio := |
| (if C.Common.Base_Priority < Get_Priority (Self_ID) |
| then Get_Priority (Self_ID) |
| else C.Common.Base_Priority); |
| |
| STPO.Create_Task |
| (C, Task_Wrapper'Address, |
| Parameters.Size_Type |
| (C.Common.Compiler_Data.Pri_Stack_Info.Size), |
| Activate_Prio, Success); |
| |
| Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1; |
| |
| if Success then |
| C.Common.State := Runnable; |
| else |
| raise Program_Error; |
| end if; |
| |
| Unlock (C); |
| end if; |
| |
| C := C.Common.Activation_Link; |
| end loop; |
| |
| Self_ID.Common.State := Activator_Sleep; |
| |
| -- Wait for the activated tasks to complete activation. It is unsafe to |
| -- abort any of these tasks until the count goes to zero. |
| |
| loop |
| exit when Self_ID.Common.Wait_Count = 0; |
| Sleep (Self_ID, Activator_Sleep); |
| end loop; |
| |
| Self_ID.Common.State := Runnable; |
| Unlock (Self_ID); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| end Activate_Tasks; |
| |
| ------------------------------------ |
| -- Complete_Restricted_Activation -- |
| ------------------------------------ |
| |
| -- As in several other places, the locks of the activator and activated |
| -- task are both locked here. This follows our deadlock prevention lock |
| -- ordering policy, since the activated task must be created after the |
| -- activator. |
| |
| procedure Complete_Restricted_Activation is |
| Self_ID : constant Task_Id := STPO.Self; |
| Activator : constant Task_Id := Self_ID.Common.Activator; |
| |
| begin |
| if Single_Lock then |
| Lock_RTS; |
| end if; |
| |
| Write_Lock (Activator); |
| Write_Lock (Self_ID); |
| |
| -- Remove dangling reference to Activator, since a task may outlive its |
| -- activator. |
| |
| Self_ID.Common.Activator := null; |
| |
| -- Wake up the activator, if it is waiting for a chain of tasks to |
| -- activate, and we are the last in the chain to complete activation |
| |
| if Activator.Common.State = Activator_Sleep then |
| Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1; |
| |
| if Activator.Common.Wait_Count = 0 then |
| Wakeup (Activator, Activator_Sleep); |
| end if; |
| end if; |
| |
| Unlock (Self_ID); |
| Unlock (Activator); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| |
| -- After the activation, active priority should be the same as base |
| -- priority. We must unlock the Activator first, though, since it should |
| -- not wait if we have lower priority. |
| |
| if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then |
| Set_Priority (Self_ID, Self_ID.Common.Base_Priority); |
| end if; |
| end Complete_Restricted_Activation; |
| |
| ------------------------------ |
| -- Complete_Restricted_Task -- |
| ------------------------------ |
| |
| procedure Complete_Restricted_Task is |
| begin |
| STPO.Self.Common.State := Terminated; |
| end Complete_Restricted_Task; |
| |
| ---------------------------- |
| -- Create_Restricted_Task -- |
| ---------------------------- |
| |
| procedure Create_Restricted_Task |
| (Priority : Integer; |
| Stack_Address : System.Address; |
| Size : System.Parameters.Size_Type; |
| Task_Info : System.Task_Info.Task_Info_Type; |
| CPU : Integer; |
| State : Task_Procedure_Access; |
| Discriminants : System.Address; |
| Elaborated : Access_Boolean; |
| Task_Image : String; |
| Created_Task : Task_Id) |
| is |
| Self_ID : constant Task_Id := STPO.Self; |
| Base_Priority : System.Any_Priority; |
| Base_CPU : System.Multiprocessors.CPU_Range; |
| Success : Boolean; |
| Len : Integer; |
| |
| begin |
| -- Stack is not preallocated on this target, so that Stack_Address must |
| -- be null. |
| |
| pragma Assert (Stack_Address = Null_Address); |
| |
| Base_Priority := |
| (if Priority = Unspecified_Priority |
| then Self_ID.Common.Base_Priority |
| else System.Any_Priority (Priority)); |
| |
| -- Legal values of CPU are the special Unspecified_CPU value which is |
| -- inserted by the compiler for tasks without CPU aspect, and those in |
| -- the range of CPU_Range but no greater than Number_Of_CPUs. Otherwise |
| -- the task is defined to have failed, and it becomes a completed task |
| -- (RM D.16(14/3)). |
| |
| if CPU /= Unspecified_CPU |
| and then (CPU < Integer (System.Multiprocessors.CPU_Range'First) |
| or else CPU > Integer (System.Multiprocessors.Number_Of_CPUs)) |
| then |
| raise Tasking_Error with "CPU not in range"; |
| |
| -- Normal CPU affinity |
| else |
| -- When the application code says nothing about the task affinity |
| -- (task without CPU aspect) then the compiler inserts the |
| -- Unspecified_CPU value which indicates to the run-time library that |
| -- the task will activate and execute on the same processor as its |
| -- activating task if the activating task is assigned a processor |
| -- (RM D.16(14/3)). |
| |
| Base_CPU := |
| (if CPU = Unspecified_CPU |
| then Self_ID.Common.Base_CPU |
| else System.Multiprocessors.CPU_Range (CPU)); |
| end if; |
| |
| if Single_Lock then |
| Lock_RTS; |
| end if; |
| |
| Write_Lock (Self_ID); |
| |
| -- With no task hierarchy, the parent of all non-Environment tasks that |
| -- are created must be the Environment task. Dispatching domains are |
| -- not allowed in Ravenscar, so the dispatching domain parameter will |
| -- always be null. |
| |
| Initialize_ATCB |
| (Self_ID, State, Discriminants, Self_ID, Elaborated, Base_Priority, |
| Base_CPU, null, Task_Info, Size, Created_Task, Success); |
| |
| -- If we do our job right then there should never be any failures, which |
| -- was probably said about the Titanic; so just to be safe, let's retain |
| -- this code for now |
| |
| if not Success then |
| Unlock (Self_ID); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| |
| raise Program_Error; |
| end if; |
| |
| Created_Task.Entry_Calls (1).Self := Created_Task; |
| |
| Len := |
| Integer'Min (Created_Task.Common.Task_Image'Length, Task_Image'Length); |
| Created_Task.Common.Task_Image_Len := Len; |
| Created_Task.Common.Task_Image (1 .. Len) := |
| Task_Image (Task_Image'First .. Task_Image'First + Len - 1); |
| |
| Unlock (Self_ID); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| |
| -- Create TSD as early as possible in the creation of a task, since it |
| -- may be used by the operation of Ada code within the task. |
| |
| SSL.Create_TSD (Created_Task.Common.Compiler_Data); |
| end Create_Restricted_Task; |
| |
| procedure Create_Restricted_Task |
| (Priority : Integer; |
| Stack_Address : System.Address; |
| Size : System.Parameters.Size_Type; |
| Task_Info : System.Task_Info.Task_Info_Type; |
| CPU : Integer; |
| State : Task_Procedure_Access; |
| Discriminants : System.Address; |
| Elaborated : Access_Boolean; |
| Chain : in out Activation_Chain; |
| Task_Image : String; |
| Created_Task : Task_Id) |
| is |
| begin |
| if Partition_Elaboration_Policy = 'S' then |
| |
| -- A unit may have been compiled without partition elaboration |
| -- policy, and in this case the compiler will emit calls for the |
| -- default policy (concurrent). But if the partition policy is |
| -- sequential, activation must be deferred. |
| |
| Create_Restricted_Task_Sequential |
| (Priority, Stack_Address, Size, Task_Info, CPU, State, |
| Discriminants, Elaborated, Task_Image, Created_Task); |
| |
| else |
| Create_Restricted_Task |
| (Priority, Stack_Address, Size, Task_Info, CPU, State, |
| Discriminants, Elaborated, Task_Image, Created_Task); |
| |
| -- Append this task to the activation chain |
| |
| Created_Task.Common.Activation_Link := Chain.T_ID; |
| Chain.T_ID := Created_Task; |
| end if; |
| end Create_Restricted_Task; |
| |
| --------------------------------------- |
| -- Create_Restricted_Task_Sequential -- |
| --------------------------------------- |
| |
| procedure Create_Restricted_Task_Sequential |
| (Priority : Integer; |
| Stack_Address : System.Address; |
| Size : System.Parameters.Size_Type; |
| Task_Info : System.Task_Info.Task_Info_Type; |
| CPU : Integer; |
| State : Task_Procedure_Access; |
| Discriminants : System.Address; |
| Elaborated : Access_Boolean; |
| Task_Image : String; |
| Created_Task : Task_Id) is |
| begin |
| Create_Restricted_Task (Priority, Stack_Address, Size, Task_Info, |
| CPU, State, Discriminants, Elaborated, |
| Task_Image, Created_Task); |
| |
| -- Append this task to the activation chain |
| |
| Created_Task.Common.Activation_Link := Tasks_Activation_Chain; |
| Tasks_Activation_Chain := Created_Task; |
| end Create_Restricted_Task_Sequential; |
| |
| --------------------------- |
| -- Finalize_Global_Tasks -- |
| --------------------------- |
| |
| -- This is needed to support the compiler interface; it will only be called |
| -- by the Environment task. Instead, it will cause the Environment to block |
| -- forever, since none of the dependent tasks are expected to terminate |
| |
| procedure Finalize_Global_Tasks is |
| Self_ID : constant Task_Id := STPO.Self; |
| |
| begin |
| pragma Assert (Self_ID = STPO.Environment_Task); |
| |
| if Single_Lock then |
| Lock_RTS; |
| end if; |
| |
| -- Handle normal task termination by the environment task, but only for |
| -- the normal task termination. In the case of Abnormal and |
| -- Unhandled_Exception they must have been handled before, and the task |
| -- termination soft link must have been changed so the task termination |
| -- routine is not executed twice. |
| |
| -- Note that in the "normal" implementation in s-tassta.adb the task |
| -- termination procedure for the environment task should be executed |
| -- after termination of library-level tasks. However, this |
| -- implementation is to be used when the Ravenscar restrictions are in |
| -- effect, and AI-394 says that if there is a fall-back handler set for |
| -- the partition it should be called when the first task (including the |
| -- environment task) attempts to terminate. |
| |
| SSL.Task_Termination_Handler.all (Ada.Exceptions.Null_Occurrence); |
| |
| Write_Lock (Self_ID); |
| Sleep (Self_ID, Master_Completion_Sleep); |
| Unlock (Self_ID); |
| |
| if Single_Lock then |
| Unlock_RTS; |
| end if; |
| |
| -- Should never return from Master Completion Sleep |
| |
| raise Program_Error; |
| end Finalize_Global_Tasks; |
| |
| --------------------------- |
| -- Restricted_Terminated -- |
| --------------------------- |
| |
| function Restricted_Terminated (T : Task_Id) return Boolean is |
| begin |
| return T.Common.State = Terminated; |
| end Restricted_Terminated; |
| |
| -------------------- |
| -- Terminate_Task -- |
| -------------------- |
| |
| procedure Terminate_Task (Self_ID : Task_Id) is |
| begin |
| Self_ID.Common.State := Terminated; |
| end Terminate_Task; |
| |
| -------------- |
| -- Init_RTS -- |
| -------------- |
| |
| procedure Init_RTS is |
| begin |
| Tasking.Initialize; |
| |
| -- Initialize lock used to implement mutual exclusion between all tasks |
| |
| STPO.Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level); |
| |
| -- Notify that the tasking run time has been elaborated so that |
| -- the tasking version of the soft links can be used. |
| |
| SSL.Lock_Task := Task_Lock'Access; |
| SSL.Unlock_Task := Task_Unlock'Access; |
| SSL.Adafinal := Finalize_Global_Tasks'Access; |
| SSL.Get_Current_Excep := Get_Current_Excep'Access; |
| |
| -- Initialize the tasking soft links (if not done yet) that are common |
| -- to the full and the restricted run times. |
| |
| SSL.Tasking.Init_Tasking_Soft_Links; |
| end Init_RTS; |
| |
| begin |
| Init_RTS; |
| end System.Tasking.Restricted.Stages; |