Scope of disable fork

I have a sequence . Inside the body -
task body
fork

… 10 threads
join_none

fork

join
disable fork;

endtask

What will be the scope of this disable fork . I ran this sequence in main phase (controlled through uvm_object_wrapper as default sequence in main phase). Is it the top initial block which runs the test case, or the main phase (it will disable all threads that are invoked in main phase of different components)

In reply to ashish_banga:

Scope, like the code within a task or begin/end block, has no effect on the functionality of disable/wait fork. See https://verificationacademy.com/forums/systemverilog/confusion-fork-join-…-disable-fork#reply-38941

However, when you call the start() method of a sequence, the code inside start task looks like

task start();
 ...
   fork
     begin
      ...
      pre_body();
      ...
      body();
      ...
      post_body();
      ...
     end
   join
 ...
endtask

So executing a disable fork inside the body() task will potentially kill the processes created by the pre_body() and body() tasks. It cannot affect any process created outside the fork within the start method.

The same is true for all the run_phase() tasks. There are all fork’ed into independent processes.

In reply to dave_59:

Thanks for clarification Dave.
As going by last line , all the main_phase tasks in different components of testbench are forked independently of each other ? So, disable fork in main_phase od scoreboard will not affect main_phase threads of monitor

In reply to ashish_banga:

Yes, for main_phase() and every time-consuming _phase task.

In reply to dave_59:

Hi Dave,
Is it possible to disable a specific fork?
for example:

fork : sample_and_refine
\ task1
\ task2
join_any

disable sample_and_refine;

In reply to yakirye:

What do you mean by specific? You have only one fork, and your disable statement disables that.

In reply to dave_59:

task my_task()
fork : first_fork
\\ task1
\\ task2
join_any

fork : sec_fork
\\ task3
\\ task4
join_any

disable sec_fork;
endtask : my_task

is this syntax valid? the intention is to kill task3 and task4 only, while keeping task1 and task2 alive.

  • i know i can swap the order of the forks and put the disable in between, this is just a theoretical question

my real issue is that i have several watchdog tasks in my ref_model, of course watchdog tasks should be kill once the expected event occurs, my concern is that if i use ‘disable fork’ in one watchdog task, it will kill all the other ref model watchdog tasks as well.

with that said, i would expect that the scope of the the ‘disable fork’ would be the scope of the task calling it. but from what i read above (and in other answers you gave), i understand that the scope of the ‘disable fork’ is the process in which it is called…

1 Like

In reply to yakirye:

Yes, what you wrote works under one condition—there is only one invocation of my_task. If there are multiple invocations, disable sec_fork kills all of them.

There are a couple better ways of coding this. You can put a fork/join as a process guard.

task my_task()
  fork : first_fork
    task1;
   task2;
  join_any : first_fork
  fork 
    begin : sec_fork_guard
      fork : sec_fork
        task3;
        task4;
      join_any : sec_fork
      disable fork; // only disable inside sec_fork_guard block
    end : sec_fork_guard
  join
endtask : my_task

And for complete control, you can use the process class

task my_task()
  process p[$];
  fork : first_fork
    task1;
   task2;
  join_any : first_fork 
  fork : sec_fork
    begin
      p.push_back(process::self();
      task3;
    end
    begin
      p.push_back(process::self();
      task4;
    end
  join_any
  foreach(p[i]) if (p[i].status != process::FINISHED) p[i].kill();
endtask : my_task
1 Like

In reply to dave_59:

Great explanation! many thanks!

In reply to dave_59:

In reply to yakirye:
Yes, what you wrote works under one condition—there is only one invocation of my_task. If there are multiple invocations, disable sec_fork kills all of them.

Hello Dave,

I have one question for ‘multiple invocations’ you mentioned.

If this task belongs to one component and we have multiple objects of this components, like below:


    comp  c0, c1, c2;
    c0 = new();
    c1 = new();
    c2 = new();

    fork
        c0.my_task();
        c1.my_task();
        c2.my_task();
    join
......

Does this mean ‘multiple invocations’ in your case? how can we just kill those threads(task3/4)inside c2 instead of all rests even in C0 and C1, if so.

Thanks!

In reply to tongwang:

Correct, ‘
disable blockname;
’ does not provide a mechanism for specifying a particular object. I already gave better ways of killing a particular process.

In reply to dave_59:

understood.

Thanks, Dave and I will try your solutions.

In reply to dave_59:


task my_task()
  fork : first_fork
    task1;
   task2;
  join_any : first_fork
  fork
    begin : sec_fork_guard
      fork : sec_fork
        task3;
        task4;
      join_any : sec_fork
      disable fork; // only disable inside sec_fork_guard block
    end : sec_fork_guard
  join
endtask : my_task

Hello Dave,
May I have one more question here. As for the first solution above, ‘disable fork’ means to disable the fork/join without label outside of begin/end instead of the ‘fork: sec_fork’. Am I correct?

Thanks,

In reply to tongwang:

disable fork only kills the processes that are children of the process that executes the disable fork statement. It might help to describe the process tree rather than scopes.

process1 calls my_task. The first statement is a fork/join_any. That suspends process1 until any one of the forked processes it creates ends. It it has two statements and creates two child processes, process2 and process3. One of those processes must end before continuing beyond the join_any. Let’s assume process3 ends, so process2 remains.

The next statement is a fork/join. That suspends process1 again until all the processes it creates ends. It contains one statement, so it creates one process4. Now process1 has two children, process2/4. Process4 contains a fork/join_any with two statements. It creates tow child processes, process5/6. One of those processes must end before continuing beyond the join_any. Let’s assume process5 ends, so process6 remains. Now process4 continues executing the disable fork statement. Only process6 is a child of process4, so only that process gets disabled. That is also the last statement in process4, so that process ends and the join can continue process1. When we get to the end of the task, process2 is still a child of process1

In reply to dave_59:

In reply to tongwang:
disable fork only kills the processes that are children of the process that executes the disable fork statement. It might help to describe the process tree rather than scopes.
process1 calls my_task. The first statement is a fork/join_any. That suspends process1 until any one of the forked processes it creates ends. It it has two statements and creates two child processes, process2 and process3. One of those processes must end before continuing beyond the join_any. Let’s assume process3 ends, so process2 remains.
The next statement is a fork/join. That suspends process1 again until all the processes it creates ends. It contains one statement, so it creates one process4. Now process1 has two children, process2/4. Process4 contains a fork/join_any with two statements. It creates tow child processes, process5/6. One of those processes must end before continuing beyond the join_any. Let’s assume process5 ends, so process6 remains. Now process4 continues executing the disable fork statement. Only process6 is a child of process4, so only that process gets disabled. That is also the last statement in process4, so that process ends and the join can continue process1. When we get to the end of the task, process2 is still a child of process1

Then if i use ‘disable sec_fork’ instead of ‘disable fork’, can i get a same result since task3 and task4 are children processes of sec_fork_guard which executes ‘disable sec_fork’ statement

Thanks.

In reply to tongwang:

We are going around in circles. disable sec_fork has the problem that it is not selective when there are multiple invocations. Suppose there was

initial fork
   my_task;
   my_task;
join

This would double the number of processes, and executing disable sec_fork would kill two processes, not just one.