blob: 70f8a9cac08f406f2b778536af35ce0b39137090 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT RUN-TIME COMPONENTS --
-- --
-- S Y S T E M . C _ T I M E --
-- --
-- B o d y --
-- --
-- Copyright (C) 2025, Free Software Foundation, Inc. --
-- --
-- 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/>. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies, Inc. --
-- --
------------------------------------------------------------------------------
package body System.C_Time is
-- Two Duration representations are described in targparm.ads:
-- Size Small Last = (2**(Size - 1) - 1) * Small
-- 32 0.02 42_949_672.94
-- 64 0.000_000_001 9_223_372_036.854_775_807
Recip : constant := (if Duration'Size = 32 then 50 else 1_000_000_000);
-- The reciprocal of the Small used to write "* Small" as "/ Recip"
Milli : constant := 1_000;
Micro : constant := 1_000_000;
Nano : constant := 1_000_000_000;
-- The standard divisors
pragma Unsuppress (Overflow_Check);
-- Overflow may occur during the various conversions
-------------------------
-- In_Timeval_Duration --
-------------------------
-- Immediate : constant Duration := 0.0;
-- Forever : constant Duration :=
-- Duration'Min (Duration'Last, 1.0 * OS_Constants.MAX_tv_sec);
-- subtype Timeval_Duration is Duration range Immediate .. Forever;
function In_Timeval_Duration (T : timeval) return Boolean is
Max_Dur : constant := 2**(Duration'Size - 1) - 1;
Max_Sec : constant := Max_Dur / Recip;
Max_Usec : constant := (Max_Dur mod Recip) * Micro / Recip;
-- When Duration'Size = 64 and time_t'Size = 32, the compiler
-- complains that Max_Sec does not fit in time_t, hence cannot
-- be compared with T.tv_sec.
Safe_Max_Sec : constant :=
(if Max_Sec > time_t'Last then time_t'Last else Max_Sec);
Safe_Max_Usec : constant :=
(if Max_Sec > time_t'Last then usec_t'Last else Max_Usec);
begin
pragma Warnings (Off, "condition is always");
return T.tv_sec >= 0
and then (T.tv_sec > 0 or else T.tv_usec >= 0)
and then T.tv_sec <= Safe_Max_Sec
and then (T.tv_sec < Safe_Max_Sec or else T.tv_usec <= Safe_Max_Usec)
and then T.tv_sec <= OS_Constants.MAX_tv_sec
and then (T.tv_sec < OS_Constants.MAX_tv_sec or else T.tv_usec = 0);
pragma Warnings (On, "condition is always");
end In_Timeval_Duration;
-----------------------------
-- Milliseconds_To_Timeval --
-----------------------------
function Milliseconds_To_Timeval (M : Interfaces.C.int) return timeval is
use Interfaces.C;
Q : constant int := M / Milli;
R : constant int := M rem Milli;
begin
return (tv_sec => time_t (Q), tv_usec => usec_t (R) * (Micro / Milli));
end Milliseconds_To_Timeval;
-----------------------------
-- Nanoseconds_To_Timespec --
-----------------------------
function Nanoseconds_To_Timespec (N : Interfaces.C.int) return timespec is
use Interfaces.C;
Q : constant int := N / Nano;
R : constant int := N rem Nano;
begin
return (tv_sec => time_t (Q), tv_nsec => nsec_t (R));
end Nanoseconds_To_Timespec;
-----------------
-- To_Duration --
-----------------
-- Duration (tv_usec) is OK even when Duration'Size = 32, see above
function To_Duration (T : timeval) return Duration is
begin
return Duration (T.tv_sec) + Duration (T.tv_usec) / Micro;
end To_Duration;
-- Duration (tv_nsec) overflows when Duration'Size = 32, see above.
-- Scale down nanoseconds by the value of the Small in nanoseconds.
function To_Duration (T : timespec) return Duration is
S : constant := Nano / Recip;
begin
return Duration (T.tv_sec) + Duration (T.tv_nsec / S) / (Nano / S);
end To_Duration;
-----------------
-- To_Timespec --
-----------------
function To_Timespec (T : timeval) return timespec is
begin
return (tv_sec => T.tv_sec, tv_nsec => nsec_t (T.tv_usec) * Milli);
end To_Timespec;
function To_Timespec (D : Duration) return timespec is
tv_sec : time_t;
tv_nsec : nsec_t;
begin
if D = 0.0 then
tv_sec := 0;
tv_nsec := 0;
elsif D < 0.0 then
tv_sec := time_t (D + 0.5);
if D = Duration (tv_sec) then
tv_nsec := 0;
else
tv_nsec := nsec_t ((D - Duration (tv_sec)) * Nano + 0.5);
end if;
else
tv_sec := time_t (D - 0.5);
if D = Duration (tv_sec) then
tv_nsec := 0;
else
tv_nsec := nsec_t ((D - Duration (tv_sec)) * Nano - 0.5);
end if;
end if;
return (tv_sec, tv_nsec);
end To_Timespec;
-----------------
-- To_Timeval --
-----------------
function To_Timeval (D : Duration) return timeval is
tv_sec : time_t;
tv_usec : usec_t;
begin
if D = 0.0 then
tv_sec := 0;
tv_usec := 0;
elsif D < 0.0 then
tv_sec := time_t (D + 0.5);
if D = Duration (tv_sec) then
tv_usec := 0;
else
tv_usec := usec_t ((D - Duration (tv_sec)) * Micro + 0.5);
end if;
else
tv_sec := time_t (D - 0.5);
if D = Duration (tv_sec) then
tv_usec := 0;
else
tv_usec := usec_t ((D - Duration (tv_sec)) * Micro - 0.5);
end if;
end if;
return (tv_sec, tv_usec);
end To_Timeval;
end System.C_Time;