Killing a fork join_none present in a for loop

Hi ,

could you provide the clarifications on the below

how to kill the all threads forked off in the belwo fork join_none . I tried with disable fork_name , but it gave compilation error



for (int j=0; j<3; j++) begin
   fork :fork_name
      automatic int k = j; // Make copy of index
     taskname(k); // Print copy
    join_none
end

It would help to show the code you tried to use to kill all the threads because it matters where you are trying to kill the threads from in relation to the forked threads.

Most likely you can use the disable fork construct which kills all the child threads of the current thread.

begin
  for (int j=0; j<3; j++) begin
   fork :fork_name
      automatic int k = j; // Make copy of index
     task_name(k); // Print copy
    join_none
  ...
  disable fork;
end

You have to be careful using this construct because the disable fork construct kills ALL threads that are children of the current thread, not just the threads created by the previous fork statement.

In reply to dave_59:

Hi Dave Thanks for the inputs.
could you provide the clarifications for the following .

I am working on a test where reset needs to be applied second time . then I am facing one issue. issue is mentioned below.



fork 
   fork
      task1
   join_none

   for loop begin
      fork
         task2
      join_none
   for loop end

  fork
     task3
  join_none
begin
@reset event 
  disable fork //place 1
end
join

@reset event 
disable fork  //place 2

all the tasks are the tasks that run until the end of simulation. I need to kill them when reset is applied. I tried with disable fork at both places (place 1 and place 2) by waiting until reset occurs . but the tasks are not getting killed. Then I tried with disable fork_name . Then it worked. due to that I tried to kill the fork join_none block in the for loop with disable fork_name. all the code is in main phase of vmm xactor. i guess the xactor is not killing the threads when cleanup task is called.

Could you suggest better Idea.

In reply to srbeeram:

It would really help to show the actual code you tried to use. In your original post, you said the disable fork_name gave you a compilation error, then you said “it worked” in your followup post without showing what you actually did.

The disable forks you show will not work because: In place 1, there are no child threads of the begin/end block thread inside the fork/join. In place 2, each statement block within the fork/join block creates a child thread and the fork/join_none block becomes a child of that thread, but the disable fork statement is outside the fork/join block and all the child threads that it created are done. disable fork only kills the direct children threads, not the grandchildren.

What you probably want is

fork : fork_block
  begin: begin_block
   fork
      task1;
   join_none
 
   for (;;) begin : for_loop
      fork
         task2;
      join_none
   end : for_loop
 
  fork
     task3;
  join_none

  @reset_event disable fork;
  end : begin_block
join : join_block

You will have to explain further about what you meant about reset needing to be applied second time, or is the reset_event here the second time already?

In reply to srbeeram:

Hi Dave,

in the following code also , still tasks are grand children as they are inside the fork blocks which are children of begin end thread. then is disable fork expected to kill the grandchildren threads (tasks) also. in this case why it is expected. could you please provide the clarifications.



fork : fork_block
  begin: begin_block
   fork
      task1;
   join_none
 
   for (;;) begin : for_loop
      fork
         task2;
      join_none
   end : for_loop
 
  fork
     task3;
  join_none
 
  @reset_event disable fork;
  end : begin_block
join : join_block

In reply to srbeeram:

Calling a task does not create a child thread, but each statement of a fork/join* block creates a child thread. And that statement could be another fork, a begin/end block, calling a task, or a simple assignment. A begin/end block inside a fork is treated as one thread, regardless of how many statements are inside it. Note that

fork
  task1;
join_none

is the same as

fork
  begin : forked_thread
    task1; // could have more statements - all in the same thread
  end : forked_thread
join_none

So your earlier example

fork 
   fork 
      task1
   join_none
 
   for loop begin
      fork
         task2
      join_none
   for loop end
 
  fork
     task3
  join_none
begin
@reset event 
  disable fork //place 1
end
join

is interpreted as

fork : fork_block
   begin: thread1 
     fork
      begin : child11 
        task1;
      end child1
   join_none end : thread1
   
   begin : thread2 
      for begin : foo_loop 
      fork
         begin : child 2N
          task2
        end : child2N
      join_none
   end : for_loop
  end : thread2
  begin : thread3
  fork
     begin : child3
       task3;
     end : child3
  join_none
  end : thread3
