src/share/vm/utilities/yieldingWorkgroup.cpp

Thu, 27 May 2010 19:08:38 -0700

author
trims
date
Thu, 27 May 2010 19:08:38 -0700
changeset 1907
c18cbe5936b8
parent 777
37f87013dfd8
child 2188
8b10f48633dc
permissions
-rw-r--r--

6941466: Oracle rebranding changes for Hotspot repositories
Summary: Change all the Sun copyrights to Oracle copyright
Reviewed-by: ohair

     1 /*
     2  * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 # include "incls/_precompiled.incl"
    26 # include "incls/_yieldingWorkgroup.cpp.incl"
    28 // Forward declaration of classes declared here.
    30 class GangWorker;
    31 class WorkData;
    33 YieldingFlexibleWorkGang::YieldingFlexibleWorkGang(
    34   const char* name, int workers, bool are_GC_task_threads) :
    35   AbstractWorkGang(name, are_GC_task_threads, false) {
    36   // Save arguments.
    37   _total_workers = workers;
    38   assert(_total_workers > 0, "Must have more than 1 worker");
    40   _yielded_workers = 0;
    42   if (TraceWorkGang) {
    43     tty->print_cr("Constructing work gang %s with %d threads", name, workers);
    44   }
    45   _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, workers);
    46   assert(gang_workers() != NULL, "Failed to allocate gang workers");
    47   for (int worker = 0; worker < total_workers(); worker += 1) {
    48     YieldingFlexibleGangWorker* new_worker =
    49       new YieldingFlexibleGangWorker(this, worker);
    50     assert(new_worker != NULL, "Failed to allocate YieldingFlexibleGangWorker");
    51     _gang_workers[worker] = new_worker;
    52     if (new_worker == NULL || !os::create_thread(new_worker, os::pgc_thread))
    53       vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
    54     if (!DisableStartThread) {
    55       os::start_thread(new_worker);
    56     }
    57   }
    58 }
    60 // Run a task; returns when the task is done, or the workers yield,
    61 // or the task is aborted, or the work gang is terminated via stop().
    62 // A task that has been yielded can be continued via this interface
    63 // by using the same task repeatedly as the argument to the call.
    64 // It is expected that the YieldingFlexibleGangTask carries the appropriate
    65 // continuation information used by workers to continue the task
    66 // from its last yield point. Thus, a completed task will return
    67 // immediately with no actual work having been done by the workers.
    68 /////////////////////
    69 // Implementatiuon notes: remove before checking XXX
    70 /*
    71 Each gang is working on a task at a certain time.
    72 Some subset of workers may have yielded and some may
    73 have finished their quota of work. Until this task has
    74 been completed, the workers are bound to that task.
    75 Once the task has been completed, the gang unbounds
    76 itself from the task.
    78 The yielding work gang thus exports two invokation
    79 interfaces: run_task() and continue_task(). The
    80 first is used to initiate a new task and bind it
    81 to the workers; the second is used to continue an
    82 already bound task that has yielded. Upon completion
    83 the binding is released and a new binding may be
    84 created.
    86 The shape of a yielding work gang is as follows:
    88 Overseer invokes run_task(*task).
    89    Lock gang monitor
    90    Check that there is no existing binding for the gang
    91    If so, abort with an error
    92    Else, create a new binding of this gang to the given task
    93    Set number of active workers (as asked)
    94    Notify workers that work is ready to be done
    95      [the requisite # workers would then start up
    96       and do the task]
    97    Wait on the monitor until either
    98      all work is completed or the task has yielded
    99      -- this is normally done through
   100         yielded + completed == active
   101         [completed workers are rest to idle state by overseer?]
   102    return appropriate status to caller
   104 Overseer invokes continue_task(*task),
   105    Lock gang monitor
   106    Check that task is the same as current binding
   107    If not, abort with an error
   108    Else, set the number of active workers as requested?
   109    Notify workers that they can continue from yield points
   110     New workers can also start up as required
   111       while satisfying the constraint that
   112          active + yielded does not exceed required number
   113    Wait (as above).
   115 NOTE: In the above, for simplicity in a first iteration
   116   our gangs will be of fixed population and will not
   117   therefore be flexible work gangs, just yielding work
   118   gangs. Once this works well, we will in a second
   119   iteration.refinement introduce flexibility into
   120   the work gang.
   122 NOTE: we can always create a new gang per each iteration
   123   in order to get the flexibility, but we will for now
   124   desist that simplified route.
   126  */
   127 /////////////////////
   128 void YieldingFlexibleWorkGang::start_task(YieldingFlexibleGangTask* new_task) {
   129   MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   130   assert(task() == NULL, "Gang currently tied to a task");
   131   assert(new_task != NULL, "Null task");
   132   // Bind task to gang
   133   _task = new_task;
   134   new_task->set_gang(this);  // Establish 2-way binding to support yielding
   135   _sequence_number++;
   137   int requested_size = new_task->requested_size();
   138   assert(requested_size >= 0, "Should be non-negative");
   139   if (requested_size != 0) {
   140     _active_workers = MIN2(requested_size, total_workers());
   141   } else {
   142     _active_workers = total_workers();
   143   }
   144   new_task->set_actual_size(_active_workers);
   146   assert(_started_workers == 0, "Tabula rasa non");
   147   assert(_finished_workers == 0, "Tabula rasa non");
   148   assert(_yielded_workers == 0, "Tabula rasa non");
   149   yielding_task()->set_status(ACTIVE);
   151   // Wake up all the workers, the first few will get to work,
   152   // and the rest will go back to sleep
   153   monitor()->notify_all();
   154   wait_for_gang();
   155 }
   157 void YieldingFlexibleWorkGang::wait_for_gang() {
   159   assert(monitor()->owned_by_self(), "Data race");
   160   // Wait for task to complete or yield
   161   for (Status status = yielding_task()->status();
   162        status != COMPLETED && status != YIELDED && status != ABORTED;
   163        status = yielding_task()->status()) {
   164     assert(started_workers() <= active_workers(), "invariant");
   165     assert(finished_workers() <= active_workers(), "invariant");
   166     assert(yielded_workers() <= active_workers(), "invariant");
   167     monitor()->wait(Mutex::_no_safepoint_check_flag);
   168   }
   169   switch (yielding_task()->status()) {
   170     case COMPLETED:
   171     case ABORTED: {
   172       assert(finished_workers() == active_workers(), "Inconsistent status");
   173       assert(yielded_workers() == 0, "Invariant");
   174       reset();   // for next task; gang<->task binding released
   175       break;
   176     }
   177     case YIELDED: {
   178       assert(yielded_workers() > 0, "Invariant");
   179       assert(yielded_workers() + finished_workers() == active_workers(),
   180              "Inconsistent counts");
   181       break;
   182     }
   183     case ACTIVE:
   184     case INACTIVE:
   185     case COMPLETING:
   186     case YIELDING:
   187     case ABORTING:
   188     default:
   189       ShouldNotReachHere();
   190   }
   191 }
   193 void YieldingFlexibleWorkGang::continue_task(
   194   YieldingFlexibleGangTask* gang_task) {
   196   MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   197   assert(task() != NULL && task() == gang_task, "Incorrect usage");
   198   // assert(_active_workers == total_workers(), "For now");
   199   assert(_started_workers == _active_workers, "Precondition");
   200   assert(_yielded_workers > 0 && yielding_task()->status() == YIELDED,
   201          "Else why are we calling continue_task()");
   202   // Restart the yielded gang workers
   203   yielding_task()->set_status(ACTIVE);
   204   monitor()->notify_all();
   205   wait_for_gang();
   206 }
   208 void YieldingFlexibleWorkGang::reset() {
   209   _started_workers  = 0;
   210   _finished_workers = 0;
   211   _active_workers   = 0;
   212   yielding_task()->set_gang(NULL);
   213   _task = NULL;    // unbind gang from task
   214 }
   216 void YieldingFlexibleWorkGang::yield() {
   217   assert(task() != NULL, "Inconsistency; should have task binding");
   218   MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   219   assert(yielded_workers() < active_workers(), "Consistency check");
   220   if (yielding_task()->status() == ABORTING) {
   221     // Do not yield; we need to abort as soon as possible
   222     // XXX NOTE: This can cause a performance pathology in the
   223     // current implementation in Mustang, as of today, and
   224     // pre-Mustang in that as soon as an overflow occurs,
   225     // yields will not be honoured. The right way to proceed
   226     // of course is to fix bug # TBF, so that abort's cause
   227     // us to return at each potential yield point.
   228     return;
   229   }
   230   if (++_yielded_workers + finished_workers() == active_workers()) {
   231     yielding_task()->set_status(YIELDED);
   232     monitor()->notify_all();
   233   } else {
   234     yielding_task()->set_status(YIELDING);
   235   }
   237   while (true) {
   238     switch (yielding_task()->status()) {
   239       case YIELDING:
   240       case YIELDED: {
   241         monitor()->wait(Mutex::_no_safepoint_check_flag);
   242         break;  // from switch
   243       }
   244       case ACTIVE:
   245       case ABORTING:
   246       case COMPLETING: {
   247         assert(_yielded_workers > 0, "Else why am i here?");
   248         _yielded_workers--;
   249         return;
   250       }
   251       case INACTIVE:
   252       case ABORTED:
   253       case COMPLETED:
   254       default: {
   255         ShouldNotReachHere();
   256       }
   257     }
   258   }
   259   // Only return is from inside switch statement above
   260   ShouldNotReachHere();
   261 }
   263 void YieldingFlexibleWorkGang::abort() {
   264   assert(task() != NULL, "Inconsistency; should have task binding");
   265   MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   266   assert(yielded_workers() < active_workers(), "Consistency check");
   267   #ifndef PRODUCT
   268     switch (yielding_task()->status()) {
   269       // allowed states
   270       case ACTIVE:
   271       case ABORTING:
   272       case COMPLETING:
   273       case YIELDING:
   274         break;
   275       // not allowed states
   276       case INACTIVE:
   277       case ABORTED:
   278       case COMPLETED:
   279       case YIELDED:
   280       default:
   281         ShouldNotReachHere();
   282     }
   283   #endif // !PRODUCT
   284   Status prev_status = yielding_task()->status();
   285   yielding_task()->set_status(ABORTING);
   286   if (prev_status == YIELDING) {
   287     assert(yielded_workers() > 0, "Inconsistency");
   288     // At least one thread has yielded, wake it up
   289     // so it can go back to waiting stations ASAP.
   290     monitor()->notify_all();
   291   }
   292 }
   294 ///////////////////////////////
   295 // YieldingFlexibleGangTask
   296 ///////////////////////////////
   297 void YieldingFlexibleGangTask::yield() {
   298   assert(gang() != NULL, "No gang to signal");
   299   gang()->yield();
   300 }
   302 void YieldingFlexibleGangTask::abort() {
   303   assert(gang() != NULL, "No gang to signal");
   304   gang()->abort();
   305 }
   307 ///////////////////////////////
   308 // YieldingFlexibleGangWorker
   309 ///////////////////////////////
   310 void YieldingFlexibleGangWorker::loop() {
   311   int previous_sequence_number = 0;
   312   Monitor* gang_monitor = gang()->monitor();
   313   MutexLockerEx ml(gang_monitor, Mutex::_no_safepoint_check_flag);
   314   WorkData data;
   315   int id;
   316   while (true) {
   317     // Check if there is work to do or if we have been asked
   318     // to terminate
   319     gang()->internal_worker_poll(&data);
   320     if (data.terminate()) {
   321       // We have been asked to terminate.
   322       assert(gang()->task() == NULL, "No task binding");
   323       // set_status(TERMINATED);
   324       return;
   325     } else if (data.task() != NULL &&
   326                data.sequence_number() != previous_sequence_number) {
   327       // There is work to be done.
   328       // First check if we need to become active or if there
   329       // are already the requisite number of workers
   330       if (gang()->started_workers() == yf_gang()->active_workers()) {
   331         // There are already enough workers, we do not need to
   332         // to run; fall through and wait on monitor.
   333       } else {
   334         // We need to pitch in and do the work.
   335         assert(gang()->started_workers() < yf_gang()->active_workers(),
   336                "Unexpected state");
   337         id = gang()->started_workers();
   338         gang()->internal_note_start();
   339         // Now, release the gang mutex and do the work.
   340         {
   341           MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag);
   342           data.task()->work(id);   // This might include yielding
   343         }
   344         // Reacquire monitor and note completion of this worker
   345         gang()->internal_note_finish();
   346         // Update status of task based on whether all workers have
   347         // finished or some have yielded
   348         assert(data.task() == gang()->task(), "Confused task binding");
   349         if (gang()->finished_workers() == yf_gang()->active_workers()) {
   350           switch (data.yf_task()->status()) {
   351             case ABORTING: {
   352               data.yf_task()->set_status(ABORTED);
   353               break;
   354             }
   355             case ACTIVE:
   356             case COMPLETING: {
   357               data.yf_task()->set_status(COMPLETED);
   358               break;
   359             }
   360             default:
   361               ShouldNotReachHere();
   362           }
   363           gang_monitor->notify_all();  // Notify overseer
   364         } else { // at least one worker is still working or yielded
   365           assert(gang()->finished_workers() < yf_gang()->active_workers(),
   366                  "Counts inconsistent");
   367           switch (data.yf_task()->status()) {
   368             case ACTIVE: {
   369               // first, but not only thread to complete
   370               data.yf_task()->set_status(COMPLETING);
   371               break;
   372             }
   373             case YIELDING: {
   374               if (gang()->finished_workers() + yf_gang()->yielded_workers()
   375                   == yf_gang()->active_workers()) {
   376                 data.yf_task()->set_status(YIELDED);
   377                 gang_monitor->notify_all();  // notify overseer
   378               }
   379               break;
   380             }
   381             case ABORTING:
   382             case COMPLETING: {
   383               break; // nothing to do
   384             }
   385             default: // everything else: INACTIVE, YIELDED, ABORTED, COMPLETED
   386               ShouldNotReachHere();
   387           }
   388         }
   389       }
   390     }
   391     // Remember the sequence number
   392     previous_sequence_number = data.sequence_number();
   393     // Wait for more work
   394     gang_monitor->wait(Mutex::_no_safepoint_check_flag);
   395   }
   396 }

mercurial