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
29namespace MTropolis {
30
31struct ICoroutineManager;
32class VThread;
33
34// Virtual thread, really a task stack
35enum VThreadState {
36 kVThreadReturn,
37 kVThreadSuspended,
38 kVThreadError,
39};
40
42};
43
44template<typename T>
46 static VThreadFaultIdentifier _identifier;
47};
48
49template<typename T>
51
53public:
55 virtual ~VThreadTaskData();
56
57 virtual VThreadState execute(VThread *thread) = 0;
58
59#ifdef MTROPOLIS_DEBUG_ENABLE
60public:
61 void debugInit(const char *name);
62
63protected:
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
74
76public:
77 explicit VThreadStackChunk(size_t capacity);
80
81 VThreadStackFrame *_topFrame;
82 byte *_memory;
83 size_t _size;
84
85private:
86 VThreadStackChunk() = delete;
87 VThreadStackChunk(const VThreadStackChunk &) = delete;
88};
89
91 VThreadTaskData *data;
92 VThreadStackFrame *prevFrame;
93 bool isLastInChunk;
94};
95
96template<typename TClass, typename TData>
98public:
99 VThreadMethodData(const VThreadFaultIdentifier *faultID, TClass *target, VThreadState (TClass::*method)(const TData &data));
102
103 VThreadState execute(VThread *thread) override;
104
105 TData &getData();
106
107private:
108 const VThreadFaultIdentifier *_faultID;
109 TClass *_target;
110 VThreadState (TClass::*_method)(const TData &data);
111 TData _data;
112};
113
114template<typename TData>
116
117public:
118 explicit VThreadFunctionData(const VThreadFaultIdentifier *faultID, VThreadState (*func)(const TData &data));
120
122
123 VThreadState execute(VThread *thread) override;
124
125 TData &getData();
126
127private:
128 const VThreadFaultIdentifier *_faultID;
129 VThreadState (*_func)(const TData &data);
130 TData _data;
131};
132
133class VThread {
134public:
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
165private:
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
182template<typename TClass, typename TData>
183VThreadMethodData<TClass, TData>::VThreadMethodData(const VThreadFaultIdentifier *faultID, TClass *target, VThreadState (TClass::*method)(const TData &data))
184 : _faultID(faultID), _target(target), _method(method) {
185}
186
187template<typename TClass, typename TData>
188VThreadMethodData<TClass, TData>::VThreadMethodData(const VThreadMethodData& other)
189 : _faultID(other._faultID), _target(other._target), _method(other._method), _data(other._data) {
190}
191
192template<typename TClass, typename TData>
193VThreadMethodData<TClass, TData>::VThreadMethodData(VThreadMethodData &&other)
194 : _faultID(other._faultID), _target(other._target), _method(other._method), _data(static_cast<TData &&>(other._data)) {
195}
196
197template<typename TClass, typename TData>
198VThreadState VThreadMethodData<TClass, TData>::execute(VThread *thread) {
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
209template<typename TClass, typename TData>
210TData &VThreadMethodData<TClass, TData>::getData() {
211 return _data;
212}
213
214template<typename TData>
215VThreadFunctionData<TData>::VThreadFunctionData(const VThreadFaultIdentifier *faultID, VThreadState (*func)(const TData &data))
216 : _faultID(faultID), _func(func) {
217}
218
219template<typename TData>
220VThreadFunctionData<TData>::VThreadFunctionData(const VThreadFunctionData &other)
221 : _faultID(other._faultID), _func(other._func), _data(other._data) {
222}
223
224template<typename TData>
225VThreadFunctionData<TData>::VThreadFunctionData(VThreadFunctionData &&other)
226 : _faultID(other._faultID), _func(other._func), _data(static_cast<TData &&>(other._data)) {
227}
228
229template<typename TData>
230VThreadState 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
240template<typename TData>
241TData &VThreadFunctionData<TData>::getData() {
242 return _data;
243}
244
245template<typename TCoroutine, typename TReturnValue, typename... TParams>
246void 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
251template<typename TCoroutine, typename TReturnValue>
252void 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
257template<typename TCoroutine, typename... TParams>
258void 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
262template<typename TCoroutine>
263void 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
267template<typename TClass, typename TData>
268TData *VThread::pushTask(const char *name, TClass *obj, VThreadState (TClass::*method)(const TData &data)) {
269 return this->pushTaskWithFaultHandler(nullptr, name, obj, method);
270}
271
272template<typename TData>
273TData *VThread::pushTask(const char *name, VThreadState (*func)(const TData &data)) {
274 return this->pushTaskWithFaultHandler(nullptr, name, func);
275}
276
277template<typename TClass, typename TData>
278TData *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
307template<typename TData>
308TData *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: array.h:52
Definition: str.h:59
Definition: debug.h:83
Definition: vthread.h:115
Definition: vthread.h:133
Definition: vthread.h:97
Definition: vthread.h:75
Definition: vthread.h:52
Definition: actions.h:25
Definition: coroutines.h:50
Definition: coroutine_protos.h:42
Definition: coroutine_return_value.h:27
Definition: coroutine_manager.h:34
Definition: debug.h:59
Definition: vthread.h:41
Definition: vthread.h:90