1 | /* |
2 | * Copyright (c) 2005, 2019, 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_GC_CMS_YIELDINGWORKGROUP_HPP |
26 | #define SHARE_GC_CMS_YIELDINGWORKGROUP_HPP |
27 | |
28 | #include "gc/shared/workgroup.hpp" |
29 | #include "utilities/macros.hpp" |
30 | |
31 | // Forward declarations |
32 | class YieldingFlexibleGangTask; |
33 | class YieldingFlexibleWorkGang; |
34 | |
35 | // Status of tasks |
36 | enum Status { |
37 | INACTIVE, |
38 | ACTIVE, |
39 | YIELDING, |
40 | YIELDED, |
41 | ABORTING, |
42 | ABORTED, |
43 | COMPLETING, |
44 | COMPLETED |
45 | }; |
46 | |
47 | class YieldingWorkData: public StackObj { |
48 | // This would be a struct, but I want accessor methods. |
49 | private: |
50 | AbstractGangTask* _task; |
51 | int _sequence_number; |
52 | public: |
53 | // Constructor and destructor |
54 | YieldingWorkData() : _task(NULL), _sequence_number(0) {} |
55 | ~YieldingWorkData() {} |
56 | |
57 | // Accessors and modifiers |
58 | AbstractGangTask* task() const { return _task; } |
59 | void set_task(AbstractGangTask* value) { _task = value; } |
60 | int sequence_number() const { return _sequence_number; } |
61 | void set_sequence_number(int value) { _sequence_number = value; } |
62 | |
63 | YieldingFlexibleGangTask* yf_task() const { |
64 | return (YieldingFlexibleGangTask*)_task; |
65 | } |
66 | }; |
67 | |
68 | // Class YieldingFlexibleGangWorker: |
69 | // Several instances of this class run in parallel as workers for a gang. |
70 | class YieldingFlexibleGangWorker: public AbstractGangWorker { |
71 | public: |
72 | YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id); |
73 | |
74 | public: |
75 | YieldingFlexibleWorkGang* yf_gang() const |
76 | { return (YieldingFlexibleWorkGang*)gang(); } |
77 | |
78 | protected: // Override from parent class |
79 | virtual void loop(); |
80 | }; |
81 | |
82 | class FlexibleGangTask: public AbstractGangTask { |
83 | int _actual_size; // size of gang obtained |
84 | protected: |
85 | int _requested_size; // size of gang requested |
86 | public: |
87 | FlexibleGangTask(const char* name): AbstractGangTask(name), |
88 | _requested_size(0) {} |
89 | |
90 | // The abstract work method. |
91 | // The argument tells you which member of the gang you are. |
92 | virtual void work(uint worker_id) = 0; |
93 | |
94 | int requested_size() const { return _requested_size; } |
95 | int actual_size() const { return _actual_size; } |
96 | |
97 | void set_requested_size(int sz) { _requested_size = sz; } |
98 | void set_actual_size(int sz) { _actual_size = sz; } |
99 | }; |
100 | |
101 | // An abstract task to be worked on by a flexible work gang, |
102 | // and where the workers will periodically yield, usually |
103 | // in response to some condition that is signalled by means |
104 | // that are specific to the task at hand. |
105 | // You subclass this to supply your own work() method. |
106 | // A second feature of this kind of work gang is that |
107 | // it allows for the signalling of certain exceptional |
108 | // conditions that may be encountered during the performance |
109 | // of the task and that may require the task at hand to be |
110 | // `aborted' forthwith. Finally, these gangs are `flexible' |
111 | // in that they can operate at partial capacity with some |
112 | // gang workers waiting on the bench; in other words, the |
113 | // size of the active worker pool can flex (up to an apriori |
114 | // maximum) in response to task requests at certain points. |
115 | // The last part (the flexible part) has not yet been fully |
116 | // fleshed out and is a work in progress. |
117 | class YieldingFlexibleGangTask: public FlexibleGangTask { |
118 | Status _status; |
119 | YieldingFlexibleWorkGang* _gang; |
120 | |
121 | protected: |
122 | // Constructor and desctructor: only construct subclasses. |
123 | YieldingFlexibleGangTask(const char* name): FlexibleGangTask(name), |
124 | _status(INACTIVE), |
125 | _gang(NULL) { } |
126 | |
127 | ~YieldingFlexibleGangTask() { } |
128 | |
129 | friend class YieldingFlexibleWorkGang; |
130 | friend class YieldingFlexibleGangWorker; |
131 | |
132 | void set_status(Status s) { |
133 | _status = s; |
134 | } |
135 | YieldingFlexibleWorkGang* gang() { |
136 | return _gang; |
137 | } |
138 | void set_gang(YieldingFlexibleWorkGang* gang) { |
139 | assert(_gang == NULL || gang == NULL, "Clobber without intermediate reset?" ); |
140 | _gang = gang; |
141 | } |
142 | |
143 | public: |
144 | // The abstract work method. |
145 | // The argument tells you which member of the gang you are. |
146 | virtual void work(uint worker_id) = 0; |
147 | |
148 | // Subclasses should call the parent's yield() method |
149 | // after having done any work specific to the subclass. |
150 | virtual void yield(); |
151 | |
152 | // An abstract method supplied by |
153 | // a concrete sub-class which is used by the coordinator |
154 | // to do any "central yielding" work. |
155 | virtual void coordinator_yield() = 0; |
156 | |
157 | // Subclasses should call the parent's abort() method |
158 | // after having done any work specific to the sunbclass. |
159 | virtual void abort(); |
160 | |
161 | Status status() const { return _status; } |
162 | bool yielding() const { return _status == YIELDING; } |
163 | bool yielded() const { return _status == YIELDED; } |
164 | bool completed() const { return _status == COMPLETED; } |
165 | bool aborted() const { return _status == ABORTED; } |
166 | bool active() const { return _status == ACTIVE; } |
167 | |
168 | // This method configures the task for proper termination. |
169 | // Some tasks do not have any requirements on termination |
170 | // and may inherit this method that does nothing. Some |
171 | // tasks do some coordination on termination and override |
172 | // this method to implement that coordination. |
173 | virtual void set_for_termination(uint active_workers) {} |
174 | }; |
175 | // Class YieldingWorkGang: A subclass of WorkGang. |
176 | // In particular, a YieldingWorkGang is made up of |
177 | // YieldingGangWorkers, and provides infrastructure |
178 | // supporting yielding to the "GangOverseer", |
179 | // being the thread that orchestrates the WorkGang via run_task(). |
180 | class YieldingFlexibleWorkGang: public AbstractWorkGang { |
181 | // Here's the public interface to this class. |
182 | public: |
183 | // Constructor and destructor. |
184 | YieldingFlexibleWorkGang(const char* name, uint workers, |
185 | bool are_GC_task_threads); |
186 | |
187 | YieldingFlexibleGangTask* yielding_task() const { |
188 | return task(); |
189 | } |
190 | // Allocate a worker and return a pointer to it. |
191 | AbstractGangWorker* allocate_worker(uint which); |
192 | |
193 | // Run a task; returns when the task is done, or the workers yield, |
194 | // or the task is aborted. |
195 | // A task that has been yielded can be continued via this same interface |
196 | // by using the same task repeatedly as the argument to the call. |
197 | // It is expected that the YieldingFlexibleGangTask carries the appropriate |
198 | // continuation information used by workers to continue the task |
199 | // from its last yield point. Thus, a completed task will return |
200 | // immediately with no actual work having been done by the workers. |
201 | void run_task(AbstractGangTask* task) { |
202 | guarantee(false, "Use start_task instead" ); |
203 | } |
204 | void start_task(YieldingFlexibleGangTask* new_task); |
205 | void continue_task(YieldingFlexibleGangTask* gang_task); |
206 | |
207 | // Abort a currently running task, if any; returns when all the workers |
208 | // have stopped working on the current task and have returned to their |
209 | // waiting stations. |
210 | void abort_task(); |
211 | |
212 | // Yield: workers wait at their current working stations |
213 | // until signalled to proceed by the overseer. |
214 | void yield(); |
215 | |
216 | // Abort: workers are expected to return to their waiting |
217 | // stations, whence they are ready for the next task dispatched |
218 | // by the overseer. |
219 | void abort(); |
220 | |
221 | private: |
222 | uint _yielded_workers; |
223 | void wait_for_gang(); |
224 | |
225 | public: |
226 | // Accessors for fields |
227 | uint yielded_workers() const { |
228 | return _yielded_workers; |
229 | } |
230 | |
231 | private: |
232 | friend class YieldingFlexibleGangWorker; |
233 | void reset(); // NYI |
234 | |
235 | |
236 | // The monitor which protects these data, |
237 | // and notifies of changes in it. |
238 | Monitor* _monitor; |
239 | // Accessors for fields |
240 | Monitor* monitor() const { |
241 | return _monitor; |
242 | } |
243 | |
244 | // The number of started workers. |
245 | uint _started_workers; |
246 | // The number of finished workers. |
247 | uint _finished_workers; |
248 | |
249 | uint started_workers() const { |
250 | return _started_workers; |
251 | } |
252 | uint finished_workers() const { |
253 | return _finished_workers; |
254 | } |
255 | |
256 | // A sequence number for the current task. |
257 | int _sequence_number; |
258 | int sequence_number() const { |
259 | return _sequence_number; |
260 | } |
261 | |
262 | YieldingFlexibleGangTask* _task; |
263 | YieldingFlexibleGangTask* task() const { |
264 | return _task; |
265 | } |
266 | |
267 | void internal_worker_poll(YieldingWorkData* data) const; |
268 | void internal_note_start(); |
269 | void internal_note_finish(); |
270 | }; |
271 | |
272 | #endif // SHARE_GC_CMS_YIELDINGWORKGROUP_HPP |
273 | |