blob: 4597dc3b5a7407480589f4e2363eb2798795edc6 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
-- --
-- A D A . R E A L _ T I M E --
-- --
-- B o d y --
-- --
-- Copyright (C) 1991-1994, Florida State University --
-- Copyright (C) 1995-2014, AdaCore --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
-- GNARL was developed by the GNARL team at Florida State University. --
-- Extensive contributions were provided by Ada Core Technologies, Inc. --
-- --
------------------------------------------------------------------------------
with System.Tasking;
package body Ada.Real_Time is
---------
-- "*" --
---------
-- Note that Constraint_Error may be propagated
function "*" (Left : Time_Span; Right : Integer) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span (Duration (Left) * Right);
end "*";
function "*" (Left : Integer; Right : Time_Span) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span (Left * Duration (Right));
end "*";
---------
-- "+" --
---------
-- Note that Constraint_Error may be propagated
function "+" (Left : Time; Right : Time_Span) return Time is
pragma Unsuppress (Overflow_Check);
begin
return Time (Duration (Left) + Duration (Right));
end "+";
function "+" (Left : Time_Span; Right : Time) return Time is
pragma Unsuppress (Overflow_Check);
begin
return Time (Duration (Left) + Duration (Right));
end "+";
function "+" (Left, Right : Time_Span) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span (Duration (Left) + Duration (Right));
end "+";
---------
-- "-" --
---------
-- Note that Constraint_Error may be propagated
function "-" (Left : Time; Right : Time_Span) return Time is
pragma Unsuppress (Overflow_Check);
begin
return Time (Duration (Left) - Duration (Right));
end "-";
function "-" (Left, Right : Time) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span (Duration (Left) - Duration (Right));
end "-";
function "-" (Left, Right : Time_Span) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span (Duration (Left) - Duration (Right));
end "-";
function "-" (Right : Time_Span) return Time_Span is
pragma Unsuppress (Overflow_Check);
begin
return Time_Span_Zero - Right;
end "-";
---------
-- "/" --
---------
-- Note that Constraint_Error may be propagated
function "/" (Left, Right : Time_Span) return Integer is
pragma Unsuppress (Overflow_Check);
pragma Unsuppress (Division_Check);
begin
return Integer (Duration (Left) / Duration (Right));
end "/";
function "/" (Left : Time_Span; Right : Integer) return Time_Span is
pragma Unsuppress (Overflow_Check);
pragma Unsuppress (Division_Check);
begin
return Time_Span (Duration (Left) / Right);
end "/";
-----------
-- Clock --
-----------
function Clock return Time is
begin
return Time (System.Task_Primitives.Operations.Monotonic_Clock);
end Clock;
------------------
-- Microseconds --
------------------
function Microseconds (US : Integer) return Time_Span is
begin
return Time_Span_Unit * US * 1_000;
end Microseconds;
------------------
-- Milliseconds --
------------------
function Milliseconds (MS : Integer) return Time_Span is
begin
return Time_Span_Unit * MS * 1_000_000;
end Milliseconds;
-------------
-- Minutes --
-------------
function Minutes (M : Integer) return Time_Span is
begin
return Milliseconds (M) * Integer'(60_000);
end Minutes;
-----------------
-- Nanoseconds --
-----------------
function Nanoseconds (NS : Integer) return Time_Span is
begin
return Time_Span_Unit * NS;
end Nanoseconds;
-------------
-- Seconds --
-------------
function Seconds (S : Integer) return Time_Span is
begin
return Milliseconds (S) * Integer'(1000);
end Seconds;
-----------
-- Split --
-----------
procedure Split (T : Time; SC : out Seconds_Count; TS : out Time_Span) is
T_Val : Time;
begin
-- Special-case for Time_First, whose absolute value is anomalous,
-- courtesy of two's complement.
T_Val := (if T = Time_First then abs (Time_Last) else abs (T));
-- Extract the integer part of T, truncating towards zero
SC :=
(if T_Val < 0.5 then 0 else Seconds_Count (Time_Span'(T_Val - 0.5)));
if T < 0.0 then
SC := -SC;
end if;
-- If original time is negative, need to truncate towards negative
-- infinity, to make TS non-negative, as per ARM.
if Time (SC) > T then
SC := SC - 1;
end if;
TS := Time_Span (Duration (T) - Duration (SC));
end Split;
-------------
-- Time_Of --
-------------
function Time_Of (SC : Seconds_Count; TS : Time_Span) return Time is
begin
-- We want to return Time (SC) + TS. To avoid spurious overflows in
-- the intermediate result Time (SC) we take advantage of the different
-- signs in SC and TS (when that is the case).
-- If the signs of SC and TS are different then we avoid converting SC
-- to Time (as we do in the else part). The reason for that is that SC
-- converted to Time may overflow the range of Time, while the addition
-- of SC plus TS does not overflow (because of their different signs).
-- The approach is to add and remove the greatest value of time
-- (greatest absolute value) to both SC and TS. SC and TS have different
-- signs, so we add the positive constant to the negative value, and the
-- negative constant to the positive value, to prevent overflows.
if (SC > 0 and then TS < 0.0) or else (SC < 0 and then TS > 0.0) then
declare
Closest_Boundary : constant Seconds_Count :=
(if TS >= 0.0 then
Seconds_Count (Time_Span_Last - Time_Span (0.5))
else
Seconds_Count (Time_Span_First + Time_Span (0.5)));
-- Value representing the integer part of the Time_Span boundary
-- closest to TS (its number of seconds). Truncate towards zero
-- to be sure that transforming this value back into Time cannot
-- overflow (when SC is equal to 0). The sign of Closest_Boundary
-- is always different from the sign of SC, hence avoiding
-- overflow in the expression Time (SC + Closest_Boundary)
-- which is part of the return statement.
Dist_To_Boundary : constant Time_Span :=
TS - Time_Span (Closest_Boundary);
-- Distance between TS and Closest_Boundary expressed in Time_Span
-- Both operands in the substraction have the same sign, hence
-- avoiding overflow.
begin
-- Both operands in the inner addition have different signs,
-- hence avoiding overflow. The Time () conversion and the outer
-- addition can overflow only if SC + TC is not within Time'Range.
return Time (SC + Closest_Boundary) + Dist_To_Boundary;
end;
-- Both operands have the same sign, so we can convert SC into Time
-- right away; if this conversion overflows then the result of adding SC
-- and TS would overflow anyway (so we would just be detecting the
-- overflow a bit earlier).
else
return Time (SC) + TS;
end if;
end Time_Of;
-----------------
-- To_Duration --
-----------------
function To_Duration (TS : Time_Span) return Duration is
begin
return Duration (TS);
end To_Duration;
------------------
-- To_Time_Span --
------------------
function To_Time_Span (D : Duration) return Time_Span is
begin
-- Note regarding AI-00432 requiring range checking on this conversion.
-- In almost all versions of GNAT (and all to which this version of the
-- Ada.Real_Time package apply), the range of Time_Span and Duration are
-- the same, so there is no issue of overflow.
return Time_Span (D);
end To_Time_Span;
begin
-- Ensure that the tasking run time is initialized when using clock and/or
-- delay operations. The initialization routine has the required machinery
-- to prevent multiple calls to Initialize.
System.Tasking.Initialize;
end Ada.Real_Time;