Accessing refence argument in fork join any block

Hello,
I have a following system verilog code


 timout_or_get_msg_size( input mailbox mbx, ref logic[9:0] msg_size, input int tmout_cnt);
    fork : timeout_block
	  begin
	    $display("here I am ");
	    mbx.get(msg_size);
		$display("msg_size is %d", msg_size);
	    @(posedge (msg_intf_inst.clkx8));
	  end
      begin
	    int tmp_cnt = tmout_cnt;
		while (tmp_cnt != 0) begin
	      tmp_cnt = tmp_cnt - 1;
		  @(posedge (msg_intf_inst.clkx8));
		end
		if (tmp_cnt == 0) begin
		  $display ("time out occurred in msg_size!!");
		  disable timeout_block;
		end
      end	  
	join_any
  endtask

It is giving following error :
xmvlog: *E,FJNRFA (design.sv,1202|36): Reference argument cannot be accessed inside fork-join_none or fork-join_any [SystemVerilog].
xrun: *E,VLGERR: An error occurred during parsing. Review the log file for errors with the code *E and fix those identified problems to proceed. Exiting with code (status 1).
TOOL: xrun 20.09-s003: Exiting on Apr 14, 2022 at 00:52:44 EDT (total: 00:00:00)

can someone help me to understand the issue and what is the work around for this. I am passing the msg_size by reference since it is passed to get method. I am not clear why reference argument cannot be accessed in for join any or none.

regards,
-sunil

In reply to puranik.sunil@tcs.com:

Please have a look at this thread Argument Passed by Reference cannot be used within fork-join_any/join_none - SystemVerilog - Verification Academy

Basically this a restriction, I wonder if you actually require msg_size to be ref** variable, but I’m not sure what is your requirement.

LRM Section 9.3.2 Parallel Blocks

…Within a fork-join_any or fork-join_none block, it shall be illegal to refer to formal arguments passed by reference other than in the initialization value expressions of variables declared in a block_item_declaration of the fork.

HTH,

-R

In reply to puranik.sunil@tcs.com:

You probably want to use output instead of ref. The value of msg_size will only be updated to the caller when the task returns.

task timout_or_get_msg_size( input mailbox mbx, output logic[9:0] msg_size, input int tmout_cnt);
    fork
	  begin
	    $display("here I am ");
	    mbx.get(msg_size);
		$display("msg_size is %d", msg_size);
	    @(posedge (msg_intf_inst.clkx8));
	  end
      begin
	    int tmp_cnt = tmout_cnt;
		while (tmp_cnt != 0) begin
	      tmp_cnt = tmp_cnt - 1;
		  @(posedge (msg_intf_inst.clkx8));
		end
		if (tmp_cnt == 0) begin
		  $display ("time out occurred in msg_size!!");
		end
      end	  
	join_any
     disable fork;
  endtask

This makes sure both processes terminate before the tasks returns. And the msg_size will be 0 if the timeout occurs.

Hi Dave,
thanks for the reply. I still have a question :
if we cannot access a reference argument inside a fork-join block since lifetime of any variable referenced inside a fork/join_none/join_any block has to exist throughout the life of the fork block. Now why does the same restriction not hold for a output argument. since output arguments are updated at the end of task, we need to still ensure that the variable passed as output argument needs to exist when the task returns. How does one ensure this.

also if we ensure that reference argument exists throughout the life of task, can we use reference argument also in fork join any?

thanks,
sunil

Hi,
I just need to update the value of msg_size. so I can pass it as an output also as Dave is suggesting.
thanks,
-sunil

In reply to puranik.sunil@tcs.com:

When using a non-ref argument, the lifetime of the actual argument (the identifier used when calling the task) and the lifetime of the formal argument (the local argument in the task declaration) are disconnected. A value gets copied when entering(input) or exiting(output) the task. The lifetime of the actual arguments just needs to be at least the duration of the call to the task.

But as soon as you add a fork/join_none, or join_any, the task caller has no idea whether the lifetime of the actual arguments need to be extended beyond the life of the task; not impossible, but extremely difficult to implement.

There is a proposal in the P1800-2023 LRM to add ref static to qualify that the actual argument must have a static lifetime to avoid this problem.