1 /* 2 * Copyright (c) 2005, 2015, 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 */ 24 25 #ifndef SHARE_VM_GC_CMS_YIELDINGWORKGROUP_HPP 26 #define SHARE_VM_GC_CMS_YIELDINGWORKGROUP_HPP 27 28 #include "gc/shared/workgroup.hpp" 29 #include "utilities/macros.hpp" 30 31 // Forward declarations 32 class YieldingFlexibleWorkGang; 33 34 // Status of tasks 35 enum Status { 36 INACTIVE, 37 ACTIVE, 38 YIELDING, 39 YIELDED, 40 ABORTING, 41 ABORTED, 42 COMPLETING, 43 COMPLETED 44 }; 45 46 // Class YieldingFlexibleGangWorker: 47 // Several instances of this class run in parallel as workers for a gang. 48 class YieldingFlexibleGangWorker: public GangWorker { 49 public: 50 // Ctor 51 YieldingFlexibleGangWorker(AbstractWorkGang* gang, int id) : 52 GangWorker(gang, id) { } 53 54 public: 55 YieldingFlexibleWorkGang* yf_gang() const 56 { return (YieldingFlexibleWorkGang*)gang(); } 57 58 protected: // Override from parent class 59 virtual void loop(); 60 }; 61 62 class FlexibleGangTask: public AbstractGangTask { 63 int _actual_size; // size of gang obtained 64 protected: 65 int _requested_size; // size of gang requested 66 public: 67 FlexibleGangTask(const char* name): AbstractGangTask(name), 68 _requested_size(0) {} 69 70 // The abstract work method. 71 // The argument tells you which member of the gang you are. 72 virtual void work(uint worker_id) = 0; 73 74 int requested_size() const { return _requested_size; } 75 int actual_size() const { return _actual_size; } 76 77 void set_requested_size(int sz) { _requested_size = sz; } 78 void set_actual_size(int sz) { _actual_size = sz; } 79 }; 80 81 // An abstract task to be worked on by a flexible work gang, 82 // and where the workers will periodically yield, usually 83 // in response to some condition that is signalled by means 84 // that are specific to the task at hand. 85 // You subclass this to supply your own work() method. 86 // A second feature of this kind of work gang is that 87 // it allows for the signalling of certain exceptional 88 // conditions that may be encountered during the performance 89 // of the task and that may require the task at hand to be 90 // `aborted' forthwith. Finally, these gangs are `flexible' 91 // in that they can operate at partial capacity with some 92 // gang workers waiting on the bench; in other words, the 93 // size of the active worker pool can flex (up to an apriori 94 // maximum) in response to task requests at certain points. 95 // The last part (the flexible part) has not yet been fully 96 // fleshed out and is a work in progress. 97 class YieldingFlexibleGangTask: public FlexibleGangTask { 98 Status _status; 99 YieldingFlexibleWorkGang* _gang; 100 101 protected: 102 // Constructor and desctructor: only construct subclasses. 103 YieldingFlexibleGangTask(const char* name): FlexibleGangTask(name), 104 _status(INACTIVE), 105 _gang(NULL) { } 106 107 ~YieldingFlexibleGangTask() { } 108 109 friend class YieldingFlexibleWorkGang; 110 friend class YieldingFlexibleGangWorker; 111 NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const { 112 return true; 113 }) 114 115 void set_status(Status s) { 116 _status = s; 117 } 118 YieldingFlexibleWorkGang* gang() { 119 return _gang; 120 } 121 void set_gang(YieldingFlexibleWorkGang* gang) { 122 assert(_gang == NULL || gang == NULL, "Clobber without intermediate reset?"); 123 _gang = gang; 124 } 125 126 public: 127 // The abstract work method. 128 // The argument tells you which member of the gang you are. 129 virtual void work(uint worker_id) = 0; 130 131 // Subclasses should call the parent's yield() method 132 // after having done any work specific to the subclass. 133 virtual void yield(); 134 135 // An abstract method supplied by 136 // a concrete sub-class which is used by the coordinator 137 // to do any "central yielding" work. 138 virtual void coordinator_yield() = 0; 139 140 // Subclasses should call the parent's abort() method 141 // after having done any work specific to the sunbclass. 142 virtual void abort(); 143 144 Status status() const { return _status; } 145 bool yielding() const { return _status == YIELDING; } 146 bool yielded() const { return _status == YIELDED; } 147 bool completed() const { return _status == COMPLETED; } 148 bool aborted() const { return _status == ABORTED; } 149 bool active() const { return _status == ACTIVE; } 150 }; 151 // Class YieldingWorkGang: A subclass of WorkGang. 152 // In particular, a YieldingWorkGang is made up of 153 // YieldingGangWorkers, and provides infrastructure 154 // supporting yielding to the "GangOverseer", 155 // being the thread that orchestrates the WorkGang via run_task(). 156 class YieldingFlexibleWorkGang: public FlexibleWorkGang { 157 // Here's the public interface to this class. 158 public: 159 // Constructor and destructor. 160 YieldingFlexibleWorkGang(const char* name, uint workers, 161 bool are_GC_task_threads); 162 163 YieldingFlexibleGangTask* yielding_task() const { 164 assert(task() == NULL || task()->is_YieldingFlexibleGang_task(), 165 "Incorrect cast"); 166 return (YieldingFlexibleGangTask*)task(); 167 } 168 // Allocate a worker and return a pointer to it. 169 GangWorker* allocate_worker(uint which); 170 171 // Run a task; returns when the task is done, or the workers yield, 172 // or the task is aborted, or the work gang is terminated via stop(). 173 // A task that has been yielded can be continued via this same interface 174 // by using the same task repeatedly as the argument to the call. 175 // It is expected that the YieldingFlexibleGangTask carries the appropriate 176 // continuation information used by workers to continue the task 177 // from its last yield point. Thus, a completed task will return 178 // immediately with no actual work having been done by the workers. 179 void run_task(AbstractGangTask* task) { 180 guarantee(false, "Use start_task instead"); 181 } 182 void start_task(YieldingFlexibleGangTask* new_task); 183 void continue_task(YieldingFlexibleGangTask* gang_task); 184 185 // Abort a currently running task, if any; returns when all the workers 186 // have stopped working on the current task and have returned to their 187 // waiting stations. 188 void abort_task(); 189 190 // Yield: workers wait at their current working stations 191 // until signalled to proceed by the overseer. 192 void yield(); 193 194 // Abort: workers are expected to return to their waiting 195 // stations, whence they are ready for the next task dispatched 196 // by the overseer. 197 void abort(); 198 199 private: 200 uint _yielded_workers; 201 void wait_for_gang(); 202 203 public: 204 // Accessors for fields 205 uint yielded_workers() const { 206 return _yielded_workers; 207 } 208 209 private: 210 friend class YieldingFlexibleGangWorker; 211 void reset(); // NYI 212 }; 213 214 #endif // SHARE_VM_GC_CMS_YIELDINGWORKGROUP_HPP