begin : thread4
@reset event 
  disable fork //place 1
end : thread4
join : fork_block

In reply to dave_59:

Hi Dave,

I have one question in similar topic

fork : fork_block
  begin: begin_block
   fork ---(fork1)
      task1;
   join_none
 
   for (;;) begin : for_loop
      fork----(for_loop fork)
         task2;
      join_none
   end : for_loop
 
  fork---------(third fork)
     task3;
  join_none
 
  @reset_event disable fork;
  end : begin_block
join : join_block

In the above code i assume all the 3 forks i.e (first_fork, for_loop fork and Third fork ) runs sequentially but if design requires to run them in parallel how we can modify the code .

Also is there any way we can kill the grand children threads because you mentioned in earlier post disable fork kills only child threads not grand child threads so if suppose task1 in above example has following code.

task 1();

#Huge_delay operations

endtask

How can we end up such a task when reset is applied .

Thanks

In reply to raku:

The child threads created by the 3 fork/join_none run in parallel regardless of the forks running sequentially or in parallel. A fork/join_none is a 0-time consuming construct and none of the child threads start until the parent thread reaches its end or a blocking statement. Putting the begin_block inside the fork/join serves two purposes: 1) it keeps the disable fork in the parent thread to be able to disable the children. 2) It prevents unwanted disabling of potentially earlier fork/join_none’s that were spawned by the same parent thread.

If you want other ways of disabling threads, see section 9.7 Fine-grain process control of the 1800-2012 LRM. Note that if you are using UVM sequences, it has methods for killing sequences as well.

In reply to dave_59:

Hi Dave , sorry for the confusion. It worked means killing the grand children happened with disable fork_name on one fork join_none block that is not the fork join_none block inside the for loop. so I tried to kill the fork block inside the for loop the same way and it gave compilation error. You are right. and applying the reset second time means I need to apply the reset on rtl when traffic flows . and the traffic flow starts after initial reset. here is the code.



fork  begin

      fork
        Rate();
      join_none

      fork
         Cycle();
      join_none
       if(!empty) 
       begin

         
         for (int i_s=Min; i_s<=Max; i_s++) begin
            fork
            automatic int local_i_s = i_s;
            begin
               task0(local_i_s);
            end
            join_none
         end

         fork: fork_drivePkt
            task1;
	
            task2;
         join_none :fork_drivePkt
              // I tried by placing the code @reset_event disable fork here (reset_event is endThreads in the code) but it didn't work. I will give a trail again.  
                begin
                   @endThreads;
                   disable fork_drivePkt;
                 end
          
       end 
   end
   join



I want to kill all the tasks inside not empty block . all the code is in main task of vmm

In reply to dave_59:

Hi dave,

I tried with the below code

ork : fork_block
begin: begin_block
fork
task1;
join_none

for (;;) begin : for_loop
fork
task2;
join_none
end : for_loop

fork
task3;
join_none

@reset_event disable fork;
end : begin_block
join : join_block

somehow the simulation is hanged.

I can see issue is driver getting not stopped

here is the difference between passing and failing logs. failing log is not giving those messages and passing log is giving the messages and continuing further. I guess failing log is waiting for them to get stopped. I am not sure how the disable fork_drivepkt is avoiding the issue. Could you please clarify what is the difference between disable fork and disable fork_name. what could be the possible reason for the simulation to work with disable fork_name

messages in passing log are as follows.
Driver(0) Stop requested
Driver(0) 0 out of 1 threads have now stopped
1 out of 1 threads have now stopped
Driver(0) Stopped

the reset_event is triggered during the stop_xactor call of this driver.I wanted to stop the all xactors but the tasks are not getting stopped.I needed to disable them manually with simple solution.it seems reset xactor will kill them all without disabling them manually.

In reply to srbeeram:

srbeeram,

I’m sorry, I don’t have anymore time to help you unless you can provide me with complete small examples of code so people can understand what you are trying to do.