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-tastim.adb < prev    next >
Text File  |  1996-09-28  |  11KB  |  381 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                     S Y S T E M . T A S K _ T I M E R                    --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.4 $                             --
  10. --                                                                          --
  11. --     Copyright (c) 1991,1992,1993,1994,1995 FSU, All Rights Reserved      --
  12. --                                                                          --
  13. -- GNARL is free software; you can redistribute it  and/or modify it  under --
  14. -- terms  of  the  GNU  Library General Public License  as published by the --
  15. -- Free Software  Foundation;  either version 2, or (at  your  option)  any --
  16. -- later  version.  GNARL is distributed  in the hope that  it will be use- --
  17. -- ful, but but WITHOUT ANY WARRANTY;  without even the implied warranty of --
  18. -- MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  19. -- eral Library Public License  for more details.  You should have received --
  20. -- a  copy of the GNU Library General Public License along with GNARL;  see --
  21. -- file COPYING.LIB.  If not,  write to the  Free Software Foundation,  675 --
  22. -- Mass Ave, Cambridge, MA 02139, USA.                                      --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with Ada.Calendar.Conv;
  27. --  Used for, Time_To_Stimespec
  28.  
  29. with System.Compiler_Exceptions;
  30. --  Used for, Current_Exception
  31.  
  32. with Ada.Real_Time.Conv;
  33. --  Used for, Time_Span_To_Stimespec
  34. --            Time_To_Stimespec
  35.  
  36. with System.Task_Primitives;
  37. --  Used for, Condition_Variable
  38. --            Lock, Unlock
  39. --            Write_Lock
  40. --            Cond_Signal
  41. --            Initialize_Lock
  42. --            Initialize_Cond
  43. --            Cond_Timed_wait
  44.  
  45. with System.Tasking.Utilities;
  46. --  Used for, Make_Independent
  47.  
  48. with System.Task_Clock;
  49.  
  50. with System.Task_Clock.Machine_Specifics;
  51. --  Used for, Machine_Specifics.Clock
  52. --             Stimespec_Ticks;
  53.  
  54. with System.Tasking.Protected_Objects;
  55.  
  56. with System.Tasking;
  57.  
  58. with Unchecked_Conversion;
  59.  
  60. with Unchecked_Deallocation;
  61.  
  62. package body System.Task_Timer is
  63.  
  64.    -------------------
  65.    -- Signal_Object --
  66.    -------------------
  67.  
  68.    use System.Tasking.Protected_Objects;
  69.    use System.Tasking;
  70.  
  71.    use System.Task_Clock;
  72.    --  Included use clause for operators
  73.  
  74.    function Clock return Stimespec
  75.      renames System.Task_Clock.Machine_Specifics.Clock;
  76.  
  77.    protected body Signal_Object is
  78.  
  79.       entry Wait when Open is
  80.       begin
  81.          Open := False;
  82.       end Wait;
  83.  
  84.       procedure Signal is
  85.       begin
  86.          Open := True;
  87.       end Signal;
  88.  
  89.    end Signal_Object;
  90.  
  91.    Timer_Condition :  Task_Primitives.Condition_Variable;
  92.    Timer_Lock      :  Task_Primitives.Lock;
  93.  
  94.    Stimespec_Day : constant Stimespec := System.Task_Clock.Time_Of (86400, 0);
  95.    Stimespec_Large : Stimespec := Clock + Stimespec_Day;
  96.    --  This value is used to make Timer.Server to sleep until some entry
  97.    --  comes into the timer queue.
  98.  
  99.    function To_Access is new
  100.      Unchecked_Conversion (System.Address, Protection_Access);
  101.  
  102.    Q_Head : Q_Link := null;
  103.  
  104.    -----------
  105.    -- Timer --
  106.    -----------
  107.  
  108.    protected body Timer is
  109.  
  110.       ------------------------
  111.       -- Timer.Time_nqueue --
  112.       ------------------------
  113.  
  114.       --  Allocate a queue element for the wakeup time T and put it in the
  115.       --  queue in wakeup time order. Return the allocated queue element
  116.       --  in N.
  117.  
  118.       procedure Time_Enqueue
  119.         (T : in System.Task_Clock.Stimespec;
  120.          D : access Delay_Block)
  121.       is
  122.          Q_Ptr : Q_Link := Q_Head;
  123.          Error : Boolean;
  124.          N     : Q_Link renames D;
  125.  
  126.       begin
  127.          N.T := T;
  128.  
  129.          --  If the new element becomes head of the queue, notify Timer Service
  130.  
  131.          if Q_Head = null then
  132.             N.Next := null;
  133.             N.Previous := null;
  134.             Q_Head := N;
  135.             Task_Primitives.Write_Lock (Timer_Lock, Error);
  136.             Task_Primitives.Cond_Signal (Timer_Condition);
  137.  
  138.             --  Signal the timer server to wake up
  139.  
  140.             Task_Primitives.Unlock (Timer_Lock);
  141.  
  142.          elsif N.T < Q_Head.T then
  143.             N.Next := Q_Head;
  144.             N.Previous := null;
  145.             Q_Head.Previous := N;
  146.             Q_Head := N;
  147.             Task_Primitives.Write_Lock (Timer_Lock, Error);
  148.             Task_Primitives.Cond_Signal (Timer_Condition);
  149.  
  150.             --  Signal the timer server to wake up
  151.  
  152.             Task_Primitives.Unlock (Timer_Lock);
  153.  
  154.          else
  155.             --  Place in the middle
  156.  
  157.             while Q_Ptr.Next /= null loop
  158.                if Q_Ptr.Next.T >= N.T then
  159.                   N.Next := Q_Ptr.Next;
  160.                   N.Previous := Q_Ptr;
  161.                   Q_Ptr.Next.Previous := N;
  162.                   Q_Ptr.Next := N;
  163.                   exit;
  164.                end if;
  165.  
  166.                Q_Ptr := Q_Ptr.Next;
  167.             end loop;
  168.  
  169.             if Q_Ptr.Next = null then
  170.  
  171.                --  Place at the end
  172.  
  173.                N.Next := null;
  174.                N.Previous := Q_Ptr;
  175.                Q_Ptr.Next := N;
  176.             end if;
  177.          end if;
  178.       end Time_Enqueue;
  179.  
  180.       -------------------
  181.       -- Timer.Service --
  182.       -------------------
  183.  
  184.       --  Service all of the wakeup requeues on the queue whose wakeup time
  185.       --  is less than the current time. Return the next wakeup time
  186.       --  after that (the wakeup time of the head of the queue if any;
  187.       --  a time far in the future if not).
  188.  
  189.       procedure Service (T : out System.Task_Clock.Stimespec) is
  190.          Q_Ptr : Q_Link := Q_Head;
  191.          W     : integer;
  192.       begin
  193.          while Q_Ptr /= null loop
  194.  
  195.             if Q_Ptr.T < Clock then
  196.  
  197.                --  Wake up the waiting task
  198.  
  199.                Q_Ptr.S_O.Signal;
  200.  
  201.                Dequeue (Q_Ptr);
  202.                --  Remove the entry
  203.  
  204.             end if;
  205.  
  206.             Q_Ptr := Q_Ptr.Next;
  207.          end loop;
  208.  
  209.          if Q_Head = null then
  210.             T := Stimespec_Large;
  211.          else
  212.             T := Q_Head.T;
  213.          end if;
  214.  
  215.       end Service;
  216.  
  217.       -------------
  218.       -- Dequeue --
  219.       -------------
  220.  
  221.       procedure Dequeue (D : access Delay_Block) is
  222.          Q_Ptr : Q_Link renames D;
  223.  
  224.       begin
  225.  
  226.          --  Case of head entry
  227.  
  228.          if Q_Head = Q_Ptr then
  229.             Q_Head := Q_Ptr.Next;
  230.             if Q_Head /= null then
  231.                Q_Head.Previous := null;
  232.             end if;
  233.  
  234.          --  Case of tail entry
  235.  
  236.          elsif Q_Ptr.Next = null then
  237.             if Q_Ptr.Previous /= null then
  238.                Q_Ptr.Previous := null;
  239.             end if;
  240.  
  241.          else
  242.             Q_Ptr.Previous.Next := Q_Ptr.Next;
  243.             Q_Ptr.Next.Previous := Q_Ptr.Previous;
  244.          end if;
  245.          Q_Ptr.Next := null;
  246.          Q_Ptr.Previous := null;
  247.       end Dequeue;
  248.  
  249.       -----------------
  250.       -- Timer.Empty --
  251.       -----------------
  252.  
  253.       function Empty return Boolean is
  254.       begin
  255.          return Q_Head = null;
  256.       end Empty;
  257.  
  258.       --  ??? The following entries used to all be called Enqueue; the
  259.       --      compiler does not seem to be able to handle overloading
  260.       --      in requeue statements.
  261.  
  262.       --  For the following Enqueue_XXX entries we add
  263.       --  Task_Clock.Machine_Specifics.Stimespec_Ticks to Time value before
  264.       --  queuing it onto the timer queue. This is need to guaranteed at
  265.       --  least the requested amount of waiting regradless of the Clock
  266.       --  granularity mismatch between the system's clock and the clock
  267.       --  used in Task_Clock.Machine_Specific.Clock.
  268.  
  269.       -----------------------
  270.       -- Enqueue_Time_Span --
  271.       -----------------------
  272.  
  273.       entry Enqueue_Time_Span
  274.         (T : in Ada.Real_Time.Time_Span;
  275.          D : access Delay_Block)
  276.       when True is
  277.          N : Q_Link renames D;
  278.  
  279.       begin
  280.          Time_Enqueue (Clock +
  281.             Ada.Real_Time.Conv.Time_Span_To_Stimespec (T) +
  282.               Task_Clock.Machine_Specifics.Stimespec_Ticks, D);
  283.          requeue N.S_O.Wait with abort;
  284.       end Enqueue_Time_Span;
  285.  
  286.       entry Enqueue_Duration
  287.          (T : in Duration;
  288.          D : access Delay_Block)
  289.       when True is
  290.          N : Q_Link renames D;
  291.  
  292.       begin
  293.          Time_Enqueue (Clock +
  294.            System.Task_Clock.Duration_To_Stimespec (T) +
  295.              Task_Clock.Machine_Specifics.Stimespec_Ticks, D);
  296.          requeue N.S_O.Wait with abort;
  297.       end Enqueue_Duration;
  298.  
  299.       entry Enqueue_Real_Time
  300.         (T : in Ada.Real_Time.Time;
  301.          D : access Delay_Block)
  302.       when True is
  303.          N : Q_Link renames D;
  304.  
  305.       begin
  306.          Time_Enqueue (Ada.Real_Time.Conv.Time_To_Stimespec (T) +
  307.            Task_Clock.Machine_Specifics.Stimespec_Ticks, D);
  308.          requeue N.S_O.Wait with abort;
  309.       end Enqueue_Real_Time;
  310.  
  311.       entry Enqueue_Calendar_Time
  312.         (T : in Ada.Calendar.Time;
  313.          D : access Delay_Block)
  314.       when True is
  315.          N : Q_Link renames D;
  316.  
  317.       begin
  318.          Time_Enqueue (Ada.Calendar.Conv.Time_To_Stimespec (T) +
  319.            Task_Clock.Machine_Specifics.Stimespec_Ticks, D);
  320.          requeue N.S_O.Wait with abort;
  321.       end Enqueue_Calendar_Time;
  322.  
  323.    end Timer;
  324.  
  325.    --------------
  326.    -- Finalize --
  327.    --------------
  328.  
  329.    procedure Finalize (Object : in out Delay_Block) is
  330.    begin
  331.       Timer.Dequeue (Object'Access);
  332.    end Finalize;
  333.  
  334.    -------------------
  335.    -- Timer_Service --
  336.    -------------------
  337.  
  338.    Next_Wakeup_Time : System.Task_Clock.Stimespec := Stimespec_Large;
  339.  
  340.    procedure Temp_Init;
  341.    procedure Temp_Wait;
  342.    --  These procedures contain processing that should be local to
  343.    --  Timer_Server---GNAT workaround. ???
  344.  
  345.    procedure Temp_Init is
  346.    begin
  347.       Tasking.Utilities.Make_Independent;
  348.       Task_Primitives.Initialize_Lock (System.Priority'Last, Timer_Lock);
  349.       Task_Primitives.Initialize_Cond (Timer_Condition);
  350.    end Temp_Init;
  351.    procedure Temp_Wait is
  352.       Result           : Boolean;
  353.       Error            : Boolean;
  354.    begin
  355.       Task_Primitives.Write_Lock (Timer_Lock, Error);
  356.       Task_Primitives.Cond_Timed_Wait
  357.         (Timer_Condition, Timer_Lock, Next_Wakeup_Time, Result);
  358.       Task_Primitives.Unlock (Timer_Lock);
  359.    end Temp_Wait;
  360.  
  361.    task Timer_Server is
  362.       pragma Priority (System.Priority'Last);
  363.    end Timer_Server;
  364.  
  365.    task body Timer_Server is
  366.    begin
  367.       Temp_Init;
  368.       loop
  369.          Temp_Wait;
  370.          if Timer.Empty and then Next_Wakeup_Time < Clock then
  371.          --  In the case where current time passes Stimespec_Large
  372.             Stimespec_Large := Stimespec_Large + Stimespec_Day;
  373.             Next_Wakeup_Time := Stimespec_Large;
  374.          else
  375.             Timer.Service (Next_Wakeup_Time);
  376.          end if;
  377.       end loop;
  378.    end Timer_Server;
  379.  
  380. end System.Task_Timer;
  381.