DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ B T

⟦65fc156f1⟧ TextFile

    Length: 33612 (0x834c)
    Types: TextFile
    Names: »B«

Derivation

└─⟦afbc8121e⟧ Bits:30000532 8mm tape, Rational 1000, MC68020_OS2000 7_2_2
    └─ ⟦77aa8350c⟧ »DATA« 
        └─⟦f794ecd1d⟧ 
            └─⟦24d1ddd49⟧ 
                └─⟦this⟧ 

TextFile

--    The use of this system is subject to the software license terms and
--    conditions agreed upon between Rational and the Customer.
--
--                Copyright 1988 by Rational.
--
--                          RESTRICTED RIGHTS LEGEND
--
--    Use, duplication, or disclosure by the Government is subject to
--    restrictions as set forth in subdivision (b)(3)(ii) of the Rights in
--    Technical Data and Computer Software clause at 52.227-7013.
--
--
--                Rational
--                3320 Scott Boulevard
--                Santa Clara, California 95054-3197
--
--   PROPRIETARY AND CONFIDENTIAL INFORMATION OF RATIONAL;
--   USE OR COPYING WITHOUT EXPRESS WRITTEN AUTHORIZATION
--   IS STRICTLY PROHIBITED.  THIS MATERIAL IS PROTECTED AS
--   AN UNPUBLISHED WORK UNDER THE U.S. COPYRIGHT ACT OF
--   1976.  CREATED 1988.  ALL RIGHTS RESERVED.
--
--

