title: System Verilog fork confusion, statements executed between fork and begin
body: <p>See the simplified example code here:</p>
  
  <pre><code>    process job[num_objs]; 
      // assume also, arr_obj1s (array of type obj1) and 
      // arr_obj2s (array of type obj2) are arrays of size 
      // num_objs, and the objects define a run() function
      foreach (arr_obj1s[i]) begin
          fork
              automatic int j = i;
              arr_obj1s[j].run(); // these run forever loops
              begin
                  job[j] = process::self();
                  arr_obj2s[j].run(); // these run finite logic
              end
          join_none
      end
  
      foreach (job[i]) begin
          wait (job[i] != null);
          job[i].await();
      end
  
      // How do we ever reach here?
  </code></pre>
  
  <p>My confusion is that the calls to <code>arr_obj1s[j].run()</code> will never return (they run forever loops) and I don't quite follow the meaning of that call's placement outside the begin/end block. Which process is that forever <code>run()</code> executed on, and how can it be that each call to <code>await()</code> will return if some process is running a <code>run()</code> which won't return?</p>
  
  <p>EDIT: Here is some more information. Posting the full code would be pages and pages, but I hope this extra bit helps.</p>
  
  <p>obj1's <code>run()</code> function looks like this:</p>
  
  <pre><code>virtual task run;
    fork
      run_a(); // different logically separated tasks
      run_b();
      run_c();
    join
  endtask: run
  </code></pre>
  
  <p>And as an example, <code>run_a</code> looks basically like this (they are all similar):</p>
  
  <pre><code>virtual task run_a;
    // declare some local variables
    forever begin
      @(posedge clk)
      // ...
    end
  endtask: run_a
  </code></pre>
  
  <p>But obj2's <code>run()</code> function looks basically like this:</p>
  
  <pre><code>virtual task run;
    fork
      run_d(); // different logically separated tasks
      run_e();
    join
  endtask: run
  </code></pre>
  
  <p>And as an example <code>run_d()</code> looks like this:</p>
  
  <pre><code>virtual task run_d;
    while ((data_que.size() &gt; 0)) begin
      // process a pre-loaded queue,
      // data will not be pushed on during the simulation
    end
  endtask:run_d
  </code></pre>