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

⟦4b04d3698⟧ TextFile

    Length: 17174 (0x4316)
    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 Creation_And_Activation is

    pragma Suppress_All;

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

        -- For_Layer.all :=
        -- Layer'(Dependent_Task_List => (Next => null),
        For_Layer.Dependent_Task_List.Next := null;
        --        Master_Task => Current_Task,
        For_Layer.Master_Task := Current_Task;
        --        Layer_Link => Current_Task.Current_Layer,
        For_Layer.Layer_Link := Current_Task.Current_Layer;
        --        Non_Terminated => 0,
        For_Layer.Non_Terminated := 0;
        --        Non_Terminable => 0,
        For_Layer.Non_Terminable := 0;
        --        Coldness => Warm);
        For_Layer.Coldness := Warm;

        Current_Task.Current_Layer := For_Layer;

        -- if Safety_Check then
        --     Checking.Check_Layer (For_Layer, "Initialize_Master",
        --                           Current_Task => Current_Task);
        -- end if;

        Release_Lock;
    end Initialize_Master;


    function Create_Task (Activation_Group  : Group_Ref;
                          Master            : Layer_Id;
                          Start_Addr_Ref    : Address_Ref;
                          Entry_Count       : Entry_Number;
                          Stack_Space       : Integer;
                          At_Priority       : Integer;
                          Closure           : System_Address;
                          Instance_Variable : System_Address) return Task_Id is
        pragma Routine_Number (Runtime_Ids.Create_Task);

        -- ** allocate new Tcb before acquiring lock, since could raise
        -- ** Storage_Error:
        New_Task : Task_Id := Storage_Manager.New_Task_Control_Block;

        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;

        Default_Task_Priority : Priority renames Main_Priority;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Create_Task");
        -- end if;
        --
        -- if Safety_Check then
        --     if Master = null then
        --         Debugging.Put_Message ("*** ERROR - No master set up for task");
        --     end if;
        --
        --     if Activation_Group = null then
        --         Debugging.Put_Message
        --            ("*** ERROR - No activation group set up for task");
        --     end if;
        --
        --     Checking.Check_Layer (Master, "Create_Task",
        --                           Current_Task => Current_Task);
        -- end if;

        --New_Task.all :=
        --   Task_Control_Block'
        --      (Checksum => Checksum (New_Task),
        New_Task.Checksum := Checksum (New_Task);
        --       Exception_Id => Exceptions.No_Error,
        New_Task.Exception_Id := null;  -- := Exceptions.No_Error;
        --       Stack_Bounds => (Null_Address, max (Stack_Space, Default));
        New_Task.Stack_Bounds.First := To_Address (0);
        if Stack_Space = 0 then
            New_Task.Stack_Bounds.Size := Default_Task_Stack_Size;
        else
            New_Task.Stack_Bounds.Size := Stack_Space;
        end if;
        --       Action_State => Empty_Actions,
        New_Task.Action_State := (others => False);
        --       Suspension_State => Not_Activated,
        New_Task.Suspension_State := Not_Activated;
        --       Current_Priority => Set_Priority,
        if At_Priority in Priority then
            New_Task.Current_Priority := At_Priority;
        else
            New_Task.Current_Priority := Default_Task_Priority;
        end if;
        --       Partner_Priority => Priority'First,
        New_Task.Partner_Priority := Priority'First;
        --       Code_Start_Ref => Start_Addr_Ref,
        New_Task.Code_Start_Ref := Start_Addr_Ref;
        --       Current_Layer => null,
        New_Task.Current_Layer := null;
        --       Queues => Storage_Manager.New_Queues
        --                    (Entry_Count, Current_Task => Current_Task),
        --*** New_Task.Queues created below
        --       Master_Block => Master,
        New_Task.Master_Block := Master;
        --       Layer_Link => List'(Next => Master.Dependent_Task_List.Next),
        New_Task.Layer_Link.Next := Master.Dependent_Task_List.Next;
        --       Callers_Head => Empty_List,
        New_Task.Callers_Head.Next := null;
        --       Callers_Link =>
        --          List'(Next => Activation_Group.all), -- temporary use
        New_Task.Callers_Link.Next := Activation_Group.all;  -- temporary use
        --       Activations_In_Progress => Convert (Closure), -- temporary use
        New_Task.Activations_In_Progress := Convert (Closure); -- temporary use
        --       Spare
        New_Task.Spare_Word0 := 0;
        --       Process_Id => 0,
        New_Task.Process_Id := 0;
        --       Ipc_Buffer_List => null);
        New_Task.Ipc_Buffer_List   := null;
        New_Task.Parent_Tcb        := Current_Task;
        New_Task.Parent_Frame_Link := Process_Ops.Get_Fp;  
        New_Task.Instance_Variable := Instance_Variable;

        Master.Non_Terminated           := Master.Non_Terminated + 1;
        Master.Non_Terminable           := Master.Non_Terminable + 1;
        Master.Dependent_Task_List.Next := New_Task;

        Activation_Group.all := New_Task;

        -- *** New_Task.Queues := ...
        -- creating queues can raise Storage_Error, so cannot hold lock
        Release_Lock;

        New_Task.Queues := Storage_Manager.New_Queues
                              (Entry_Count, Current_Task => Current_Task);

        -- if Debug_Mode then
        --     Debugging.Put_Message ("");
        --     Debugging.Put_Message ("Task_Management.Create_Task result = ");
        --     Debugging.Put_Tcb (New_Task);
        --     Debugging.Put_Message ("");
        -- end if;

        return New_Task;
    end Create_Task;


    procedure Activate_Offspring (Activation_Group          : Group_Ref;
                                  Perform_Elaboration_Check : Boolean) is
        pragma Routine_Number (Runtime_Ids.Activate_Offspring);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;

        Next_Task      : Task_Id := Activation_Group.all;
        Next_Next_Task : Task_Id;

        Params : Fork_Parameters;
        Reply  : Reply_Kind;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Activate_Offspring");
        -- end if;

        Runtime_Exceptions.Check_For_Abnormality (Current_Task => Current_Task);

        if Perform_Elaboration_Check then
            while Next_Task /= null loop
                if Next_Task.Code_Start_Ref.all = To_Address (0) then
                    -- Terminate all unstarted tasks in the activation group
                    -- before raising Program_Error.  C93007A tests this.
                    Next_Task := Activation_Group.all;
                    while Next_Task /= null loop
                        if Next_Task.Suspension_State = Not_Activated then
                            Termination_And_Abortion.Forced_Termination
                               (Next_Task,
                                Term_Via_Abort => False,
                                Current_Task   => Current_Task);
                        end if;
                        Next_Task := Next_Task.Callers_Link.Next;
                    end loop;
                    Runtime_Exceptions.Raise_Program_Error;
                end if;
                -- 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;
            end loop;
            Next_Task := Activation_Group.all;
        end if;

        Current_Task.Activations_In_Progress := 0;  
        Params.Global_Base_Address           := Process_Ops.Global_Base_Address;
        Params.Code_Start                    := Task_Code_Start;

        while Next_Task /= null loop
            -- if Safety_Check then
            --     if (Next_Task.Suspension_State /= Not_Activated) and then
            --        ((Next_Task.Suspension_State /= Terminated) or else
            --         (not Next_Task.Action_State (Abnormal))) then
            --         --
            --         -- A task that is aborted before it is activated has its
            --         -- Suspension_State set to Terminated.
            --
            --         Runtime_Exceptions.Raise_Runtime_Error
            --            ("Activate_Offspring",
            --             "Activating an already-activated task",
            --             Err.Task_Activated_Twice,
            --             Current_Task => Current_Task);
            --     end if;
            -- end if;

            -- Until a task is activated, the Callers_Link field is
            -- used to store the link to the next member of the
            -- activation group. The Callers_Head field is set here
            -- to reference the activator.

            Next_Next_Task := Next_Task.Callers_Link.Next;

            if not Next_Task.Action_State (Abnormal) then

                Next_Task.Suspension_State := Not_Suspended;
                Next_Task.Callers_Head     := List'(Next => Current_Task);
                Params.New_Task_Id         := Next_Task;
                Params.Instance_Variable   := Next_Task.Instance_Variable;

                -- if Debug_Mode then
                --     Debugging.Put_Message
                --        ("In Activate_Offspring, about to call Os9_Ops.Fork");
                -- end if;

                declare
                    Next_Priority : Integer := Integer
                                                  (Next_Task.Current_Priority);
                    Stack_Size    : Integer := Next_Task.Stack_Bounds.Size;
                    Status        : Process_Ops.Status;

                    Minimum_Stack_Size : constant := 64;
                begin
                    if Next_Priority < Minimum_Os_Priority then
                        Next_Priority := Minimum_Os_Priority;
                    end if;

                    if Stack_Size < Minimum_Stack_Size then
                        Stack_Size := Minimum_Stack_Size;
                    end if;

                    Process_Ops.Fork (Params'Address, Fork_Parameters_Size,
                                      Next_Priority, Stack_Size, Status);

                    if Status = Process_Ops.E_Noram then
                        if Debug_Mode then
                            Debugging.Put_Message
                               ("In Activate_Offspring, Os9_Ops.Fork failed due to insufficient available memory");
                        end if;

                        -- Update TCB and layer state since task not activated
                        Next_Task.Suspension_State := Not_Activated;
                        Termination_And_Abortion.Forced_Termination
                           (The_Task       => Next_Task,
                            Term_Via_Abort => False,
                            Current_Task   => Current_Task);

                        -- Simulate effect of raising storage_error (sic)
                        -- during child's activation.
                        --
                        Current_Task.Action_State (Exception_Pending) := True;  
                        Current_Task.Exception_Id := Exceptions.Tasking_Error;
                    else
                        -- if Debug_Mode then
                        --     Debugging.Put_Message
                        --        ("In Activate_Offspring, after call to Os9_Ops.Fork");
                        -- end if;
                        --
                        -- if Safety_Check then
                        --     Checking.Check_Os9_Ops_Status
                        --        (Status, Err.Bad_Status_From_Fork,
                        --         Current_Task => Current_Task);
                        -- end if;

                        if Status /= Process_Ops.Success then
                            Debugging.Put_Message
                               ("Got bad status from fork " &
                                Process_Ops.Status'Image (Status));
                        end if;

                        Current_Task.Activations_In_Progress :=
                           Current_Task.Activations_In_Progress + 1;
                    end if;
                end;
            end if;

            Next_Task := Next_Next_Task;
        end loop;

        Activation_Group.all := null;

        -- It is desirable that all elements of the activation group
        -- be forked before any of them begin to execute user code.
        -- Otherwise there may be problems with a low priority parent
        -- forking a medium priority child before a high priority child;
        -- it would be possible for the medium priority child to starve the
        -- parent and thereby prevent its sibling from ever being forked.
        -- This is currently not a problem, because a task registers itself
        -- (which involves acquiring the task management serialization
        -- lock) before it begins to execute user code.

        if Current_Task.Activations_In_Progress > 0 then
            Message_Queue_Utilities.Await_Reply
               (Child_Activating, Reply, Current_Task => Current_Task);
            -- if Safety_Check then
            --     Checking.Check_Reply (Reply, Activation_Group_Activated,
            --                           Current_Task => Current_Task);
            -- end if;
        end if;

        Runtime_Exceptions.Check_For_Pending_Exception
           (Current_Task => Current_Task);

        Release_Lock;
    end Activate_Offspring;


    procedure Notify_Parent_Internal
                 (Tasking_Error_Found : Boolean; Current_Task : Task_Id) is
        pragma Routine_Number (Runtime_Ids.Internal);

        -- While a task is activating, the Callers_Head field is
        -- used to store the task_id of the parent (i.e. activator,
        -- as opposed to master) task.
        --
        Parent                 : Task_Id renames Current_Task.Callers_Head.Next;
        Parent_Tcb             : Task_Control_Block renames Parent.all;
        Parent_Offspring_Count : Integer
            renames Parent_Tcb.Activations_In_Progress;
    begin
        -- if Debug_Mode then
        --     Debugging.Put_Message ("Entered Notify_Parent");
        -- end if;

        if Tasking_Error_Found then
            Parent_Tcb.Action_State (Exception_Pending) := True;  
            Parent_Tcb.Exception_Id := Exceptions.Tasking_Error;
        end if;

        Parent_Offspring_Count := Parent_Offspring_Count - 1;

        if Parent_Offspring_Count = 0 then
            Message_Queue_Utilities.Send_Reply
               (Parent, Activation_Group_Activated,
                Current_Task => Current_Task);
        end if;

        -- if Safety_Check and then
        --    Current_Task.Action_State (Activation_Done) then
        --     Runtime_Exceptions.Raise_Runtime_Error
        --        ("Notify_Parent", "child has already notified parent",
        --         Err.Parent_Notified_Twice,
        --         Current_Task => Current_Task);
        -- end if;

        Current_Task.Action_State (Activation_Done) := True;

        Runtime_Exceptions.Check_For_Abnormality (Current_Task => Current_Task);
    end Notify_Parent_Internal;


    procedure Notify_Parent (Tasking_Error_Found : Boolean) is
        pragma Routine_Number (Runtime_Ids.Notify_Parent);
        Current_Task : constant Task_Id := Get_Current_Task_And_Acquire_Lock;
    begin
        Notify_Parent_Internal (Tasking_Error_Found,
                                Current_Task => Current_Task);
        Release_Lock;
    end Notify_Parent;

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