2685N/A * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A// Forward declaration of classes declared here. 0N/A// Run a task; returns when the task is done, or the workers yield, 0N/A// or the task is aborted, or the work gang is terminated via stop(). 0N/A// A task that has been yielded can be continued via this interface 0N/A// by using the same task repeatedly as the argument to the call. 0N/A// It is expected that the YieldingFlexibleGangTask carries the appropriate 0N/A// continuation information used by workers to continue the task 0N/A// from its last yield point. Thus, a completed task will return 0N/A// immediately with no actual work having been done by the workers. 0N/A///////////////////// 0N/A// Implementatiuon notes: remove before checking XXX 0N/AEach gang is working on a task at a certain time. 0N/ASome subset of workers may have yielded and some may 0N/Ahave finished their quota of work. Until this task has 0N/Abeen completed, the workers are bound to that task. 0N/AOnce the task has been completed, the gang unbounds 0N/Aitself from the task. 0N/AThe yielding work gang thus exports two invokation 0N/Ainterfaces: run_task() and continue_task(). The 0N/Afirst is used to initiate a new task and bind it 0N/Ato the workers; the second is used to continue an 0N/Aalready bound task that has yielded. Upon completion 0N/Athe binding is released and a new binding may be 0N/AThe shape of a yielding work gang is as follows: 0N/AOverseer invokes run_task(*task). 0N/A Check that there is no existing binding for the gang 0N/A If so, abort with an error 0N/A Else, create a new binding of this gang to the given task 0N/A Set number of active workers (as asked) 0N/A Notify workers that work is ready to be done 0N/A [the requisite # workers would then start up 0N/A Wait on the monitor until either 0N/A all work is completed or the task has yielded 0N/A -- this is normally done through 0N/A yielded + completed == active 0N/A [completed workers are rest to idle state by overseer?] 0N/A return appropriate status to caller 0N/AOverseer invokes continue_task(*task), 0N/A Check that task is the same as current binding 0N/A If not, abort with an error 0N/A Else, set the number of active workers as requested? 0N/A Notify workers that they can continue from yield points 0N/A New workers can also start up as required 0N/A while satisfying the constraint that 0N/A active + yielded does not exceed required number 0N/ANOTE: In the above, for simplicity in a first iteration 0N/A our gangs will be of fixed population and will not 0N/A therefore be flexible work gangs, just yielding work 0N/A gangs. Once this works well, we will in a second 0N/A iteration.refinement introduce flexibility into 0N/ANOTE: we can always create a new gang per each iteration 0N/A in order to get the flexibility, but we will for now 0N/A desist that simplified route. 0N/A///////////////////// 0N/A // Bind task to gang 0N/A // Wake up all the workers, the first few will get to work, 0N/A // and the rest will go back to sleep 0N/A // Wait for task to complete or yield 0N/A reset();
// for next task; gang<->task binding released 0N/A "Inconsistent counts");
0N/A "Else why are we calling continue_task()");
0N/A // Restart the yielded gang workers 0N/A // Do not yield; we need to abort as soon as possible 0N/A // XXX NOTE: This can cause a performance pathology in the 0N/A // current implementation in Mustang, as of today, and 0N/A // pre-Mustang in that as soon as an overflow occurs, 0N/A // yields will not be honoured. The right way to proceed 0N/A // of course is to fix bug # TBF, so that abort's cause 0N/A // us to return at each potential yield point. 0N/A break;
// from switch 0N/A // Only return is from inside switch statement above 0N/A // not allowed states 0N/A // At least one thread has yielded, wake it up 0N/A // so it can go back to waiting stations ASAP. 0N/A/////////////////////////////// 0N/A// YieldingFlexibleGangTask 0N/A/////////////////////////////// 0N/A/////////////////////////////// 0N/A// YieldingFlexibleGangWorker 0N/A/////////////////////////////// 0N/A // Check if there is work to do or if we have been asked 0N/A // We have been asked to terminate. 0N/A // set_status(TERMINATED); 0N/A // There is work to be done. 0N/A // First check if we need to become active or if there 0N/A // are already the requisite number of workers 0N/A // There are already enough workers, we do not need to 0N/A // to run; fall through and wait on monitor. 0N/A // We need to pitch in and do the work. 0N/A "Unexpected state");
0N/A // Now, release the gang mutex and do the work. 0N/A // Reacquire monitor and note completion of this worker 0N/A // Update status of task based on whether all workers have 0N/A // finished or some have yielded 0N/A }
else {
// at least one worker is still working or yielded 0N/A "Counts inconsistent");
0N/A // first, but not only thread to complete 0N/A break;
// nothing to do 0N/A default:
// everything else: INACTIVE, YIELDED, ABORTED, COMPLETED 0N/A // Remember the sequence number 0N/A // Wait for more work