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