yieldingWorkgroup.hpp revision 8413:92457dfb91bd
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 YieldingFlexibleWorkGang;
33
34// Status of tasks
35enum 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.
48class YieldingFlexibleGangWorker: public GangWorker {
49public:
50  // Ctor
51  YieldingFlexibleGangWorker(AbstractWorkGang* gang, int id) :
52    GangWorker(gang, id) { }
53
54public:
55  YieldingFlexibleWorkGang* yf_gang() const
56    { return (YieldingFlexibleWorkGang*)gang(); }
57
58protected: // Override from parent class
59  virtual void loop();
60};
61
62class FlexibleGangTask: public AbstractGangTask {
63  int _actual_size;                      // size of gang obtained
64protected:
65  int _requested_size;                   // size of gang requested
66public:
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.
97class YieldingFlexibleGangTask: public FlexibleGangTask {
98  Status _status;
99  YieldingFlexibleWorkGang* _gang;
100
101protected:
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
126public:
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().
156class YieldingFlexibleWorkGang: public FlexibleWorkGang {
157  // Here's the public interface to this class.
158public:
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
199private:
200  uint _yielded_workers;
201  void wait_for_gang();
202
203public:
204  // Accessors for fields
205  uint yielded_workers() const {
206    return _yielded_workers;
207  }
208
209private:
210  friend class YieldingFlexibleGangWorker;
211  void reset(); // NYI
212};
213
214#endif // SHARE_VM_GC_CMS_YIELDINGWORKGROUP_HPP
215