Commit 6b6a0f02 by Dmitriy Anisimkov Committed by Pierre-Marie de Rodat

[Ada] GNAT.Sockets: fix timeout computations for sockets

2018-12-11  Dmitriy Anisimkov  <anisimko@adacore.com>

gcc/ada/

	* libgnat/g-socket.ads, libgnat/g-socket.adb: Fix duration
	computations to be compatible with the type for socket timeouts
	on Windows.

From-SVN: r266998
parent 371e21cf
2018-12-11 Dmitriy Anisimkov <anisimko@adacore.com>
* libgnat/g-socket.ads, libgnat/g-socket.adb: Fix duration
computations to be compatible with the type for socket timeouts
on Windows.
2018-12-11 Gary Dismukes <dismukes@adacore.com> 2018-12-11 Gary Dismukes <dismukes@adacore.com>
* exp_util.ads: Use preferred U.S. spelling of "honored". * exp_util.ads: Use preferred U.S. spelling of "honored".
......
...@@ -1154,10 +1154,12 @@ package body GNAT.Sockets is ...@@ -1154,10 +1154,12 @@ package body GNAT.Sockets is
Optname : Interfaces.C.int := -1) return Option_Type Optname : Interfaces.C.int := -1) return Option_Type
is is
use SOSC; use SOSC;
use type C.unsigned;
use type C.unsigned_char; use type C.unsigned_char;
V8 : aliased Two_Ints; V8 : aliased Two_Ints;
V4 : aliased C.int; V4 : aliased C.int;
U4 : aliased C.unsigned;
V1 : aliased C.unsigned_char; V1 : aliased C.unsigned_char;
VT : aliased Timeval; VT : aliased Timeval;
Len : aliased C.int; Len : aliased C.int;
...@@ -1207,8 +1209,8 @@ package body GNAT.Sockets is ...@@ -1207,8 +1209,8 @@ package body GNAT.Sockets is
-- a DWORD. -- a DWORD.
if Target_OS = Windows then if Target_OS = Windows then
Len := V4'Size / 8; Len := U4'Size / 8;
Add := V4'Address; Add := U4'Address;
else else
Len := VT'Size / 8; Len := VT'Size / 8;
...@@ -1286,10 +1288,10 @@ package body GNAT.Sockets is ...@@ -1286,10 +1288,10 @@ package body GNAT.Sockets is
-- Timeout is in milliseconds, actual value is 500 ms + -- Timeout is in milliseconds, actual value is 500 ms +
-- returned value (unless it is 0). -- returned value (unless it is 0).
if V4 = 0 then if U4 = 0 then
Opt.Timeout := 0.0; Opt.Timeout := 0.0;
else else
Opt.Timeout := Natural (V4) * 0.001 + 0.500; Opt.Timeout := Duration (U4) / 1000 + 0.500;
end if; end if;
else else
...@@ -2293,9 +2295,11 @@ package body GNAT.Sockets is ...@@ -2293,9 +2295,11 @@ package body GNAT.Sockets is
Option : Option_Type) Option : Option_Type)
is is
use SOSC; use SOSC;
use type C.unsigned;
V8 : aliased Two_Ints; V8 : aliased Two_Ints;
V4 : aliased C.int; V4 : aliased C.int;
U4 : aliased C.unsigned;
V1 : aliased C.unsigned_char; V1 : aliased C.unsigned_char;
VT : aliased Timeval; VT : aliased Timeval;
Len : C.int; Len : C.int;
...@@ -2376,17 +2380,17 @@ package body GNAT.Sockets is ...@@ -2376,17 +2380,17 @@ package body GNAT.Sockets is
-- the actual timeout is 500 ms + the given value (unless it -- the actual timeout is 500 ms + the given value (unless it
-- is 0). -- is 0).
V4 := C.int (Option.Timeout / 0.001); U4 := C.unsigned (Option.Timeout / 0.001);
if V4 > 500 then if U4 > 500 then
V4 := V4 - 500; U4 := U4 - 500;
elsif V4 > 0 then elsif U4 > 0 then
V4 := 1; U4 := 1;
end if; end if;
Len := V4'Size / 8; Len := U4'Size / 8;
Add := V4'Address; Add := U4'Address;
else else
VT := To_Timeval (Option.Timeout); VT := To_Timeval (Option.Timeout);
...@@ -2509,8 +2513,24 @@ package body GNAT.Sockets is ...@@ -2509,8 +2513,24 @@ package body GNAT.Sockets is
----------------- -----------------
function To_Duration (Val : Timeval) return Timeval_Duration is function To_Duration (Val : Timeval) return Timeval_Duration is
begin Max_D : constant Long_Long_Integer := Long_Long_Integer (Forever - 0.5);
return Natural (Val.Tv_Sec) * 1.0 + Natural (Val.Tv_Usec) * 1.0E-6; Tv_sec_64 : constant Boolean := SOSC.SIZEOF_tv_sec = 8;
-- Need to separate this condition into the constant declaration to
-- avoid GNAT warning about "always true" or "always false".
begin
if Tv_sec_64 then
-- Check for possible Duration overflow when Tv_Sec field is 64 bit
-- integer.
if Val.Tv_Sec > time_t (Max_D) or else
(Val.Tv_Sec = time_t (Max_D) and then
Val.Tv_Usec > suseconds_t ((Forever - Duration (Max_D)) * 1E6))
then
return Forever;
end if;
end if;
return Duration (Val.Tv_Sec) + Duration (Val.Tv_Usec) * 1.0E-6;
end To_Duration; end To_Duration;
------------------- -------------------
...@@ -2701,7 +2721,12 @@ package body GNAT.Sockets is ...@@ -2701,7 +2721,12 @@ package body GNAT.Sockets is
else else
S := time_t (Val - 0.5); S := time_t (Val - 0.5);
uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S))); uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)) - 0.5);
if uS = -1 then
-- It happen on integer duration
uS := 0;
end if;
end if; end if;
return (S, uS); return (S, uS);
......
...@@ -433,8 +433,13 @@ package GNAT.Sockets is ...@@ -433,8 +433,13 @@ package GNAT.Sockets is
Immediate : constant Duration := 0.0; Immediate : constant Duration := 0.0;
Forever : constant Duration := Forever : constant Duration :=
Duration'Min (Duration'Last, 1.0 * SOSC.MAX_tv_sec); Duration'Min
-- Largest possible Duration that is also a valid value for struct timeval (Duration'Last,
(if SOSC."=" (SOSC.Target_OS, SOSC.Windows)
then Duration (2 ** 32 / 1000)
else 1.0 * SOSC.MAX_tv_sec));
-- Largest possible Duration that is also a valid value for the OS type
-- used for socket timeout.
subtype Timeval_Duration is Duration range Immediate .. Forever; subtype Timeval_Duration is Duration range Immediate .. Forever;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment