home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / s-os2~tp.adb < prev    next >
Text File  |  1996-09-28  |  17KB  |  610 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS                --
  4. --                                                                          --
  5. --                S Y S T E M . T A S K _ P R I M I T I V E S               --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                               (OS/2 Version)                             --
  9. --                                                                          --
  10. --                             $Revision: 1.8 $                             --
  11. --                                                                          --
  12. --          Copyright (c) 1993,1994,1995 NYU, All Rights Reserved           --
  13. --                                                                          --
  14. --  GNARL is free software; you can redistribute it and/or modify it  under --
  15. --  terms  of  the  GNU  Library General Public License as published by the --
  16. --  Free Software Foundation; either version 2,  or (at  your  option)  any --
  17. --  later  version.   GNARL is distributed in the hope that it will be use- --
  18. --  ful, but but WITHOUT ANY WARRANTY; without even the implied warranty of --
  19. --  MERCHANTABILITY  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  20. --  eral Library Public License for more details.  You should have received --
  21. --  a  copy of the GNU Library General Public License along with GNARL; see --
  22. --  file COPYING. If not, write to the Free Software Foundation,  675  Mass --
  23. --  Ave, Cambridge, MA 02139, USA.                                          --
  24. --                                                                          --
  25. ------------------------------------------------------------------------------
  26.  
  27. with System.Task_Clock.Machine_Specifics;
  28. with Interfaces.C.Strings;    use Interfaces.C.Strings;
  29. with System.Address_To_Access_Conversions;
  30. with System.OS2Lib;           use System.OS2Lib;
  31. with System.OS2Lib.Errors;    use System.OS2Lib.Errors;
  32. with System.Storage_Elements; use System.Storage_Elements;
  33. with System.Io;               use System.Io;
  34.  
  35. package body System.Task_Primitives is
  36.  
  37.    Offset : Storage_Offset;
  38.    --  Holds the offset from the base of a thread's stack to the TCB for the
  39.    --  thread. The assumption is that this is the same for all threads. See
  40.    --  description of Self function. Set by Booster.
  41.  
  42.    Thread_1_TCB_Ptr : TCB_Ptr;
  43.    --  Pointer to TCB of main task. We need this because we can't use the
  44.    --  normal self mechanism (with the "booster" trick) for the main task.
  45.    --  See Self procedure for more details.
  46.  
  47.    package Address_TCB_Ptr_Ptr_Conversion is
  48.      new Address_To_Access_Conversions (TCB_Ptr);
  49.  
  50.    package Address_TCB_Ptr_Conversion is
  51.       new Address_To_Access_Conversions (Task_Control_Block);
  52.  
  53.    package Address_Boolean_Conversion is
  54.      new Address_To_Access_Conversions (Boolean);
  55.  
  56.    -------------------------
  57.    -- Initialize_LL_Tasks --
  58.    -------------------------
  59.  
  60.    procedure Initialize_LL_Tasks (T : TCB_Ptr) is
  61.    begin
  62.       T.all := (LL_Entry_Point  => null,
  63.                 LL_Arg          => Null_Address,
  64.                 Thread          => 1,            --  By definition
  65.                 Active_Priority => Default_Priority,
  66.                 Aborted         => False);
  67.  
  68.       Thread_1_TCB_Ptr := T;
  69.    end Initialize_LL_Tasks;
  70.  
  71.    ----------
  72.    -- Self --
  73.    ----------
  74.  
  75.    --  When a task is created, the body of the (OS/2) thread is the
  76.    --  procedure Booster, which in turn calls the actual task body.
  77.    --  Booster has a local variable where the TCB pointer is stored.
  78.  
  79.    --  The assumption is that the offset from the base of the thread's
  80.    --  stack to this variable is always the same; this offset is stored
  81.    --  in the global variable Offset by Booster itself.
  82.  
  83.    --  Therefore, we retrieve the stack pointer as the location at Offset
  84.    --  from the thread's stack base.
  85.  
  86.    --  Note: This does not work for Thread 1, since this one is not created
  87.    --  using the Booster trick. Thread 1 TCB addr is in Thread_1_TCB_Ptr.
  88.  
  89.    function Self return TCB_Ptr is
  90.       use Address_TCB_Ptr_Ptr_Conversion;
  91.  
  92.       Process_Info : aliased PPIB;
  93.       Thread_Info  : aliased PTIB;
  94.  
  95.    begin
  96.       Must_Not_Fail
  97.         (DosGetInfoBlocks (Thread_Info'Access, Process_Info'Access));
  98.  
  99.       if Thread_Info.tib_ptib2.tib2_ultid = 1 then
  100.          return Thread_1_TCB_Ptr;
  101.       else
  102.          return To_Pointer (Thread_Info.tib_pstack + Offset).all;
  103.       end if;
  104.    end Self;
  105.  
  106.    -------------
  107.    -- Booster --
  108.    -------------
  109.  
  110.    procedure Booster (Info : PVOID);
  111.    --  See description above for Self function
  112.  
  113.    procedure Booster (Info : PVOID) is
  114.  
  115.       use Address_TCB_Ptr_Conversion;
  116.  
  117.       My_TCB_Ptr : TCB_Ptr;
  118.  
  119.    begin
  120.       My_TCB_Ptr := To_Pointer (Info).all'Access;
  121.  
  122.       declare
  123.          Process_Info : aliased PPIB;
  124.          Thread_Info  : aliased PTIB;
  125.  
  126.       begin
  127.          if DosGetInfoBlocks (Thread_Info'Access, Process_Info'Access)
  128.                                          = NO_ERROR
  129.          then
  130.             Offset := My_TCB_Ptr'Address - Thread_Info.tib_pstack;
  131.          else
  132.             raise Storage_error;
  133.          end if;
  134.       end;
  135.  
  136.       --  Here we go!
  137.  
  138.       My_TCB_Ptr.LL_Entry_Point (My_TCB_Ptr.LL_Arg);
  139.  
  140.    end Booster;
  141.  
  142.    --------------------
  143.    -- Create_LL_Task --
  144.    --------------------
  145.  
  146.    procedure Create_LL_Task
  147.      (Priority       : Priority;
  148.       Stack_Size     : Task_Storage_Size;
  149.       LL_Entry_Point : LL_Task_Procedure_Access;
  150.       Arg            : Address;
  151.       T              : TCB_Ptr)
  152.    is
  153.       use Interfaces.C;
  154.       use Address_TCB_Ptr_Conversion;
  155.  
  156.       Result : OS2Lib.APIRET;
  157.       Id     : aliased TID;
  158.       Junk1  : PVOID; -- TBSL ???
  159.       Junk2  : ULONG; -- TBSL ???
  160.  
  161.    begin
  162.       --  Step 1: Create the thread in blocked mode
  163.  
  164.       Junk1  := Address_TCB_Ptr_Conversion.To_Address (T.all'Access);
  165.       Junk2  := ULONG (Stack_Size);
  166.       Result := DosCreateThread
  167.                    (F_ptid   => Id'Unchecked_Access,
  168.                     pfn      => LL_Task_Procedure_Access'(Booster'Access),
  169.                     param    => Junk1,
  170.                     flag     => 1, -- Block_child + No_commit_stack,
  171.                     cbStack  => Junk2);
  172.       if Result /= NO_ERROR then
  173.          raise Storage_error;
  174.       end if;
  175.  
  176.       --  Step 2: set its TCB
  177.  
  178.       T.all := (LL_Entry_Point => LL_Entry_Point,
  179.                 LL_Arg          => Arg,
  180.                 Thread          => Id,
  181.                 Active_Priority => Priority,
  182.                 Aborted         => False);
  183.  
  184.       --  Step 3: set its priority (child has inherited priority from parent)
  185.  
  186.       Must_Not_Fail
  187.         (DosSetPriority (Scope   => PRTYS_THREAD,
  188.                          Class   => PRTYC_NOCHANGE,
  189.                          Delta_P => long (Priority - Get_Own_Priority),
  190.                          PorTid  => Id));
  191.  
  192.       --  Step 4: Now, start it for good:
  193.  
  194.       Must_Not_Fail (DosResumeThread (Id));
  195.  
  196.    end Create_LL_Task;
  197.  
  198.    ------------------
  199.    -- Exit_LL_Task --
  200.    ------------------
  201.  
  202.    procedure Exit_LL_Task is
  203.    begin
  204.       DosExit (EXIT_THREAD, 0);
  205.    end Exit_LL_Task;
  206.  
  207.    ---------------------
  208.    -- Initialize_Lock --
  209.    ---------------------
  210.  
  211.    procedure Initialize_Lock (Prio : Integer; L : in out Lock) is
  212.    begin
  213.       if DosCreateMutexSem (Null_Ptr, L.Mutex'Unchecked_Access, 0, False32)
  214.                                             /= NO_ERROR
  215.       then
  216.          raise Storage_Error;
  217.       end if;
  218.  
  219.       L.Priority := Prio;
  220.    end Initialize_Lock;
  221.  
  222.    -------------------
  223.    -- Finalize_Lock --
  224.    -------------------
  225.  
  226.    procedure Finalize_Lock (L : in out Lock) is
  227.    begin
  228.       Must_Not_Fail (DosCloseMutexSem (L.Mutex));
  229.    end Finalize_Lock;
  230.  
  231.    ----------------
  232.    -- Write_Lock --
  233.    ----------------
  234.  
  235.    procedure Write_Lock (L : in out Lock; Ceiling_Violation : out Boolean) is
  236.    begin
  237.       L.Owner_Priority := Get_Own_Priority;
  238.  
  239.       if L.Priority < L.Owner_Priority then
  240.          Ceiling_Violation := True;
  241.          return;
  242.       end if;
  243.  
  244.       Must_Not_Fail (DosRequestMutexSem (L.Mutex, SEM_INDEFINITE_WAIT));
  245.  
  246.       Ceiling_Violation := False;
  247.  
  248.       if L.Priority > L.Owner_Priority then
  249.          Set_Own_Priority (L.Priority);
  250.       end if;
  251.    end Write_Lock;
  252.  
  253.    ---------------
  254.    -- Read_Lock --
  255.    ---------------
  256.  
  257.    --  Not worth worrying about distinguishing read and write locks until
  258.    --  OS/2 supports multi-processing, since no advantage would be gained.
  259.  
  260.    procedure Read_Lock (L : in out Lock; Ceiling_Violation : out Boolean)
  261.       renames Write_Lock;
  262.  
  263.    ------------
  264.    -- Unlock --
  265.    ------------
  266.  
  267.    procedure Unlock (L : in out Lock) is
  268.    begin
  269.       if L.Owner_Priority /= L.Priority then
  270.          Set_Own_Priority (L.Owner_Priority);
  271.       end if;
  272.  
  273.       Must_Not_Fail (DosReleaseMutexSem (L.Mutex));
  274.    end Unlock;
  275.  
  276.    -----------------------
  277.    -- Initalialize_Cond --
  278.    -----------------------
  279.  
  280.    procedure Initialize_Cond (Cond : in out Condition_Variable) is
  281.       Temporary : aliased HEV;
  282.       --  This temporary is needed for two reasons:
  283.       --  1) Since DosCreateSem operates on an PHEV, not HEV, it is not
  284.       --     derived and thus not available on type Condition_variable.
  285.       --  2) Moreover we cannot have an aliased view of Cond, required
  286.       --     for 'Access.
  287.  
  288.    begin
  289.       Must_Not_Fail
  290.         (DosCreateEventSem (Null_Ptr, Temporary'Unchecked_Access, 0, True32));
  291.       Cond := Condition_Variable (Temporary);
  292.    end Initialize_Cond;
  293.  
  294.    -------------------
  295.    -- Finalize_Cond --
  296.    -------------------
  297.  
  298.    --  No such problem here, DosCloseEventSem has been derived.
  299.    --  What does such refer to in above comment???
  300.  
  301.    procedure Finalize_Cond (Cond : in out Condition_Variable) is
  302.    begin
  303.       Must_Not_Fail (DosCloseEventSem (Cond));
  304.    end Finalize_Cond;
  305.  
  306.    ---------------
  307.    -- Cond_Wait --
  308.    ---------------
  309.  
  310.    --  Pre-assertion: Cond is posted
  311.    --                 L is locked.
  312.  
  313.    --  Post-assertion: Cond is posted
  314.    --                  L is locked.
  315.  
  316.    procedure Cond_Wait
  317.      (Cond : in out Condition_Variable;
  318.       L    : in out Lock)
  319.    is
  320.       Count : aliased ULONG; -- Unused
  321.       Error : Boolean;
  322.    begin
  323.       --  Must reset Cond BEFORE L is unlocked.
  324.  
  325.       Must_Not_Fail (DosResetEventSem (Cond, Count'Unchecked_Access));
  326.       Unlock (L);
  327.  
  328.       --  No problem if we are interrupted here: if the condition is signaled,
  329.       --  DosWaitEventSem will simply not block
  330.  
  331.       Must_Not_Fail (DosWaitEventSem (Cond, SEM_INDEFINITE_WAIT));
  332.  
  333.       --  Since L was previously accquired, Error cannot be false:
  334.  
  335.       Write_Lock (L, Error);
  336.    end Cond_Wait;
  337.  
  338.    ---------------------
  339.    -- Cond_Timed_Wait --
  340.    ---------------------
  341.  
  342.    --  Pre-assertion: Cond is posted
  343.    --                 L is locked.
  344.  
  345.    --  Post-assertion: Cond is posted
  346.    --                  L is locked.
  347.  
  348.    procedure Cond_Timed_Wait
  349.      (Cond      : in out Condition_Variable;
  350.       L         : in out Lock;
  351.       Abs_Time  : System.Task_Clock.Stimespec;
  352.       Timed_Out : out Boolean)
  353.    is
  354.       use System.Task_Clock;
  355.       use System.Task_Clock.Machine_Specifics;
  356.  
  357.       Count    : aliased ULONG; -- Unused
  358.       Time_Out : ULONG;
  359.       Error    : Boolean;
  360.       Rel_Time : Stimespec;
  361.  
  362.    begin
  363.       --  Change Abs_time to a relative delay.
  364.  
  365.       --  Be careful not to reintroduce the race condition that gave birth
  366.       --  to delay until.
  367.  
  368.       Must_Not_Fail (DosEnterCritSec);
  369.       Rel_Time := Abs_Time - Clock;
  370.       Must_Not_Fail (DosExitCritSec);
  371.  
  372.       --  Must reset Cond BEFORE L is unlocked.
  373.  
  374.       Must_Not_Fail (DosResetEventSem (Cond, Count'Unchecked_Access));
  375.       Unlock (L);
  376.  
  377.       --  No problem if we are interrupted here: if the condition is signaled,
  378.       --  DosWaitEventSem will simply not block
  379.  
  380.       if Rel_Time <= Stimespec_Zero then
  381.          Timed_Out := True;
  382.       else
  383.          Time_Out := ULONG (Stimespec_Seconds  (Rel_Time)) * 1000 +
  384.                      ULONG (Stimespec_NSeconds (Rel_Time) / 1E6);
  385.          Timed_Out :=  DosWaitEventSem (Cond, Time_Out) = ERROR_TIMEOUT;
  386.       end if;
  387.  
  388.       --  Since L was previously accquired, Error cannot be false
  389.  
  390.       Write_Lock (L, Error);
  391.  
  392.       --  Ensure post-condition
  393.  
  394.       if Timed_Out then
  395.          Must_Not_Fail (DosPostEventSem (Cond));
  396.       end if;
  397.    end Cond_Timed_Wait;
  398.  
  399.    -----------------
  400.    -- Cond_Signal --
  401.    -----------------
  402.  
  403.    procedure Cond_Signal (Cond : in out Condition_Variable) is
  404.    begin
  405.       Must_Not_Fail (DosPostEventSem (Cond));
  406.    end Cond_Signal;
  407.  
  408.    ------------------
  409.    -- Set_Priority --
  410.    ------------------
  411.  
  412.    --  Note: Currently, we have only 32 priorities, all in Regular Class.
  413.    --  Priority level 31 is the only value for Interrupt_Priority. (see
  414.    --  package System). A better choice (for OS/2) would be to have 32
  415.    --  priorities in Regular class for subtype Priority and 32 priorities
  416.    --  in Time-critical class for Interrupt_Priority ???
  417.  
  418.    procedure Set_Priority (T : TCB_Ptr; Prio : Integer) is
  419.       use Interfaces.C;
  420.  
  421.    begin
  422.       Must_Not_Fail
  423.         (DosSetPriority (Scope   => PRTYS_THREAD,
  424.                          Class   => PRTYC_NOCHANGE,
  425.                          Delta_P => long (Prio - T.Active_Priority),
  426.                          PorTid  => T.Thread));
  427.       T.Active_Priority := Prio;
  428.    end Set_Priority;
  429.  
  430.    ----------------------
  431.    -- Set_Own_Priority --
  432.    ----------------------
  433.  
  434.    procedure Set_Own_Priority (Prio : Integer) is
  435.    begin
  436.       Set_Priority (Self, Prio);
  437.    end Set_Own_Priority;
  438.  
  439.    ------------------
  440.    -- Get_Priority --
  441.    ------------------
  442.  
  443.    function Get_Priority (T : TCB_Ptr) return Integer is
  444.    begin
  445.       return T.Active_Priority;
  446.    end Get_Priority;
  447.  
  448.    ----------------------
  449.    -- Get_Own_Priority --
  450.    ----------------------
  451.  
  452.    function Get_Own_Priority return Integer is
  453.    begin
  454.       return Get_Priority (Self);
  455.    end Get_Own_Priority;
  456.  
  457.    ----------------
  458.    -- Abort_Task --
  459.    ----------------
  460.  
  461.    procedure Abort_Task (T : TCB_Ptr) is
  462.    begin
  463.       T.Aborted := True;
  464.    end Abort_Task;
  465.  
  466.    ----------------
  467.    -- Test_Abort --
  468.    ----------------
  469.  
  470.    Current_Abort_Handler : Abort_Handler_Pointer;
  471.  
  472.    procedure Test_Abort is
  473.    begin
  474.       if Self.Aborted then
  475.          Current_Abort_Handler (0);   -- Parameter not used
  476.       end if;
  477.    end Test_Abort;
  478.  
  479.    ---------------------------
  480.    -- Install_Abort_Handler --
  481.    ---------------------------
  482.  
  483.    procedure Install_Abort_Handler (Handler : Abort_Handler_Pointer) is
  484.    begin
  485.       Current_Abort_Handler := Handler;
  486.    end Install_Abort_Handler;
  487.  
  488.    ---------------------------
  489.    -- Install_Error_Handler --
  490.    ---------------------------
  491.  
  492.    procedure Install_Error_Handler (Handler : Address) is
  493.    begin
  494.       null;
  495.    end Install_Error_Handler;
  496.  
  497.    -----------------
  498.    -- Signal_Task --
  499.    -----------------
  500.  
  501.    procedure Signal_Task (T : TCB_Ptr; I : Interrupt_ID) is
  502.    begin
  503.       raise Program_Error;
  504.    end Signal_Task;
  505.  
  506.    ---------------------
  507.    -- Wait_For_Signal --
  508.    ---------------------
  509.  
  510.    procedure Wait_for_Signal (I : Interrupt_ID) is
  511.    begin
  512.       raise PROGRAM_ERROR;
  513.    end Wait_for_Signal;
  514.  
  515.    ---------------------
  516.    -- Reserved_Signal --
  517.    ---------------------
  518.  
  519.    function Reserved_Signal (I : Interrupt_ID) return Boolean is
  520.    begin
  521.       return False;
  522.    end Reserved_Signal;
  523.  
  524.    ------------------
  525.    -- Test_And_Set --
  526.    ------------------
  527.  
  528.    Test_And_Set_Mutex : Lock;
  529.    --  Lock used by Test_And_Set procedure
  530.  
  531.    -------------------------
  532.    -- Initialize_TAS_Cell --
  533.    -------------------------
  534.  
  535.    procedure Initialize_TAS_Cell (Cell : out TAS_Cell) is
  536.    begin
  537.       Cell.Value := False;
  538.    end Initialize_TAS_Cell;
  539.  
  540.    -----------------------
  541.    -- Finalize_TAS_Cell --
  542.    -----------------------
  543.  
  544.    procedure Finalize_TAS_Cell   (Cell : in out TAS_Cell) is
  545.    begin
  546.       null;
  547.    end Finalize_TAS_Cell;
  548.  
  549.    -----------
  550.    -- Clear --
  551.    -----------
  552.  
  553.    --  This was not atomic with respect to another Test_and_Set in the
  554.    --  original code.  Need it be???
  555.  
  556.    procedure Clear (Cell : in out TAS_Cell) is
  557.    begin
  558.       Cell.Value := False;
  559.    end Clear;
  560.  
  561.    ------------
  562.    -- Is_Set --
  563.    ------------
  564.  
  565.    --  This was not atomic with respect to another Test_and_Set in the
  566.    --  original code.  Need it be???
  567.  
  568.    function Is_Set (Cell : in TAS_Cell) return Boolean is
  569.    begin
  570.       return Cell.Value;
  571.    end Is_Set;
  572.  
  573.    ------------------
  574.    -- Test_And_Set --
  575.    ------------------
  576.  
  577.    procedure Test_And_Set (Cell : in out TAS_Cell; Result : out Boolean) is
  578.       Error : Boolean;
  579.    begin
  580.       Write_Lock (Test_And_Set_Mutex, Error);
  581.  
  582.       if Cell.Value then
  583.          Result := False;
  584.       else
  585.          Result :=  True;
  586.          Cell.Value := True;
  587.       end if;
  588.  
  589.       Unlock (Test_And_Set_Mutex);
  590.    end Test_And_Set;
  591.  
  592.    ---------------
  593.    -- LL_Assert --
  594.    ---------------
  595.  
  596.    procedure LL_Assert (B : Boolean; M : String) is
  597.    begin
  598.       if not B then
  599.          Put ("Failed assertion: ");
  600.          Put (M);
  601.          Put ('.');
  602.          New_Line;
  603.          pragma Assert (False);
  604.       end if;
  605.    end LL_Assert;
  606.  
  607. begin
  608.    Initialize_Lock (System.Priority'Last, Test_And_Set_Mutex);
  609. end System.Task_Primitives;
  610.