----------------------------------------------------------------------- -- util-events-timers -- Timer list management -- Copyright (C) 2017 Stephane Carrez -- Written by Stephane Carrez (Stephane.Carrez@gmail.com) -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. ----------------------------------------------------------------------- with Ada.Real_Time; with Ada.Exceptions; private with Ada.Finalization; private with Util.Concurrent.Counters; -- == Timer Management == -- The Util.Events.Timers package provides a timer list that allows to have -- operations called on regular basis when a deadline has expired. It is very close to -- the Ada.Real_Time.Timing_Events package but it provides more flexibility -- by allowing to have several timer lists that run independently. Unlike the GNAT -- implementation, this timer list management does not use tasks at all. The timer list -- can therefore be used in a mono-task environment by the main process task. Furthermore -- you can control your own task priority by having your own task that uses the timer list. -- -- The timer list is created by an instance of Timer_List: -- -- Manager : Util.Events.Timers.Timer_List; -- -- The timer list is protected against concurrent accesses so that timing events can be -- setup by a task but the timer handler is executed by another task. -- -- === Timer Creation === -- A timer handler is defined by implementing the Timer interface with the -- Time_Handler procedure. A typical timer handler could be declared as follows: -- -- type Timeout is new Timer with null record; -- overriding procedure Time_Handler (T : in out Timeout); -- -- My_Timeout : aliased Timeout; -- -- The timer instance is represented by the Timer_Ref type that describes the handler -- to be called as well as the deadline time. The timer instance is initialized as follows: -- -- T : Util.Events.Timers.Timer_Ref; -- Manager.Set_Timer (T, My_Timeout'Access, Ada.Real_Time.Seconds (1)); -- -- === Timer Main Loop === -- Because the implementation does not impose any execution model, the timer management must -- be called regularly by some application's main loop. The Process procedure -- executes the timer handler that have elapsed and it returns the deadline to wait for the -- next timer to execute. -- -- Deadline : Ada.Real_Time.Time; -- loop -- ... -- Manager.Process (Deadline); -- delay until Deadline; -- end loop; -- package Util.Events.Timers is type Timer_Ref is tagged private; -- The timer interface that must be implemented by applications. type Timer is limited interface; type Timer_Access is access all Timer'Class; -- The timer handler executed when the timer deadline has passed. procedure Time_Handler (T : in out Timer; Event : in out Timer_Ref'Class) is abstract; -- Repeat the timer. procedure Repeat (Event : in out Timer_Ref; In_Time : in Ada.Real_Time.Time_Span); -- Cancel the timer. procedure Cancel (Event : in out Timer_Ref); -- Check if the timer is ready to be executed. function Is_Scheduled (Event : in Timer_Ref) return Boolean; -- Returns the deadline time for the timer execution. -- Returns Time'Last if the timer is not scheduled. function Time_Of_Event (Event : in Timer_Ref) return Ada.Real_Time.Time; type Timer_List is tagged limited private; -- Set a timer to be called at the given time. procedure Set_Timer (List : in out Timer_List; Handler : in Timer_Access; Event : in out Timer_Ref'Class; At_Time : in Ada.Real_Time.Time); -- Set a timer to be called after the given time span. procedure Set_Timer (List : in out Timer_List; Handler : in Timer_Access; Event : in out Timer_Ref'Class; In_Time : in Ada.Real_Time.Time_Span); -- Process the timer handlers that have passed the deadline and return the next -- deadline. The Max_Count parameter allows to limit the number of timer handlers -- that are called by operation. The default is not limited. procedure Process (List : in out Timer_List; Timeout : out Ada.Real_Time.Time; Max_Count : in Natural := Natural'Last); -- Procedure called when a timer handler raises an exception. -- The default operation reports an error in the logs. This procedure can be -- overridden to implement specific error handling. procedure Error (List : in out Timer_List; Handler : in Timer_Access; E : in Ada.Exceptions.Exception_Occurrence); private type Timer_Manager; type Timer_Manager_Access is access all Timer_Manager; type Timer_Node; type Timer_Node_Access is access all Timer_Node; type Timer_Ref is new Ada.Finalization.Controlled with record Value : Timer_Node_Access; end record; overriding procedure Adjust (Object : in out Timer_Ref); overriding procedure Finalize (Object : in out Timer_Ref); type Timer_Node is limited record Next : Timer_Node_Access; Prev : Timer_Node_Access; List : Timer_Manager_Access; Counter : Util.Concurrent.Counters.Counter := Util.Concurrent.Counters.ONE; Handler : Timer_Access; Deadline : Ada.Real_Time.Time; end record; protected type Timer_Manager is -- Add a timer. procedure Add (Timer : in Timer_Node_Access; Deadline : in Ada.Real_Time.Time); -- Cancel a timer. procedure Cancel (Timer : in out Timer_Node_Access); -- Find the next timer to be executed before the given time or return the next deadline. procedure Find_Next (Before : in Ada.Real_Time.Time; Deadline : out Ada.Real_Time.Time; Timer : in out Timer_Ref); private List : Timer_Node_Access; end Timer_Manager; type Timer_List is new Ada.Finalization.Limited_Controlled with record Manager : aliased Timer_Manager; end record; overriding procedure Finalize (Object : in out Timer_List); end Util.Events.Timers;