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

Reply via email to