duke@435: /* ysr@2192: * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP stefank@2314: #define SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP stefank@2314: stefank@2314: #ifndef SERIALGC stefank@2314: #include "utilities/workgroup.hpp" stefank@2314: #endif stefank@2314: duke@435: duke@435: // Forward declarations duke@435: class YieldingFlexibleWorkGang; duke@435: duke@435: // Status of tasks duke@435: enum Status { duke@435: INACTIVE, duke@435: ACTIVE, duke@435: YIELDING, duke@435: YIELDED, duke@435: ABORTING, duke@435: ABORTED, duke@435: COMPLETING, duke@435: COMPLETED duke@435: }; duke@435: duke@435: // Class YieldingFlexibleGangWorker: duke@435: // Several instances of this class run in parallel as workers for a gang. duke@435: class YieldingFlexibleGangWorker: public GangWorker { duke@435: public: duke@435: // Ctor duke@435: YieldingFlexibleGangWorker(AbstractWorkGang* gang, int id) : duke@435: GangWorker(gang, id) { } duke@435: duke@435: public: duke@435: YieldingFlexibleWorkGang* yf_gang() const duke@435: { return (YieldingFlexibleWorkGang*)gang(); } duke@435: duke@435: protected: // Override from parent class duke@435: virtual void loop(); duke@435: }; duke@435: jmasa@2188: class FlexibleGangTask: public AbstractGangTask { jmasa@2188: int _actual_size; // size of gang obtained jmasa@2188: protected: jmasa@2188: int _requested_size; // size of gang requested jmasa@2188: public: jmasa@2188: FlexibleGangTask(const char* name): AbstractGangTask(name), jmasa@2188: _requested_size(0) {} jmasa@2188: jmasa@2188: // The abstract work method. jmasa@2188: // The argument tells you which member of the gang you are. jmasa@2188: virtual void work(int i) = 0; jmasa@2188: jmasa@2188: int requested_size() const { return _requested_size; } jmasa@2188: int actual_size() const { return _actual_size; } jmasa@2188: jmasa@2188: void set_requested_size(int sz) { _requested_size = sz; } jmasa@2188: void set_actual_size(int sz) { _actual_size = sz; } jmasa@2188: }; jmasa@2188: duke@435: // An abstract task to be worked on by a flexible work gang, duke@435: // and where the workers will periodically yield, usually duke@435: // in response to some condition that is signalled by means duke@435: // that are specific to the task at hand. duke@435: // You subclass this to supply your own work() method. duke@435: // A second feature of this kind of work gang is that duke@435: // it allows for the signalling of certain exceptional duke@435: // conditions that may be encountered during the performance duke@435: // of the task and that may require the task at hand to be duke@435: // `aborted' forthwith. Finally, these gangs are `flexible' duke@435: // in that they can operate at partial capacity with some duke@435: // gang workers waiting on the bench; in other words, the duke@435: // size of the active worker pool can flex (up to an apriori duke@435: // maximum) in response to task requests at certain points. duke@435: // The last part (the flexible part) has not yet been fully duke@435: // fleshed out and is a work in progress. jmasa@2188: class YieldingFlexibleGangTask: public FlexibleGangTask { duke@435: Status _status; duke@435: YieldingFlexibleWorkGang* _gang; duke@435: duke@435: protected: duke@435: // Constructor and desctructor: only construct subclasses. jmasa@2188: YieldingFlexibleGangTask(const char* name): FlexibleGangTask(name), duke@435: _status(INACTIVE), jmasa@2188: _gang(NULL) { } duke@435: duke@435: virtual ~YieldingFlexibleGangTask() { } duke@435: duke@435: friend class YieldingFlexibleWorkGang; duke@435: friend class YieldingFlexibleGangWorker; duke@435: NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const { duke@435: return true; duke@435: }) duke@435: duke@435: void set_status(Status s) { duke@435: _status = s; duke@435: } duke@435: YieldingFlexibleWorkGang* gang() { duke@435: return _gang; duke@435: } duke@435: void set_gang(YieldingFlexibleWorkGang* gang) { duke@435: assert(_gang == NULL || gang == NULL, "Clobber without intermediate reset?"); duke@435: _gang = gang; duke@435: } duke@435: duke@435: public: duke@435: // The abstract work method. duke@435: // The argument tells you which member of the gang you are. duke@435: virtual void work(int i) = 0; duke@435: duke@435: // Subclasses should call the parent's yield() method duke@435: // after having done any work specific to the subclass. duke@435: virtual void yield(); duke@435: duke@435: // An abstract method supplied by duke@435: // a concrete sub-class which is used by the coordinator duke@435: // to do any "central yielding" work. duke@435: virtual void coordinator_yield() = 0; duke@435: duke@435: // Subclasses should call the parent's abort() method duke@435: // after having done any work specific to the sunbclass. duke@435: virtual void abort(); duke@435: duke@435: Status status() const { return _status; } ysr@2192: bool yielding() const { return _status == YIELDING; } duke@435: bool yielded() const { return _status == YIELDED; } duke@435: bool completed() const { return _status == COMPLETED; } duke@435: bool aborted() const { return _status == ABORTED; } duke@435: bool active() const { return _status == ACTIVE; } duke@435: }; duke@435: // Class YieldingWorkGang: A subclass of WorkGang. duke@435: // In particular, a YieldingWorkGang is made up of duke@435: // YieldingGangWorkers, and provides infrastructure duke@435: // supporting yielding to the "GangOverseer", duke@435: // being the thread that orchestrates the WorkGang via run_task(). jmasa@2188: class YieldingFlexibleWorkGang: public FlexibleWorkGang { duke@435: // Here's the public interface to this class. duke@435: public: duke@435: // Constructor and destructor. ysr@777: YieldingFlexibleWorkGang(const char* name, int workers, ysr@777: bool are_GC_task_threads); duke@435: duke@435: YieldingFlexibleGangTask* yielding_task() const { duke@435: assert(task() == NULL || task()->is_YieldingFlexibleGang_task(), duke@435: "Incorrect cast"); duke@435: return (YieldingFlexibleGangTask*)task(); duke@435: } jmasa@2188: // Allocate a worker and return a pointer to it. jmasa@2188: GangWorker* allocate_worker(int which); jmasa@2188: duke@435: // Run a task; returns when the task is done, or the workers yield, duke@435: // or the task is aborted, or the work gang is terminated via stop(). duke@435: // A task that has been yielded can be continued via this same interface duke@435: // by using the same task repeatedly as the argument to the call. duke@435: // It is expected that the YieldingFlexibleGangTask carries the appropriate duke@435: // continuation information used by workers to continue the task duke@435: // from its last yield point. Thus, a completed task will return duke@435: // immediately with no actual work having been done by the workers. duke@435: void run_task(AbstractGangTask* task) { duke@435: guarantee(false, "Use start_task instead"); duke@435: } duke@435: void start_task(YieldingFlexibleGangTask* new_task); duke@435: void continue_task(YieldingFlexibleGangTask* gang_task); duke@435: duke@435: // Abort a currently running task, if any; returns when all the workers duke@435: // have stopped working on the current task and have returned to their duke@435: // waiting stations. duke@435: void abort_task(); duke@435: duke@435: // Yield: workers wait at their current working stations duke@435: // until signalled to proceed by the overseer. duke@435: void yield(); duke@435: duke@435: // Abort: workers are expected to return to their waiting duke@435: // stations, whence they are ready for the next task dispatched duke@435: // by the overseer. duke@435: void abort(); duke@435: duke@435: private: duke@435: int _active_workers; duke@435: int _yielded_workers; duke@435: void wait_for_gang(); duke@435: duke@435: public: duke@435: // Accessors for fields duke@435: int active_workers() const { duke@435: return _active_workers; duke@435: } duke@435: jmasa@2188: // Accessors for fields duke@435: int yielded_workers() const { duke@435: return _yielded_workers; duke@435: } duke@435: duke@435: private: duke@435: friend class YieldingFlexibleGangWorker; duke@435: void reset(); // NYI duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP