Wait for signal value in a task with timeout

Hi,
I would like to write a task that receives a signal by reference and waits for its posedge or negedge. If the signal is not set to the desired value within a specified timeout, an error message should be set.
I wrote something like this:

task automatic timeout(ref logic signal,input logic value,input time timeout_value);
      if(signal !== value) begin
           fork
               begin
                  #timeout_value;
                  `uvm_error(....
               end
               begin
                  if (signal !== signal_value)
                     @(signal === signal_value);
               end
           join_any
           disable fork;
endtask

This code does not compile because it violates Verilog LRM section 9.3.2(parallel blocks):it is illegal to refer to an argument passed by reference in fork - join_any block.
Do you have any suggestions? Maybe there is a solution for this in UVM? I could not find any.
Thanks

In reply to shaygueta:

Just fork the timeout delay.

task automatic timeout(ref logic signal,input logic value,input time timeout_value);
   bit timed_out;
           fork begin
              fork
                begin
                  #timeout_value;
                  `uvm_error(....
                  timed_out = '1;
                end
             join_none
             wait(signal === value || timed_out);
             disable fork;
           end join
endtask

Note the enclosing fork/join is needed to prevent the disable fork from killing other child threads that may have been spawned before calling this task.

In reply to dave_59:

Why add another bit “timed_out” instead of using join_any?

task automatic timeout(ref logic signal,input logic value,input time timeout_value);
           fork begin
              fork
                begin
                  #timeout_value;
                  `uvm_error(....
                end
                begin
                  wait(signal === value);
                end
             join_any
             disable fork;
           end join
endtask

In reply to Elisha K:

Because the reference to signal inside a fork/join_any or join_none is not legal.

In reply to dave_59:

In reply to shaygueta:
Just fork the timeout delay.

task automatic timeout(ref logic signal,input logic value,input time timeout_value);
bit timed_out;
fork begin
fork
begin
#timeout_value;
`uvm_error(....
timed_out = '1;
end
join_none
wait(signal === value || timed_out);
disable fork;
end join
endtask

Note the enclosing fork/join is needed to prevent the disable fork from killing other child threads that may have been spawned before calling this task.

HI Dave :
1 can I use disable {name of fork} instead of the guard fork/join here ? i.e
wait(signal === value || timed_out);
disable < name of fork process>; // assume there is name of fork/join_none
2. Do you recommend always use a guard fork/join when there is disable fork ? for example
in run_phase(uvm_phase phase);

Thanks

In reply to VE:

  1. Using
    disable name_of_fork
    has problems if there are multiple concurrent instances of the fork. Since you are allowed to use
    disable name_of_fork
    from anywhere, it has no way of knowing which instance you mean and it kills all instances.
  2. I do recommend using guard fork/join whenever there is disable fork as a good habit. But you can avoid it if you are sure no other processes would get disabled accidentally. All of the UVM phase tasks are forked as a separate process so there are no other child process that could get disabled accidentally.