ScummVM API documentation
vthread.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef MTROPOLIS_VTHREAD_H
23 #define MTROPOLIS_VTHREAD_H
24 
25 #include "mtropolis/coroutine_protos.h"
26 #include "mtropolis/coroutine_return_value.h"
27 #include "mtropolis/debug.h"
28 
29 namespace MTropolis {
30 
31 struct ICoroutineManager;
32 class VThread;
33 
34 // Virtual thread, really a task stack
35 enum VThreadState {
36  kVThreadReturn,
37  kVThreadSuspended,
38  kVThreadError,
39 };
40 
42 };
43 
44 template<typename T>
46  static VThreadFaultIdentifier _identifier;
47 };
48 
49 template<typename T>
51 
52 class VThreadTaskData : public Debuggable {
53 public:
55  virtual ~VThreadTaskData();
56 
57  virtual VThreadState execute(VThread *thread) = 0;
58 
59 #ifdef MTROPOLIS_DEBUG_ENABLE
60 public:
61  void debugInit(const char *name);
62 
63 protected:
64  SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
65  const char *debugGetTypeName() const override { return "Task"; }
66  const Common::String &debugGetName() const override { return _debugName; }
67  void debugInspect(IDebugInspectionReport *report) const override;
68 
69  Common::String _debugName;
70 #endif
71 };
72 
73 struct VThreadStackFrame;
74 
76 public:
77  explicit VThreadStackChunk(size_t capacity);
80 
81  VThreadStackFrame *_topFrame;
82  byte *_memory;
83  size_t _size;
84 
85 private:
86  VThreadStackChunk() = delete;
87  VThreadStackChunk(const VThreadStackChunk &) = delete;
88 };
89 
91  VThreadTaskData *data;
92  VThreadStackFrame *prevFrame;
93  bool isLastInChunk;
94 };
95 
96 template<typename TClass, typename TData>
98 public:
99  VThreadMethodData(const VThreadFaultIdentifier *faultID, TClass *target, VThreadState (TClass::*method)(const TData &data));
100  VThreadMethodData(const VThreadMethodData &other);
102 
103  VThreadState execute(VThread *thread) override;
104 
105  TData &getData();
106 
107 private:
108  const VThreadFaultIdentifier *_faultID;
109  TClass *_target;
110  VThreadState (TClass::*_method)(const TData &data);
111  TData _data;
112 };
113 
114 template<typename TData>
116 
117 public:
118  explicit VThreadFunctionData(const VThreadFaultIdentifier *faultID, VThreadState (*func)(const TData &data));
120 
122 
123  VThreadState execute(VThread *thread) override;
124 
125  TData &getData();
126 
127 private:
128  const VThreadFaultIdentifier *_faultID;
129  VThreadState (*_func)(const TData &data);
130  TData _data;
131 };
132 
133 class VThread {
134 public:
135  explicit VThread(ICoroutineManager *coroManager);
136  ~VThread();
137 
138  template<typename TClass, typename TData>
139  TData *pushTask(const char *name, TClass *obj, VThreadState (TClass::*method)(const TData &data));
140 
141  template<typename TData>
142  TData *pushTask(const char *name, VThreadState (*func)(const TData &data));
143 
144  VThreadState step();
145 
146  bool hasTasks() const;
147 
148  bool popFrame();
149 
150  VThreadTaskData *pushCoroutineFrame(const CompiledCoroutine *compiledCoro, const CoroutineParamsBase &params, const CoroutineReturnValueRefBase &returnValueRef);
151 
152  template<typename TCoroutine, typename TReturnValue, typename ...TParams>
153  void pushCoroutineWithReturn(TReturnValue *returnValuePtr, TParams &&...args);
154 
155  template<typename TCoroutine, typename TReturnValue>
156  void pushCoroutineWithReturn(TReturnValue *returnValuePtr);
157 
158  template<typename TCoroutine, typename... TParams>
159  void pushCoroutine(TParams &&...args);
160 
161  template<typename TCoroutine>
162  void pushCoroutine();
163 
164 
165 private:
166  void reserveFrame(size_t frameAlignment, size_t frameSize, VThreadStackFrame *&outFramePtr, size_t dataAlignment, size_t dataSize, void *&outDataPtr, bool &outIsNewChunk);
167  static bool reserveFrameInChunk(VThreadStackChunk *chunk, size_t frameAlignment, size_t frameSize, VThreadStackFrame *&outFramePtr, size_t dataAlignment, size_t dataSize, void *&outDataPtr);
168 
169  void pushCoroutineInternal(CompiledCoroutine **compiledCoroPtr, CoroutineCompileFunction_t compileFunc, bool isVoidReturn, const CoroutineParamsBase &params, const CoroutineReturnValueRefBase &returnValueRef);
170 
171  template<typename TClass, typename TData>
172  TData *pushTaskWithFaultHandler(const VThreadFaultIdentifier *faultID, const char *name, TClass *obj, VThreadState (TClass::*method)(const TData &data));
173 
174  template<typename TData>
175  TData *pushTaskWithFaultHandler(const VThreadFaultIdentifier *faultID, const char *name, VThreadState (*func)(const TData &data));
176 
178  ICoroutineManager *_coroManager;
179  uint _numActiveStackChunks;
180 };
181 
182 template<typename TClass, typename TData>
183 VThreadMethodData<TClass, TData>::VThreadMethodData(const VThreadFaultIdentifier *faultID, TClass *target, VThreadState (TClass::*method)(const TData &data))
184  : _faultID(faultID), _target(target), _method(method) {
185 }
186 
187 template<typename TClass, typename TData>
189  : _faultID(other._faultID), _target(other._target), _method(other._method), _data(other._data) {
190 }
191 
192 template<typename TClass, typename TData>
194  : _faultID(other._faultID), _target(other._target), _method(other._method), _data(static_cast<TData &&>(other._data)) {
195 }
196 
197 template<typename TClass, typename TData>
199  TData data(static_cast<TData &&>(_data));
200 
201  TClass *target = _target;
202  VThreadState (TClass::*method)(const TData &) = _method;
203 
204  thread->popFrame();
205 
206  return (target->*method)(data);
207 }
208 
209 template<typename TClass, typename TData>
211  return _data;
212 }
213 
214 template<typename TData>
215 VThreadFunctionData<TData>::VThreadFunctionData(const VThreadFaultIdentifier *faultID, VThreadState (*func)(const TData &data))
216  : _faultID(faultID), _func(func) {
217 }
218 
219 template<typename TData>
221  : _faultID(other._faultID), _func(other._func), _data(other._data) {
222 }
223 
224 template<typename TData>
226  : _faultID(other._faultID), _func(other._func), _data(static_cast<TData &&>(other._data)) {
227 }
228 
229 template<typename TData>
230 VThreadState VThreadFunctionData<TData>::execute(VThread *thread) {
231  TData data(static_cast<TData &&>(_data));
232 
233  VThreadState (*func)(const TData &) = _func;
234 
235  thread->popFrame();
236 
237  return func(data);
238 }
239 
240 template<typename TData>
242  return _data;
243 }
244 
245 template<typename TCoroutine, typename TReturnValue, typename... TParams>
246 void VThread::pushCoroutineWithReturn(TReturnValue *returnValuePtr, TParams &&...args) {
247  assert(returnValuePtr != nullptr);
248  this->pushCoroutineInternal(&TCoroutine::ms_compiledCoro, TCoroutine::compileCoroutine, CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>::isVoid(), typename TCoroutine::Params(Common::forward<TParams>(args)...), CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>(returnValuePtr));
249 }
250 
251 template<typename TCoroutine, typename TReturnValue>
252 void VThread::pushCoroutineWithReturn(TReturnValue *returnValuePtr) {
253  assert(returnValuePtr != nullptr);
254  this->pushCoroutineInternal(&TCoroutine::ms_compiledCoro, TCoroutine::compileCoroutine, CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>::isVoid(), typename TCoroutine::Params(), CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>(returnValuePtr));
255 }
256 
257 template<typename TCoroutine, typename... TParams>
258 void VThread::pushCoroutine(TParams &&...args) {
259  this->pushCoroutineInternal(&TCoroutine::ms_compiledCoro, TCoroutine::compileCoroutine, CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>::isVoid(), typename TCoroutine::Params(Common::forward<TParams>(args)...), CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>());
260 }
261 
262 template<typename TCoroutine>
263 void VThread::pushCoroutine() {
264  this->pushCoroutineInternal(&TCoroutine::ms_compiledCoro, TCoroutine::compileCoroutine, CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>::isVoid(), typename TCoroutine::Params(), CoroutineReturnValueRef<typename TCoroutine::ReturnValue_t>());
265 }
266 
267 template<typename TClass, typename TData>
268 TData *VThread::pushTask(const char *name, TClass *obj, VThreadState (TClass::*method)(const TData &data)) {
269  return this->pushTaskWithFaultHandler(nullptr, name, obj, method);
270 }
271 
272 template<typename TData>
273 TData *VThread::pushTask(const char *name, VThreadState (*func)(const TData &data)) {
274  return this->pushTaskWithFaultHandler(nullptr, name, func);
275 }
276 
277 template<typename TClass, typename TData>
278 TData *VThread::pushTaskWithFaultHandler(const VThreadFaultIdentifier *faultID, const char *name, TClass *obj, VThreadState (TClass::*method)(const TData &data)) {
279  typedef VThreadMethodData<TClass, TData> FrameData_t;
280 
281  const size_t frameAlignment = alignof(VThreadStackFrame);
282  const size_t dataAlignment = alignof(FrameData_t);
283 
284  VThreadStackFrame *prevFrame = nullptr;
285  if (_numActiveStackChunks > 0)
286  prevFrame = _stackChunks[_numActiveStackChunks - 1]._topFrame;
287 
288  VThreadStackFrame *framePtr = nullptr;
289  void *dataPtr = nullptr;
290  bool isNewChunk = false;
291  reserveFrame(frameAlignment, sizeof(VThreadStackFrame), framePtr, dataAlignment, sizeof(FrameData_t), dataPtr, isNewChunk);
292 
293  VThreadStackFrame *frame = new (framePtr) VThreadStackFrame();
294  FrameData_t *frameData = new (dataPtr) FrameData_t(faultID, obj, method);
295 
296  frame->data = frameData;
297  frame->prevFrame = prevFrame;
298  frame->isLastInChunk = isNewChunk;
299 
300 #ifdef MTROPOLIS_DEBUG_ENABLE
301  frameData->debugInit(name);
302 #endif
303 
304  return &frameData->getData();
305 }
306 
307 template<typename TData>
308 TData *VThread::pushTaskWithFaultHandler(const VThreadFaultIdentifier *faultID, const char *name, VThreadState (*func)(const TData &data)) {
309  typedef VThreadFunctionData<TData> FrameData_t;
310 
311  const size_t frameAlignment = alignof(VThreadStackFrame);
312  const size_t dataAlignment = alignof(FrameData_t);
313 
314  VThreadStackFrame *prevFrame = nullptr;
315  if (_numActiveStackChunks > 0)
316  prevFrame = _stackChunks[_numActiveStackChunks - 1]._topFrame;
317 
318  VThreadStackFrame *framePtr = nullptr;
319  void *dataPtr = nullptr;
320  bool isNewChunk = false;
321  reserveFrame(frameAlignment, sizeof(VThreadStackFrame), framePtr, dataAlignment, sizeof(FrameData_t), dataPtr, isNewChunk);
322 
323  VThreadStackFrame *frame = new (framePtr) VThreadStackFrame();
324  FrameData_t *frameData = new (dataPtr) FrameData_t(faultID, func);
325 
326  frame->data = frameData;
327  frame->prevFrame = prevFrame;
328  frame->isLastInChunk = isNewChunk;
329 
330 #ifdef MTROPOLIS_DEBUG_ENABLE
331  frameData->debugInit(name);
332 #endif
333 
334  return &frameData->getData();
335 }
336 
337 } // End of namespace MTropolis
338 
339 #endif
Definition: str.h:59
Definition: vthread.h:90
Definition: array.h:52
Definition: debug.h:83
Definition: vthread.h:41
Definition: coroutine_return_value.h:27
Definition: coroutine_protos.h:42
Definition: debug.h:59
Definition: coroutines.h:50
Definition: vthread.h:97
Definition: vthread.h:52
Definition: vthread.h:75
Definition: vthread.h:115
Definition: vthread.h:133
Definition: actions.h:25
Definition: coroutine_return_value.h:31
Definition: coroutine_manager.h:34