Potential hang with nested fork

task run_phase();

  forever begin
    fork
      begin
        fork
          begin
            sample_thread();
          end
          begin
            check_thread();
          end
          begin
            reset_thread();
          end
        join_any
        disable fork;
        @(rst_n === 1);
      end
    join
  end
endtask : run_phase
task check_thread();

  fork
    begin: Main_check_thread

      fork
        begin: abc_exp
          forever begin

            wait(abc_expected == 1)
            `uvm_info(get_name(), $sformatf("abc_exp expected is 1, waiting for actual value"), UVM_LOW)

            fork
            begin: 20 cycle thread
              repeat (20) @(posedge clk);
              `uvm_error(get_name(), $sformatf(
                  "abc_exp fail with expected value = %0d, actual design value =%0d",
                  abc_exp_expected,
                  m_vif.abc_exp
                ));
            end: 20 cycle thread

            begin: actual value check
              wait(m_vif.abc_exp)
              `uvm_info(get_name(), $sformatf("abc_exp pass"), UVM_LOW)
            end: actual value check
      join_any
      disable fork;
    end
  end: abc_exp
join
end:Main_check_thread
endtask:check_thread

Hi, I have a doubt regarding the above code:

→ 20 cycle thread and actual value check thread are triggered parallely, as soon as one of them finishes, they come out of fork join_any and fork is disabled

→ But abc_exp thread is still running, and it should come out of fork join? Is that correct? Or do I need to use disable fork for abc_exp thread as well?

My expectation is as soon as 20 cycle thread or actual value check thread is done, the entire abc_exp thread should be finished. I am seeing a potential hang in my test due to the above code.

What could be wrong?

Note that within ‘Main_check_thread’ there is forever loop. So once either ‘thread 20 cycle thread’ or ‘actual value check’ finish, it goes back to next iteration of forever loop.
Hence you observe that it’s hanged
Add a break statement after the disable fork or simply remove the forever loop if your expectation is that thread ‘abc_exp’ should execute only once

// End of abc_exp
....
join_any
      disable fork;
      break ;  // Comes out of forever loop
    end
  end: abc_exp
join
end:Main_check_thread
endtask:check_thread

disable fork kills the active child thread(s) and not the parent thread from where it’s called.
In order to kill the parent thread as well it’s child thread(s) use process.kill();
This would be the 3rd possible solution.