separate (Task_Management)
package body Termination_And_Abortion is

    pragma Suppress_All;

    function "=" (X, Y : Tt.Wait_List_Link) return Boolean renames Tt."=";

    procedure Delete_Entry_Queues
                 (The_Task : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);

        Next_Caller : Task_Id;
        Message     : Entry_Call_Message;
        Status      : Mq.Stratus;
    begin
        if Debug_Mode then
            Debugging.Put_Message ("Entered Delete_Entry_Queues");
        end if;

        -- if Safety_Check then
        --     Checking.Check_Task (The_Task, "Delete_Entry_Queues",
        --                          Current_Task => Current_Task);
        -- end if;

        -- mark the task as non_callable
        The_Task.Action_State (Non_Callable) := True;

        if The_Task.Queues.Wait_List /= null then

            for I in First_Entry_Index ..
                        The_Task.Queues.Wait_List.List'Last loop
                declare
                    The_Wait_Item : Mq.Wait_Item
                        renames The_Task.Queues.Wait_List.List (I);
                    The_Queue     : Mq.Id renames The_Wait_Item.Wait_Queue;
                begin
                    -- Only evacuate if the current task.  PRS 9723630-0120-1
                    if The_Wait_Item.Ipc_Queue and The_Task = Current_Task then
                        Ipc.Evacuate_Queue
                           (The_Queue  => The_Queue,
                            Queue_Data => Message_Queue_Utilities.
                                             Get_Associated_Data
                                             (The_Queue, The_Task));
                    end if;

                    -- Only delete if necessary.
                    if (not The_Wait_Item.Ipc_Queue) or
                       (The_Task = Current_Task) then
                        Delete_A_Queue:
                            loop
                                Mq.Delete_If_Empty (The_Queue, Status);
                                if Status /= Mq.Q_Notemp then
                                    if Safety_Check then
                                        Checking.Check_Message_Queue_Status
                                           (Status,
                                            Err.Bad_Status_From_Delete_If_Empty,
                                            Current_Task => Current_Task);
                                    end if;

                                    -- The_Queue := Mq.Null_Id;
                                    The_Queue.Upper := 0;
                                    The_Queue.Lower := 0;
                                    exit Delete_A_Queue;
                                end if;

                                Cause_Tasking_Error:  
                                    loop
                                        Mq.Retrieve_If_Available
                                           (The_Queue, Message'Address,
                                            Entry_Call_Message_Size, Status);
                                        exit when Status = Mq.Q_Nomess;

                                        Message_Queue_Utilities.Cancel_Timer
                                           (Message.Timer_Id,
                                            Current_Task => Current_Task);
                                        Next_Caller := To_Task_Id
                                                          (Message.Caller);

                                        Next_Caller.Exception_Id :=
                                           Exceptions.Tasking_Error;
                                        Next_Caller.Action_State
                                           (Exception_Pending)   := True;

                                        Message_Queue_Utilities.Send_Reply
                                           (Next_Caller, Rendezvous_Done,
                                            Current_Task => Current_Task);
                                    end loop Cause_Tasking_Error;
                            end loop Delete_A_Queue;
                    end if;
                end;
            end loop;
        end if;
    end Delete_Entry_Queues;


    procedure Prepare_For_Aborted_Entry_Caller_Reply
                 (Abortee : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);

        -- There is a comment in Abort_Multiple_Tasks that explains all of this

        Aborted_While_Calling_Entry : Integer
            renames Current_Task.Activations_In_Progress;

        function Convert is new Unchecked_Conversion
                                   (System.Address, Group_Ref);
        Aborter_Id : Task_Id
            renames Convert (Abortee.Activations_In_Progress'Address).all;
    begin
        Aborted_While_Calling_Entry := Aborted_While_Calling_Entry + 1;

        Aborter_Id := Current_Task;
    end Prepare_For_Aborted_Entry_Caller_Reply;


    procedure Forced_Termination (The_Task       : Task_Id;
                                  Term_Via_Abort : Boolean;
                                  Current_Task   : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Forced_Termination, The_Task =" &
        --                            Integer'Image (The_Task.Os9_Process_Id));
        -- end if;

        if Safety_Check then
            Checking.Check_Task (The_Task, "Forced_Termination",
                                 Current_Task => Current_Task);
        end if;

        if The_Task.Action_State (Abnormal) or else
           The_Task.Suspension_State = Terminated then
            return;
        end if;

        if Term_Via_Abort then
            The_Task.Action_State (Abnormal) := True;

            -- mark task as non_callable and delete queues
            Delete_Entry_Queues (The_Task, Current_Task => Current_Task);
        end if;

        if The_Task.Suspension_State = Not_Activated then
            The_Task.Suspension_State := Terminated;
            The_Task.Action_State (Parent_Or_Child_Ok_Tcb_Reclamation) := True;
            The_Task.Master_Block.Non_Terminated :=
               The_Task.Master_Block.Non_Terminated - 1;
            The_Task.Master_Block.Non_Terminable :=
               The_Task.Master_Block.Non_Terminable - 1;
            if not Term_Via_Abort then
                Delete_Entry_Queues (The_Task, Current_Task => Current_Task);
            end if;

        elsif The_Task.Suspension_State = Calling_Entry or else
              The_Task.Suspension_State = Awaiting_Entry_Call or else
              The_Task.Suspension_State = Delaying or else
              The_Task.Suspension_State = Not_Suspended then

            -- A task that calls Collective_Termination will
            -- be in Not_Suspended state, but it still needs a reply;
            -- other non-suspended tasks do not get a reply.

            if (The_Task.Suspension_State /= Not_Suspended) or else
               ((The_Task = Current_Task) and then (not Term_Via_Abort)) then

                if Term_Via_Abort then

                    if The_Task.Suspension_State = Calling_Entry then
                        Prepare_For_Aborted_Entry_Caller_Reply
                           (Abortee => The_Task, Current_Task => Current_Task);
                    end if;

                    Message_Queue_Utilities.Send_Reply
                       (The_Task, Task_Aborted, Current_Task => Current_Task);
                else
                    Message_Queue_Utilities.Send_Reply
                       (The_Task, Termination_Selected,
                        Current_Task => Current_Task);
                end if;
            end if;
        end if;
    end Forced_Termination;


    procedure Collective_Termination
                 (For_Layer : Layer_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Next_Task  : Task_Id;
        Next_Layer : Layer_Id;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Collective_Termination");
        -- end if;

        -- Because Collective_Termination is recursive, and the runtime
        -- does not have stack_checks enabled, we verify here that the
        -- stack has not overflowed.  If it has, a fatal error is reported
        -- and the process terminates.  This will generally cause program
        -- deadlock, but the program cannot safely proceed, since there
        -- is insufficient stack to complete the termination sequence.

        Process_Ops.Verify_Stack;

        if For_Layer.Non_Terminated > 0 then
            Next_Task := For_Layer.Dependent_Task_List.Next;

            while Next_Task /= null loop
                if Next_Task.Suspension_State /= Terminated then
                    Next_Layer := Next_Task.Current_Layer;
                    while Next_Layer /= null loop
                        Collective_Termination (Next_Layer,
                                                Current_Task => Current_Task);
                        Next_Layer := Next_Layer.Layer_Link;
                    end loop;

                    Forced_Termination (Next_Task,
                                        Term_Via_Abort => False,
                                        Current_Task   => Current_Task);

                end if;
                Next_Task := Next_Task.Layer_Link.Next;
            end loop;
        end if;
    end Collective_Termination;


    procedure Wait_Until_Really_Dead
                 (Child : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Reply : Reply_Kind;
    begin  
        if not Child.Action_State (Parent_Or_Child_Ok_Tcb_Reclamation) then
            Child.Action_State (Parent_Or_Child_Ok_Tcb_Reclamation) := True;

            Message_Queue_Utilities.Await_Reply
               (Awaiting_Tcb_Reclamation_Ok, Reply,
                Current_Task => Current_Task);
            if Safety_Check then
                Checking.Check_Reply (Reply, Child_Tcb_Reclaimable,
                                      Current_Task => Current_Task);
            end if;
        end if;
    end Wait_Until_Really_Dead;

    procedure Do_Await_Dependents (Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Current_Layer  : Layer_Id := Current_Task.Current_Layer;
        Next_Dependent : Task_Id;
        Next_Next_Task : Task_Id;
        Reply          : Reply_Kind;
    begin
        if Current_Layer /= null then
            -- if Safety_Check then
            --     Checking.Check_Layer (Current_Layer, "Await_Dependents",
            --                           Current_Task => Current_Task);
            -- end if;

            if Current_Layer.Non_Terminable > 0 then
                Message_Queue_Utilities.Await_Reply
                   (Awaiting_Dependent_Termination, Reply,
                    Current_Task => Current_Task);
                if Safety_Check then
                    Checking.Check_Reply (Reply, Dependents_Terminated,
                                          Current_Task => Current_Task);
                end if;

            elsif Current_Layer.Non_Terminated > 0 then
                Collective_Termination (Current_Layer,
                                        Current_Task => Current_Task);
            end if;

            Next_Dependent := Current_Layer.Dependent_Task_List.Next;

            while Next_Dependent /= null loop
                if Safety_Check then
                    Checking.Check_Task (Next_Dependent, "Await_Dependents",
                                         Current_Task => Current_Task);
                end if;

                Next_Next_Task := Next_Dependent.Layer_Link.Next;

                Wait_Until_Really_Dead (Child        => Next_Dependent,
                                        Current_Task => Current_Task);


                Storage_Manager.Free_Queues (Next_Dependent.Queues,
                                             Current_Task => Current_Task);
                Storage_Manager.Free_Tcb (Next_Dependent);

                Next_Dependent := Next_Next_Task;
            end loop;

            Current_Task.Current_Layer := Current_Layer.Layer_Link;

            Runtime_Exceptions.Check_For_Abnormality
               (Current_Task => Current_Task);
            -- else
            --     if Debug_Mode then
            --         Debugging.Put_Message
            --            ("*** Warning: Await_Dependents called but Current_Layer is null");
            --     end if;
        end if;
    end Do_Await_Dependents;


    procedure Await_Dependents is
        pragma Routine_Number (Runtime_Ids.Await_Dependents);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
    begin
        if Debug_Mode then
            Debugging.Put_Message ("Entered Await_Dependents");
        end if;

        Do_Await_Dependents (Current_Task);

        Release_Lock;
    end Await_Dependents;


    procedure Make_Masters_Cold (The_Task : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Next_Layer : Layer_Id;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Make_Masters_Cold");
        -- end if;

        -- if Safety_Check then
        --     Checking.Check_Task (The_Task, "Make_Masters_Cold",
        --                          Current_Task => Current_Task);
        --     Checking.Check_Layer (The_Task.Master_Block, "Make_Masters_Cold",
        --                           Current_Task => Current_Task);
        -- end if;

        -- Because Make_Masters_Cold is recursive, and the runtime
        -- does not have stack_checks enabled, we verify here that the
        -- stack has not overflowed.  If it has, a fatal error is reported
        -- and the process terminates.  This will generally cause program
        -- deadlock, but the program cannot safely proceed, since there
        -- is insufficient stack to complete the termination sequence.

        Process_Ops.Verify_Stack;

        --

        declare
            Master_Layer : Layer_Id renames The_Task.Master_Block;
            Master_Task  : Task_Id  renames Master_Layer.Master_Task;
        begin
            if The_Task.Suspension_State = Terminated then
                -- if Safety_Check and then (Master_Layer.Non_Terminated = 0) then
                --     Runtime_Exceptions.Raise_Runtime_Error
                --        ("Make_Masters_Cold",
                --         "decrementing non_terminated count below zero",
                --         Err.Layer_State_Inconsistency,
                --         Current_Task => Current_Task);
                -- end if;
                Master_Layer.Non_Terminated := Master_Layer.Non_Terminated - 1;
            end if;
            -- if Safety_Check and then (Master_Layer.Non_Terminable = 0) then
            --     Runtime_Exceptions.Raise_Runtime_Error
            --        ("Make_Masters_Cold",
            --         "decrementing non_terminable count below zero",
            --         Err.Layer_State_Inconsistency,
            --         Current_Task => Current_Task);
            -- end if;
            Master_Layer.Non_Terminable := Master_Layer.Non_Terminable - 1;

            if Master_Layer.Non_Terminable > 0 then
                return;

            elsif Master_Task.Suspension_State =
                  Awaiting_Dependent_Termination and then
                  (The_Task.Master_Block = Master_Task.Current_Layer) then

                if Master_Layer.Non_Terminated > 0 then
                    Collective_Termination (Master_Layer,
                                            Current_Task => Current_Task);
                end if;

                Message_Queue_Utilities.Send_Reply
                   (Master_Task, Dependents_Terminated,
                    Current_Task => Current_Task);

            elsif Master_Layer.Coldness = Cool then
                Master_Layer.Coldness := Cold;
                Next_Layer            := Master_Layer.Layer_Link;
                while Next_Layer /= null loop
                    if Next_Layer.Non_Terminable <= 0 then
                        Next_Layer.Coldness := Cold;
                        Next_Layer          := Next_Layer.Layer_Link;
                    else
                        Next_Layer.Coldness := Cool;
                        exit;
                    end if;
                end loop;
                if Next_Layer = null then
                    Make_Masters_Cold (Master_Task,
                                       Current_Task => Current_Task);
                end if;
            end if;
        end;
    end Make_Masters_Cold;


    procedure Task_Completion is
        pragma Routine_Number (Runtime_Ids.Task_Completion);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
    begin
        if Debug_Mode then
            Debugging.Put_Message ("Entered Task_Completion");
        end if;

        if not Current_Task.Action_State (Abnormal) then
            -- If abnormal, then aborter has already deleted entry queues
            -- mark task as non_callable and delete entry queues
            Delete_Entry_Queues (The_Task     => Current_Task,
                                 Current_Task => Current_Task);
        end if;

        Do_Await_Dependents (Current_Task);

        Release_Lock;
    end Task_Completion;


    procedure Task_End is
        pragma Routine_Number (Runtime_Ids.Task_End);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
    begin
        if Debug_Mode then
            Debugging.Put_Message ("Entered Task_End");
        end if;

        if not Current_Task.Action_State (Activation_Done) then
            Creation_And_Activation.Notify_Parent_Internal
               (Tasking_Error_Found => (Current_Task.Exception_Id /= null),
                Current_Task        => Current_Task);
        end if;

        if not Current_Task.Action_State (Non_Callable) then
            -- If Non_Callable, then aborter has already deleted entry queues
            -- else mark task as non_callable and delete entry queues
            Delete_Entry_Queues (Current_Task, Current_Task => Current_Task);
        end if;

        -- if Safety_Check and then (Current_Task.Current_Layer /= null) then
        --     -- Tartan called Await_Dependents here instead
        --     -- of Raise_Runtime_Error.
        --
        --     Runtime_Exceptions.Raise_Runtime_Error
        --        ("Task_End", "Current layer is non-null",
        --         Err.Layer_State_Inconsistency,
        --         Current_Task => Current_Task);
        -- end if;

        Current_Task.Suspension_State := Terminated;

        if not Current_Task.Action_State (Selecting_Termination) then
            -- If terminating via a select-with-terminate-alternative, then
            -- already made masters cold.

            Make_Masters_Cold (Current_Task, Current_Task => Current_Task);
        end if;

        if Current_Task.Action_State (Parent_Or_Child_Ok_Tcb_Reclamation) then
            Message_Queue_Utilities.Send_Reply
               (Current_Task.Master_Block.Master_Task, Child_Tcb_Reclaimable,
                Current_Task => Current_Task);
        else
            Current_Task.Action_State (Parent_Or_Child_Ok_Tcb_Reclamation) :=
               True;  
        end if;

        -- if Debug_Mode then
        --     Debugging.Put_Message
        --        ("In Task_Management.Task_End, about to call OS9_Ops.Suicide");
        -- end if;

        Release_Lock;

        Process_Ops.Suicide;
        -- if Debug_Mode then
        --     Debugging.Put_Message ("*** ERROR - Task_End returning to caller");
        -- end if;
    end Task_End;


    procedure Terminate_Activation_Group
                 (First_In_Group : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Next_Task : Task_Id := First_In_Group;
    begin  
        if (First_In_Group /= null) and then
           (First_In_Group.Suspension_State = Not_Activated) then

            loop
                -- if Safety_Check and then
                --    (Next_Task.Suspension_State /= Not_Activated) then
                --
                --     Runtime_Exceptions.Raise_Runtime_Error
                --        ("Terminate_Activation_Group",
                --         "Group member has been activated",
                --         Err.Suspension_State_Inconsistency,
                --         Current_Task => Current_Task);
                -- end if;

                Forced_Termination (Next_Task,
                                    Term_Via_Abort => False,
                                    Current_Task   => Current_Task);

                -- Until a task is activated, the Callers_Link field is
                -- used to store the link to the next member of the
                -- activation group.
                --
                Next_Task := Next_Task.Callers_Link.Next;
                exit when Next_Task = null;
            end loop;
        end if;
    end Terminate_Activation_Group;


    procedure Terminate_Allocated_Offspring (Activation_Group : Group_Ref) is
        pragma Routine_Number (Runtime_Ids.Terminate_Allocated_Offspring);
        Current_Task   : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
        First_In_Group : Task_Id          := Activation_Group.all;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Terminate_Allocated_Offspring");
        -- end if;

        Activation_Group.all := null;
        Terminate_Activation_Group (First_In_Group => First_In_Group,
                                    Current_Task   => Current_Task);
        Release_Lock;
    end Terminate_Allocated_Offspring;


    procedure Terminate_Dependent_Offspring is
        pragma Routine_Number (Runtime_Ids.Terminate_Dependent_Offspring);
        Current_Task   : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
        First_In_Group : Task_Id          :=
           Current_Task.Current_Layer.Dependent_Task_List.Next;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Terminate_Dependent_Offspring");
        -- end if;

        while First_In_Group /= null loop
            if First_In_Group.Suspension_State = Not_Activated then
                Terminate_Activation_Group (First_In_Group => First_In_Group,  
                                            Current_Task   => Current_Task);  
            end if;

            First_In_Group := First_In_Group.Layer_Link.Next;
        end loop;
        Release_Lock;
    end Terminate_Dependent_Offspring;


    procedure Abortion (The_Task : Task_Id; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Next_Layer : Layer_Id;
        Next_Child : Task_Id;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Abortion");
        -- end if;
        --
        -- if Safety_Check then
        --     Checking.Check_Task (The_Task, "Abortion",
        --                          Current_Task => Current_Task);
        --     if The_Task.Current_Layer /= null then
        --         Checking.Check_Layer (The_Task.Current_Layer, "Abortion",
        --                               Current_Task => Current_Task);
        --     end if;
        -- end if;

        Next_Layer := The_Task.Current_Layer;

        while Next_Layer /= null loop
            Next_Child := Next_Layer.Dependent_Task_List.Next;

            while Next_Child /= null loop
                Abortion (Next_Child, Current_Task => Current_Task);
                Next_Child := Next_Child.Layer_Link.Next;
            end loop;

            Next_Layer := Next_Layer.Layer_Link;
        end loop;

        Forced_Termination (The_Task,
                            Term_Via_Abort => True,
                            Current_Task   => Current_Task);
    end Abortion;


    procedure Abort_Main_Program is
        pragma Routine_Number (Runtime_Ids.Internal);
        -- The call to abort the main program is made from
        -- serialization, so the lock is already held.
        Current_Task : constant Task_Id := Task_Map.Get_Current_Task_Id;
    begin
        Abort_Main_Program_Flag := False;

        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Abort_Main_Program");
        -- end if;

        Abortion (Root_Task_Ptr, Current_Task);

        -- do not release the lock
    end Abort_Main_Program;


    procedure Abort_Multiple_Tasks
                 (Task_Count : Positive; The_First_Task : Task_Id) is
        pragma Routine_Number
           (Runtime_Ids.Abort_Multiple_Tasks, Pop_Params => False);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;

        type Task_Array     is array (1 .. Task_Count) of Task_Id;
        type Task_Array_Ref is access Task_Array;
        for Task_Array_Ref'Storage_Size use 0;

        function Convert is new Unchecked_Conversion
                                   (System.Address, Task_Array_Ref);

        Abortees : Task_Array renames Convert (The_First_Task'Address).all;

        -- LRM 9.10(5) requires that if a task is blocked on an unaccepted
        -- entry call at the time that it is aborted, then it must be
        -- removed from the entry queue before the completion of the
        -- execution of the abort statement. To implement this, the
        -- Activations_In_Progress field of the TCB is flagrantly abused.
        -- In the case of the abortee, this field is used to store the
        -- Task_Id of the aborter; in the case of the aborter, this field
        -- is used to store the count of abortees that were in this state
        -- at the time of their abortion. If the count is non-zero, then
        -- the aborter blocks, awaiting a reply. The count is decremented by
        -- each of the "special" abortees after they have removed themselves
        -- from the appropriate entry queue; the abortee who decrements
        -- the count to zero sends a reply to unblock the aborter.

        Aborted_While_Calling_Entry : Integer
            renames Current_Task.Activations_In_Progress;
        Reply                       : Reply_Kind;
    begin
        -- if Debug_Mode then
        --     if Task_Count = 1 then
        --         Debugging.Put_Message ("Entered Abort_Task");
        --     else
        --         Debugging.Put_Message ("Entered Abort_Multiple_Tasks");
        --     end if;
        -- end if;

        Runtime_Exceptions.Check_For_Abnormality (Current_Task => Current_Task);

        Aborted_While_Calling_Entry := 0;

        for I in Abortees'Range loop
            if Safety_Check then
                Checking.Check_Task (Abortees (I), "Abort_Multiple_Tasks",
                                     Current_Task => Current_Task);
            end if;

            Abortion (Abortees (I), Current_Task => Current_Task);
        end loop;

        if Aborted_While_Calling_Entry /= 0 then
            Message_Queue_Utilities.Await_Reply
               (Awaiting_Abortee_Reply, Reply, Current_Task => Current_Task);

            if Safety_Check then
                Checking.Check_Reply (Reply, Abortion_Acknowledged,
                                      Current_Task => Current_Task);
                -- if Aborted_While_Calling_Entry /= 0 then
                --     Runtime_Exceptions.Raise_Runtime_Error
                --        ("Abort_Multiple_Tasks",
                --         "Aborter awakened with non-zero pending reply count: " &
                --            Integer'Image (Aborted_While_Calling_Entry),
                --         Err.Suspension_State_Inconsistency,
                --         Current_Task => Current_Task);
                -- end if;
            end if;
        end if;

        Runtime_Exceptions.Check_For_Abnormality (Current_Task => Current_Task);
        Release_Lock;
    end Abort_Multiple_Tasks;


    procedure Make_Eligible_For_Termination (Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Terminable : Boolean  := True;
        Next_Layer : Layer_Id := Current_Task.Current_Layer;
    begin
        -- if Safety_Check and then (Next_Layer /= null) then
        --     Checking.Check_Layer (Next_Layer, "Make_Eligible_For_Termination",
        --                           Current_Task => Current_Task);
        -- end if;

        while Terminable and then Next_Layer /= null loop
            if Next_Layer.Non_Terminable > 0 then
                Terminable          := False;
                Next_Layer.Coldness := Cool;
            else
                Next_Layer.Coldness := Cold;
                Next_Layer          := Next_Layer.Layer_Link;
            end if;
        end loop;

        if Terminable then
            Termination_And_Abortion.Make_Masters_Cold
               (Current_Task, Current_Task => Current_Task);
        end if;  
    end Make_Eligible_For_Termination;


    procedure Make_Ineligible_For_Termination (Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);
        Next_Master : Task_Id  := Current_Task;
        Next_Layer  : Layer_Id := Current_Task.Current_Layer;
    begin
        loop
            -- if Safety_Check and then (Next_Layer /= null) then
            --     Checking.Check_Layer (Next_Layer,
            --                           "Make_Ineligible_For_Termination",
            --                           Current_Task => Current_Task);
            -- end if;

            while Next_Layer /= null loop
                if Next_Layer.Coldness = Cold then
                    Next_Layer.Coldness := Warm;
                    Next_Layer          := Next_Layer.Layer_Link;

                elsif Next_Layer.Coldness = Cool then
                    Next_Layer.Coldness := Warm;
                    return;

                elsif Next_Layer.Coldness = Warm then
                    return;

                else -- root or illegal
                    Runtime_Exceptions.Raise_Runtime_Error
                       ("MIFT", "bad layer inner loop",
                        Err.Layer_State_Inconsistency,
                        Current_Task => Current_Task);
                end if;
            end loop;

            Next_Layer                := Next_Master.Master_Block;
            Next_Master               := Next_Layer.Master_Task;
            Next_Layer.Non_Terminable := Next_Layer.Non_Terminable + 1;

            if Next_Layer.Coldness = Cold then
                Next_Layer.Coldness := Cool;
                Next_Layer          := Next_Layer.Layer_Link;

            elsif Next_Layer.Coldness = Cool or else
                  Next_Layer.Coldness = Warm then
                return;

            else  -- Root
                Runtime_Exceptions.Raise_Runtime_Error
                   ("MIFT", "root layer outer loop",
                    Err.Layer_State_Inconsistency,
                    Current_Task => Current_Task);
            end if;
        end loop;
    end Make_Ineligible_For_Termination;


    function Check_Return_Task
                (The_Task : Task_Id; Ptr_Stack_Frame : System_Address)
                return Boolean is
        pragma Routine_Number (Runtime_Ids.Check_Return_Task);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
        Result       : Boolean;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Check_Return_Task");
        -- end if;
        --
        -- if Safety_Check then
        --     Checking.Check_Task (The_Task, "Check_Return_Task",
        --                          Current_Task => Current_Task);
        -- end if;

        -- Result := Addressing.Is_Contained
        --              (The_Task.Master_Block,
        --               Frame_Begin => Ptr_Stack_Frame,
        --               Frame_End   => Current_Task.Stack_Bounds.First);
        --
        declare
            Middle : System_Address := The_Task.Master_Block.all'Address;
        begin
            --return (Frame_End <= Middle) and then (Middle < Frame_Begin);
            Result := (Le (Current_Task.Stack_Bounds.First, Middle)) and then
                         (Lt (Middle, Ptr_Stack_Frame));
        end;

        Release_Lock;
        return Result;
    end Check_Return_Task;

end Termination_And_Abortion;
pragma Runtime_Unit (Unit_Number         => Runtime_Ids.Runtime_Compunit,
                     Elab_Routine_Number => Runtime_Ids.Internal);