src/hotspot/share/gc/cms/yieldingWorkgroup.cpp
branchaefimov-dns-client-branch
changeset 59099 fcdb8e7ead8f
parent 58984 15e026239a6c
parent 59075 355f4f42dda5
child 59100 b92aac38b046
--- a/src/hotspot/share/gc/cms/yieldingWorkgroup.cpp	Fri Nov 08 14:54:17 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,399 +0,0 @@
-/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/cms/yieldingWorkgroup.hpp"
-#include "gc/shared/gcId.hpp"
-#include "utilities/macros.hpp"
-
-YieldingFlexibleGangWorker::YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id)
-    : AbstractGangWorker(gang, id) {}
-
-YieldingFlexibleWorkGang::YieldingFlexibleWorkGang(
-    const char* name, uint workers, bool are_GC_task_threads) :
-         AbstractWorkGang(name, workers, are_GC_task_threads, false),
-         _yielded_workers(0),
-         _started_workers(0),
-         _finished_workers(0),
-         _sequence_number(0),
-         _task(NULL) {
-
-  // Other initialization.
-  _monitor = new Monitor(/* priority */       Mutex::leaf,
-                         /* name */           "WorkGroup monitor",
-                         /* allow_vm_block */ are_GC_task_threads,
-                                              Monitor::_safepoint_check_never);
-
-  assert(monitor() != NULL, "Failed to allocate monitor");
-}
-
-AbstractGangWorker* YieldingFlexibleWorkGang::allocate_worker(uint which) {
-  return new YieldingFlexibleGangWorker(this, which);
-}
-
-void YieldingFlexibleWorkGang::internal_worker_poll(YieldingWorkData* data) const {
-  assert(data != NULL, "worker data is null");
-  data->set_task(task());
-  data->set_sequence_number(sequence_number());
-}
-
-void YieldingFlexibleWorkGang::internal_note_start() {
-  assert(monitor()->owned_by_self(), "note_finish is an internal method");
-  _started_workers += 1;
-}
-
-void YieldingFlexibleWorkGang::internal_note_finish() {
-  assert(monitor()->owned_by_self(), "note_finish is an internal method");
-  _finished_workers += 1;
-}
-
-// Run a task; returns when the task is done, or the workers yield,
-// or the task is aborted.
-// A task that has been yielded can be continued via this interface
-// by using the same task repeatedly as the argument to the call.
-// It is expected that the YieldingFlexibleGangTask carries the appropriate
-// continuation information used by workers to continue the task
-// from its last yield point. Thus, a completed task will return
-// immediately with no actual work having been done by the workers.
-/////////////////////
-// Implementatiuon notes: remove before checking XXX
-/*
-Each gang is working on a task at a certain time.
-Some subset of workers may have yielded and some may
-have finished their quota of work. Until this task has
-been completed, the workers are bound to that task.
-Once the task has been completed, the gang unbounds
-itself from the task.
-
-The yielding work gang thus exports two invokation
-interfaces: run_task() and continue_task(). The
-first is used to initiate a new task and bind it
-to the workers; the second is used to continue an
-already bound task that has yielded. Upon completion
-the binding is released and a new binding may be
-created.
-
-The shape of a yielding work gang is as follows:
-
-Overseer invokes run_task(*task).
-   Lock gang monitor
-   Check that there is no existing binding for the gang
-   If so, abort with an error
-   Else, create a new binding of this gang to the given task
-   Set number of active workers (as asked)
-   Notify workers that work is ready to be done
-     [the requisite # workers would then start up
-      and do the task]
-   Wait on the monitor until either
-     all work is completed or the task has yielded
-     -- this is normally done through
-        yielded + completed == active
-        [completed workers are rest to idle state by overseer?]
-   return appropriate status to caller
-
-Overseer invokes continue_task(*task),
-   Lock gang monitor
-   Check that task is the same as current binding
-   If not, abort with an error
-   Else, set the number of active workers as requested?
-   Notify workers that they can continue from yield points
-    New workers can also start up as required
-      while satisfying the constraint that
-         active + yielded does not exceed required number
-   Wait (as above).
-
-NOTE: In the above, for simplicity in a first iteration
-  our gangs will be of fixed population and will not
-  therefore be flexible work gangs, just yielding work
-  gangs. Once this works well, we will in a second
-  iteration.refinement introduce flexibility into
-  the work gang.
-
-NOTE: we can always create a new gang per each iteration
-  in order to get the flexibility, but we will for now
-  desist that simplified route.
-
- */
-/////////////////////
-void YieldingFlexibleWorkGang::start_task(YieldingFlexibleGangTask* new_task) {
-  MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag);
-  assert(task() == NULL, "Gang currently tied to a task");
-  assert(new_task != NULL, "Null task");
-  // Bind task to gang
-  _task = new_task;
-  new_task->set_gang(this);  // Establish 2-way binding to support yielding
-  _sequence_number++;
-
-  uint requested_size = new_task->requested_size();
-  if (requested_size != 0) {
-    _active_workers = MIN2(requested_size, total_workers());
-  } else {
-    _active_workers = active_workers();
-  }
-  new_task->set_actual_size(_active_workers);
-  new_task->set_for_termination(_active_workers);
-
-  assert(_started_workers == 0, "Tabula rasa non");
-  assert(_finished_workers == 0, "Tabula rasa non");
-  assert(_yielded_workers == 0, "Tabula rasa non");
-  yielding_task()->set_status(ACTIVE);
-
-  // Wake up all the workers, the first few will get to work,
-  // and the rest will go back to sleep
-  monitor()->notify_all();
-  wait_for_gang();
-}
-
-void YieldingFlexibleWorkGang::wait_for_gang() {
-
-  assert(monitor()->owned_by_self(), "Data race");
-  // Wait for task to complete or yield
-  for (Status status = yielding_task()->status();
-       status != COMPLETED && status != YIELDED && status != ABORTED;
-       status = yielding_task()->status()) {
-    assert(started_workers() <= active_workers(), "invariant");
-    assert(finished_workers() <= active_workers(), "invariant");
-    assert(yielded_workers() <= active_workers(), "invariant");
-    monitor()->wait_without_safepoint_check();
-  }
-  switch (yielding_task()->status()) {
-    case COMPLETED:
-    case ABORTED: {
-      assert(finished_workers() == active_workers(), "Inconsistent status");
-      assert(yielded_workers() == 0, "Invariant");
-      reset();   // for next task; gang<->task binding released
-      break;
-    }
-    case YIELDED: {
-      assert(yielded_workers() > 0, "Invariant");
-      assert(yielded_workers() + finished_workers() == active_workers(),
-             "Inconsistent counts");
-      break;
-    }
-    case ACTIVE:
-    case INACTIVE:
-    case COMPLETING:
-    case YIELDING:
-    case ABORTING:
-    default:
-      ShouldNotReachHere();
-  }
-}
-
-void YieldingFlexibleWorkGang::continue_task(
-  YieldingFlexibleGangTask* gang_task) {
-
-  MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag);
-  assert(task() != NULL && task() == gang_task, "Incorrect usage");
-  assert(_started_workers == _active_workers, "Precondition");
-  assert(_yielded_workers > 0 && yielding_task()->status() == YIELDED,
-         "Else why are we calling continue_task()");
-  // Restart the yielded gang workers
-  yielding_task()->set_status(ACTIVE);
-  monitor()->notify_all();
-  wait_for_gang();
-}
-
-void YieldingFlexibleWorkGang::reset() {
-  _started_workers  = 0;
-  _finished_workers = 0;
-  yielding_task()->set_gang(NULL);
-  _task = NULL;    // unbind gang from task
-}
-
-void YieldingFlexibleWorkGang::yield() {
-  assert(task() != NULL, "Inconsistency; should have task binding");
-  MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag);
-  assert(yielded_workers() < active_workers(), "Consistency check");
-  if (yielding_task()->status() == ABORTING) {
-    // Do not yield; we need to abort as soon as possible
-    // XXX NOTE: This can cause a performance pathology in the
-    // current implementation in Mustang, as of today, and
-    // pre-Mustang in that as soon as an overflow occurs,
-    // yields will not be honoured. The right way to proceed
-    // of course is to fix bug # TBF, so that abort's cause
-    // us to return at each potential yield point.
-    return;
-  }
-  if (++_yielded_workers + finished_workers() == active_workers()) {
-    yielding_task()->set_status(YIELDED);
-    monitor()->notify_all();
-  } else {
-    yielding_task()->set_status(YIELDING);
-  }
-
-  while (true) {
-    switch (yielding_task()->status()) {
-      case YIELDING:
-      case YIELDED: {
-        monitor()->wait_without_safepoint_check();
-        break;  // from switch
-      }
-      case ACTIVE:
-      case ABORTING:
-      case COMPLETING: {
-        assert(_yielded_workers > 0, "Else why am i here?");
-        _yielded_workers--;
-        return;
-      }
-      case INACTIVE:
-      case ABORTED:
-      case COMPLETED:
-      default: {
-        ShouldNotReachHere();
-      }
-    }
-  }
-  // Only return is from inside switch statement above
-  ShouldNotReachHere();
-}
-
-void YieldingFlexibleWorkGang::abort() {
-  assert(task() != NULL, "Inconsistency; should have task binding");
-  MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag);
-  assert(yielded_workers() < active_workers(), "Consistency check");
-  #ifndef PRODUCT
-    switch (yielding_task()->status()) {
-      // allowed states
-      case ACTIVE:
-      case ABORTING:
-      case COMPLETING:
-      case YIELDING:
-        break;
-      // not allowed states
-      case INACTIVE:
-      case ABORTED:
-      case COMPLETED:
-      case YIELDED:
-      default:
-        ShouldNotReachHere();
-    }
-  #endif // !PRODUCT
-  Status prev_status = yielding_task()->status();
-  yielding_task()->set_status(ABORTING);
-  if (prev_status == YIELDING) {
-    assert(yielded_workers() > 0, "Inconsistency");
-    // At least one thread has yielded, wake it up
-    // so it can go back to waiting stations ASAP.
-    monitor()->notify_all();
-  }
-}
-
-///////////////////////////////
-// YieldingFlexibleGangTask
-///////////////////////////////
-void YieldingFlexibleGangTask::yield() {
-  assert(gang() != NULL, "No gang to signal");
-  gang()->yield();
-}
-
-void YieldingFlexibleGangTask::abort() {
-  assert(gang() != NULL, "No gang to signal");
-  gang()->abort();
-}
-
-///////////////////////////////
-// YieldingFlexibleGangWorker
-///////////////////////////////
-void YieldingFlexibleGangWorker::loop() {
-  int previous_sequence_number = 0;
-  Monitor* gang_monitor = yf_gang()->monitor();
-  MutexLocker ml(gang_monitor, Mutex::_no_safepoint_check_flag);
-  YieldingWorkData data;
-  int id;
-  while (true) {
-    // Check if there is work to do.
-    yf_gang()->internal_worker_poll(&data);
-    if (data.task() != NULL && data.sequence_number() != previous_sequence_number) {
-      // There is work to be done.
-      // First check if we need to become active or if there
-      // are already the requisite number of workers
-      if (yf_gang()->started_workers() == yf_gang()->active_workers()) {
-        // There are already enough workers, we do not need to
-        // to run; fall through and wait on monitor.
-      } else {
-        // We need to pitch in and do the work.
-        assert(yf_gang()->started_workers() < yf_gang()->active_workers(),
-               "Unexpected state");
-        id = yf_gang()->started_workers();
-        yf_gang()->internal_note_start();
-        // Now, release the gang mutex and do the work.
-        {
-          MutexUnlocker mul(gang_monitor, Mutex::_no_safepoint_check_flag);
-          GCIdMark gc_id_mark(data.task()->gc_id());
-          data.task()->work(id);   // This might include yielding
-        }
-        // Reacquire monitor and note completion of this worker
-        yf_gang()->internal_note_finish();
-        // Update status of task based on whether all workers have
-        // finished or some have yielded
-        assert(data.task() == yf_gang()->task(), "Confused task binding");
-        if (yf_gang()->finished_workers() == yf_gang()->active_workers()) {
-          switch (data.yf_task()->status()) {
-            case ABORTING: {
-              data.yf_task()->set_status(ABORTED);
-              break;
-            }
-            case ACTIVE:
-            case COMPLETING: {
-              data.yf_task()->set_status(COMPLETED);
-              break;
-            }
-            default:
-              ShouldNotReachHere();
-          }
-          gang_monitor->notify_all();  // Notify overseer
-        } else { // at least one worker is still working or yielded
-          assert(yf_gang()->finished_workers() < yf_gang()->active_workers(),
-                 "Counts inconsistent");
-          switch (data.yf_task()->status()) {
-            case ACTIVE: {
-              // first, but not only thread to complete
-              data.yf_task()->set_status(COMPLETING);
-              break;
-            }
-            case YIELDING: {
-              if (yf_gang()->finished_workers() + yf_gang()->yielded_workers()
-                  == yf_gang()->active_workers()) {
-                data.yf_task()->set_status(YIELDED);
-                gang_monitor->notify_all();  // notify overseer
-              }
-              break;
-            }
-            case ABORTING:
-            case COMPLETING: {
-              break; // nothing to do
-            }
-            default: // everything else: INACTIVE, YIELDED, ABORTED, COMPLETED
-              ShouldNotReachHere();
-          }
-        }
-      }
-    }
-    // Remember the sequence number
-    previous_sequence_number = data.sequence_number();
-    // Wait for more work
-    gang_monitor->wait_without_safepoint_check();
-  }
-}