Skip to content

Commit 93aa395

Browse files
Eric BotcazouMarc Poulhiès
authored andcommitted
ada: Fix inconsistencies in conversion functions from Duration
The 3 units Ada.Calendar, GNAT.Calendar and GNAT.Sockets contain conversion functions from the Duration fixed-point type that implement the same idiom but with some inconsistencies: * GNAT.Sockets only handles Timeval_Duration, i.e. positive Duration, and is satisfactory, although a simpler implementation can be written, * GNAT.Calendar mishandles negative Duration values, as well as integral Duration values, * Ada.Calendar mishandles negative Duration values, and rounds nanoseconds instead of truncating them. gcc/ada/ChangeLog: * libgnat/a-calend.adb (To_Struct_Timespec_64): Deal with negative Duration values and truncate the nanoseconds too. * libgnat/g-calend.adb (timeval_to_duration): Unsuppress overflow checks. (duration_to_timeval): Likewise. Deal with negative Duration values as well as integral Duration values. * libgnat/g-socket.adb (To_Timeval): Simplify the implementation.
1 parent 1603eeb commit 93aa395

File tree

3 files changed

+42
-17
lines changed

3 files changed

+42
-17
lines changed

gcc/ada/libgnat/a-calend.adb

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,19 +1068,28 @@ is
10681068
tv_nsec : out Long_Integer)
10691069
is
10701070
pragma Unsuppress (Overflow_Check);
1071-
Secs : Duration;
1072-
Nano_Secs : Duration;
10731071

10741072
begin
1075-
-- Seconds extraction, avoid potential rounding errors
1076-
1077-
Secs := D - 0.5;
1078-
tv_sec := Long_Long_Integer (Secs);
1079-
1080-
-- Nanoseconds extraction
1073+
if D = 0.0 then
1074+
tv_sec := 0;
1075+
tv_nsec := 0;
1076+
1077+
elsif D < 0.0 then
1078+
tv_sec := Long_Long_Integer (D + 0.5);
1079+
if D = Duration (tv_sec) then
1080+
tv_nsec := 0;
1081+
else
1082+
tv_nsec := Long_Integer ((D - Duration (tv_sec)) * Nano + 0.5);
1083+
end if;
10811084

1082-
Nano_Secs := D - Duration (tv_sec);
1083-
tv_nsec := Long_Integer (Nano_Secs * Nano);
1085+
else
1086+
tv_sec := Long_Long_Integer (D - 0.5);
1087+
if D = Duration (tv_sec) then
1088+
tv_nsec := 0;
1089+
else
1090+
tv_nsec := Long_Integer ((D - Duration (tv_sec)) * Nano - 0.5);
1091+
end if;
1092+
end if;
10841093
end To_Struct_Timespec_64;
10851094

10861095
------------------

gcc/ada/libgnat/g-calend.adb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ package body GNAT.Calendar is
344344
sec : aliased C.Extensions.long_long;
345345
usec : aliased C.long;
346346

347+
pragma Unsuppress (Overflow_Check);
348+
347349
begin
348350
timeval_to_duration (T, sec'Access, usec'Access);
349351
pragma Annotate (CodePeer, Modified, sec);
@@ -369,13 +371,28 @@ package body GNAT.Calendar is
369371
sec : C.Extensions.long_long;
370372
usec : C.long;
371373

374+
pragma Unsuppress (Overflow_Check);
375+
372376
begin
373377
if D = 0.0 then
374378
sec := 0;
375379
usec := 0;
380+
381+
elsif D < 0.0 then
382+
sec := C.Extensions.long_long (D + 0.5);
383+
if D = Duration (sec) then
384+
usec := 0;
385+
else
386+
usec := C.long ((D - Duration (sec)) * Micro + 0.5);
387+
end if;
388+
376389
else
377-
sec := C.Extensions.long_long (D - 0.5);
378-
usec := C.long ((D - Duration (sec)) * Micro - 0.5);
390+
sec := C.Extensions.long_long (D - 0.5);
391+
if D = Duration (sec) then
392+
usec := 0;
393+
else
394+
usec := C.long ((D - Duration (sec)) * Micro - 0.5);
395+
end if;
379396
end if;
380397

381398
duration_to_timeval (sec, usec, Result'Access);

gcc/ada/libgnat/g-socket.adb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,12 +3059,11 @@ package body GNAT.Sockets is
30593059
-- Normal case where we do round down
30603060

30613061
else
3062-
S := time_t (Val - 0.5);
3063-
uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)) - 0.5);
3064-
3065-
if uS = -1 then
3066-
-- It happen on integer duration
3062+
S := time_t (Val - 0.5);
3063+
if Val = Timeval_Duration (S) then
30673064
uS := 0;
3065+
else
3066+
uS := suseconds_t ((Val - Timeval_Duration (S)) * 1_000_000 - 0.5);
30683067
end if;
30693068
end if;
30703069

0 commit comments

Comments
 (0)