A question about how to use disable fork_name

Hi, Dear,

Recently I run into a problem as :



task body();
  for (int i = 0; i < 8; i++) begin
    automatic link = i;
    if (p_sequencer.rx_cfg[i].enable == 1) fork
      // do something pre ...
      ....
      fork : data_send
        begin
          forever begin
            `uvm_do_with(data_seq, {slice == link;})
          end
        end

        begin
          `uvm_do_with(check_seq, {slice == link;})
        end
      join_any
      disable data_send;

      // do something post ...
      ....
    join_none
  end
endtask


I thought the disable data_send will only kill particular thread generated from every “i”, however I found that when first disable data_send; executed, all “data_send” threads (8 threads totally) were killed simultaneously, looks like the thread name “data_send” was shared for every thread, and disable data_send; is visible for them, kill them all …

Could you please help explain what’s going on here and gave me a solution for this issue ?

The disable <named_block> construct is very simple - just makes every <named_block> jump to the end of the block. It does not consider any threading. You probably want to use disable fork instead. That construct terminates all threads that are the children of the parent thread (the thread executing the disable fork)

There are a few other issues with your example code.

You probably want the code inside the fork/join_none wrapped in a begin/end block. Otherwise the statements after the "do something pre/post, the disable fork, and the fork/join_any will all execute in parallel threads.

There is never a need to use the automatic keyword inside a class. All variables have automatic lifetime by default.

Abruptly killing a thread running a sequence might result in a hang. See Sequences/Stopping | Verification Academy

In reply to dave_59:

Hi, Dave,

Thanks so much for your response, it helps a lot :) Two more questions :

  1. The reason I do not use disable fork is that I have some other threads on “do something pre” and “do something post” block, looks to me that disable fork will kill the thread in “do something pre” as well, but it is not my expectation, that is why I use disable data_send; instead. Any suggestion to handle this ?

  2. I am really curious about what you said “abruptly killing a thread running a sequence might result in a hang.” I didn’t get too much information from the link you pointed out, could you please elaborate more here ? I really want to know the potential risk for this code.

Thanks so much,

WangYang

In reply to caowangyang:

For Q1 Two things you can do. You can wrap the fork/join_any in a fork/begin/end/join to isolate the threads you want affected by disable.

task body();
  for (int i = 0; i < 8; i++) begin
    link = i;
    if (p_sequencer.rx_cfg[i].enable == 1) fork
      // do something pre ...
      ....
      fork begin : isolation_block
        fork : data_send
        begin
          forever begin
            `uvm_do_with(data_seq, {slice == link;})
          end
        end
 
        begin
          `uvm_do_with(check_seq, {slice == link;})
        end
      join_any
      disable fork; // only disables the threads that are children of isolation_block
      end : isolation_block join
 
      // do something post ...
      ....
    join_none
  end
endtask

or you could get a handle to the process you want to terminate. See 9.7 Fine-grain process control in the LRM

task body();
  process data_send;
  for (int i = 0; i < 8; i++) begin
    link = i;
    if (p_sequencer.rx_cfg[i].enable == 1) fork
      // do something pre ...
      ....
        fork
        begin
          data_send = process::self();
          forever begin
            `uvm_do_with(data_seq, {slice == link;})
          end
        end
 
        begin
          `uvm_do_with(check_seq, {slice == link;})
        end
      join_any
      data_send.kill();
      // do something post ...
      ....
    join_none
  end
endtask

For Q2, you just need to be aware that the driver might have to deal with a sequence being terminated in the middle of the protocol with the sequence. Most of the time, this is not a problem because the driver is only blocked waiting for get_next_item(), but more advanced scenarios, such has using blocking put() for the response could result in a hang. I would not worry about it untill you get to that point.

In reply to dave_59:

Got it, thanks for your response.