yieldingWorkgroup.hpp revision 8848:90861a3150d0
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
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_VM_GC_CMS_YIELDINGWORKGROUP_HPP
273