+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>
* exp_util.ads: Use preferred U.S. spelling of "honored".
Optname : Interfaces.C.int := -1) return Option_Type
is
use SOSC;
+ use type C.unsigned;
use type C.unsigned_char;
V8 : aliased Two_Ints;
V4 : aliased C.int;
+ U4 : aliased C.unsigned;
V1 : aliased C.unsigned_char;
VT : aliased Timeval;
Len : aliased C.int;
-- a DWORD.
if Target_OS = Windows then
- Len := V4'Size / 8;
- Add := V4'Address;
+ Len := U4'Size / 8;
+ Add := U4'Address;
else
Len := VT'Size / 8;
-- Timeout is in milliseconds, actual value is 500 ms +
-- returned value (unless it is 0).
- if V4 = 0 then
+ if U4 = 0 then
Opt.Timeout := 0.0;
else
- Opt.Timeout := Natural (V4) * 0.001 + 0.500;
+ Opt.Timeout := Duration (U4) / 1000 + 0.500;
end if;
else
Option : Option_Type)
is
use SOSC;
+ use type C.unsigned;
V8 : aliased Two_Ints;
V4 : aliased C.int;
+ U4 : aliased C.unsigned;
V1 : aliased C.unsigned_char;
VT : aliased Timeval;
Len : C.int;
-- the actual timeout is 500 ms + the given value (unless it
-- is 0).
- V4 := C.int (Option.Timeout / 0.001);
+ U4 := C.unsigned (Option.Timeout / 0.001);
- if V4 > 500 then
- V4 := V4 - 500;
+ if U4 > 500 then
+ U4 := U4 - 500;
- elsif V4 > 0 then
- V4 := 1;
+ elsif U4 > 0 then
+ U4 := 1;
end if;
- Len := V4'Size / 8;
- Add := V4'Address;
+ Len := U4'Size / 8;
+ Add := U4'Address;
else
VT := To_Timeval (Option.Timeout);
-----------------
function To_Duration (Val : Timeval) return Timeval_Duration is
- begin
- return Natural (Val.Tv_Sec) * 1.0 + Natural (Val.Tv_Usec) * 1.0E-6;
+ Max_D : constant Long_Long_Integer := Long_Long_Integer (Forever - 0.5);
+ 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;
-------------------
else
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;
return (S, uS);
Immediate : constant Duration := 0.0;
Forever : constant Duration :=
- Duration'Min (Duration'Last, 1.0 * SOSC.MAX_tv_sec);
- -- Largest possible Duration that is also a valid value for struct timeval
+ Duration'Min
+ (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;