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
32class YieldingFlexibleGangTask;
33class YieldingFlexibleWorkGang;
34
35// Status of tasks
36enum Status {
37 INACTIVE,
38 ACTIVE,
39 YIELDING,
40 YIELDED,
41 ABORTING,
42 ABORTED,
43 COMPLETING,
44 COMPLETED
45};
46
47class YieldingWorkData: public StackObj {
48 // This would be a struct, but I want accessor methods.
49private:
50 AbstractGangTask* _task;
51 int _sequence_number;
52public:
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.
70class YieldingFlexibleGangWorker: public AbstractGangWorker {
71public:
72 YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id);
73
74public:
75 YieldingFlexibleWorkGang* yf_gang() const
76 { return (YieldingFlexibleWorkGang*)gang(); }
77
78protected: // Override from parent class
79 virtual void loop();
80};
81
82class FlexibleGangTask: public AbstractGangTask {
83 int _actual_size; // size of gang obtained
84protected:
85 int _requested_size; // size of gang requested
86public:
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.
117class YieldingFlexibleGangTask: public FlexibleGangTask {
118 Status _status;
119 YieldingFlexibleWorkGang* _gang;
120
121protected:
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
143public:
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().
180class YieldingFlexibleWorkGang: public AbstractWorkGang {
181 // Here's the public interface to this class.
182public:
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
221private:
222 uint _yielded_workers;
223 void wait_for_gang();
224
225public:
226 // Accessors for fields
227 uint yielded_workers() const {
228 return _yielded_workers;
229 }
230
231private:
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