Got it.
Starting with svn130, grt now contains a linked list of non-sensitized
processes in a timed wait. This chain can get corrupted, resulting in
either infinite loops within grt, or an internal error "process in
timeout".
A wait statement in a non-sensitized process is compiled into the
following sequence:
Ghdl_Process_Wait_Set_Timeout (set the timeout)
Ghdl_Process_Wait_Add_Sensitivity (add signal(s) to sensitivity list)
Ghdl_Process_Wait_Suspend (actual wait)
Ghdl_Process_Wait_Close (cleanup)
Ghdl_Process_Wait_Set_Timeout adds the process to the timeout chain
(using Update_Process_First_Timeout), and Ghdl_Process_Wait_Close
removes the process from the timeout chain again (using
Remove_Process_From_Timeout_Chain).
Now if the process just waits on signals without timeout, the call to
Ghdl_Process_Wait_Set_Timeout is omitted. But Ghdl_Process_Wait_Close
still needs to be called to clean up the sensitivity list.
Unfortunately, Ghdl_Process_Wait_Close unconditionally calls
Remove_Process_From_Timeout_Chain, and Remove_Process_From_Timeout_Chain
does not have any protection against removing a process that is not on
the timeout chain. It will silently corrupt the timeout chain.
t.vhd is a reproducer that illustrates the bug.
First, the timeout chain is set up like this:
P0->P1->P2
then P1 is removed from the timeout chain:
P0->P2
then P0 and P2 are reversed:
P2->P0
then P1 is removed a second time from the timeout chain:
P2->P0->P2
resulting in an infinite loop when traversing the timeout chain.
My proposed fix is in grt-processtimeoutchain.patch. Clearing the Prev
and Next pointers in Remove_Process_From_Timeout_Chain ensures that a
second call to Remove_Process_From_Timeout_Chain is harmless and won't
alter timeout chain. It is quite cheap also, because stores go into CPU
write buffers, and the constant zero is cheap as well.
grt-processtimeoutchain.patch:
--- gcc/vhdl/grt/grt-processes.adb.orig 2009-12-13 00:36:47.000000000 +0100
+++ gcc/vhdl/grt/grt-processes.adb 2009-12-13 00:37:24.000000000 +0100
@@ -312,6 +312,8 @@
Proc.Timeout_Chain_Next.Timeout_Chain_Prev :=
Proc.Timeout_Chain_Prev;
end if;
+ Proc.Timeout_Chain_Next := null;
+ Proc.Timeout_Chain_Prev := null;
end Remove_Process_From_Timeout_Chain;
procedure Ghdl_Process_Wait_Set_Timeout (Time : Std_Time)
t.vhd:
entity test is
end test;
architecture bug of test is
signal cnt : natural := 0;
begin
P0: process
begin
wait until cnt = 1;
wait until cnt = 6 for 1 sec;
wait until cnt = 10 for 1 sec;
wait;
end process P0;
P1: process
begin
wait until cnt = 2;
wait until cnt = 4 for 1 sec;
wait until cnt = 7;
wait until cnt = 10;
wait;
end process P1;
P2: process
begin
wait until cnt = 3;
wait until cnt = 5 for 1 sec;
wait until cnt = 10 for 1 sec;
wait;
end process P2;
stimulus_p: process
begin
loop
wait for 1 us;
exit when cnt = 10;
cnt <= cnt + 1;
end loop;
wait;
end process stimulus_p;
end bug;
_______________________________________________
Ghdl-discuss mailing list
[email protected]
https://mail.gna.org/listinfo/ghdl-discuss