ScummVM API documentation
coroutines.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 COMMON_COROUTINES_H
23 #define COMMON_COROUTINES_H
24 
25 #include "common/scummsys.h"
26 #include "common/util.h" // for SCUMMVM_CURRENT_FUNCTION
27 #include "common/list.h"
28 #include "common/singleton.h"
29 
30 namespace Common {
31 
44 #define CoroScheduler (Common::CoroutineScheduler::instance())
45 
46 
47 // Enable this macro to enable some debugging support in the coroutine code.
48 //#define COROUTINE_DEBUG
49 
55  int _line;
56  int _sleep;
57  CoroBaseContext *_subctx;
58 #ifdef COROUTINE_DEBUG
59  const char *_funcName;
60 #endif
61 
64  CoroBaseContext(const char *func);
65 
69  virtual ~CoroBaseContext();
70 };
71 
73 
74 
80 extern CoroContext nullContext;
81 
91  CoroContext &_ctx;
92 public:
93  CoroContextHolder(CoroContext &ctx) : _ctx(ctx) {
94  assert(ctx);
95  assert(ctx->_sleep >= 0);
96  ctx->_sleep = 0;
97  }
99  if (_ctx && _ctx->_sleep == 0) {
100  delete _ctx;
101  _ctx = nullptr;
102  }
103  }
104 };
105 
107 #define CORO_PARAM Common::CoroContext &coroParam
108 
109 
131 #define CORO_BEGIN_CONTEXT \
132  struct CoroContextTag : Common::CoroBaseContext { \
133  CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) { DUMMY = 0; } \
134  int DUMMY
135 
141 #define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam
142 
147 #define CORO_BEGIN_CODE(x) \
148  if (&coroParam == &Common::nullContext) assert(!Common::nullContext); \
149  if (!x) { coroParam = x = new CoroContextTag(); } \
150  x->DUMMY = 0; \
151  Common::CoroContextHolder tmpHolder(coroParam); \
152  switch (coroParam->_line) { default: break; case 0:;
153 
157 #define CORO_END_CODE \
158  if (&coroParam == &Common::nullContext) { \
159  delete Common::nullContext; \
160  Common::nullContext = NULL; \
161  } \
162  }
163 
167 #define CORO_SLEEP(delay) \
168  do { \
169  coroParam->_line = __LINE__; \
170  coroParam->_sleep = delay; \
171  assert(&coroParam != &Common::nullContext); \
172  return; case __LINE__:; \
173  } while (0)
174 
175 #define CORO_GIVE_WAY do { CoroScheduler.giveWay(); CORO_SLEEP(1); } while (0)
176 #define CORO_RESCHEDULE do { CoroScheduler.reschedule(); CORO_SLEEP(1); } while (0)
177 
186 #define CORO_KILL_SELF() \
187  do { if (&coroParam != &Common::nullContext) { coroParam->_sleep = -1; } return; } while (0)
188 
189 
194 #define CORO_SUBCTX coroParam->_subctx
195 
216 #define CORO_INVOKE_ARGS(subCoro, ARGS) \
217  do { \
218  coroParam->_line = __LINE__; \
219  coroParam->_subctx = 0; \
220  do { \
221  subCoro ARGS; \
222  if (!coroParam->_subctx) break; \
223  coroParam->_sleep = coroParam->_subctx->_sleep; \
224  assert(&coroParam != &Common::nullContext); \
225  return; case __LINE__:; \
226  } while (1); \
227  } while (0)
228 
235 #define CORO_INVOKE_ARGS_V(subCoro, RESULT, ARGS) \
236  do { \
237  coroParam->_line = __LINE__; \
238  coroParam->_subctx = 0; \
239  do { \
240  subCoro ARGS; \
241  if (!coroParam->_subctx) break; \
242  coroParam->_sleep = coroParam->_subctx->_sleep; \
243  assert(&coroParam != &Common::nullContext); \
244  return RESULT; case __LINE__:; \
245  } while (1); \
246  } while (0)
247 
252 #define CORO_INVOKE_0(subCoroutine) \
253  CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX))
254 
259 #define CORO_INVOKE_1(subCoroutine, a0) \
260  CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0))
261 
266 #define CORO_INVOKE_2(subCoroutine, a0,a1) \
267  CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1))
268 
273 #define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \
274  CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1, a2))
275 
280 #define CORO_INVOKE_4(subCoroutine, a0,a1,a2,a3) \
281  CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1, a2, a3))
282 
283 
284 
286 #define CORO_PARAM_SIZE 40
287 
289 #define CORO_NUM_PROCESS 100
290 #define CORO_MAX_PROCESSES 100
291 #define CORO_MAX_PID_WAITING 5
292 
293 #define CORO_INFINITE 0xffffffff
294 #define CORO_INVALID_PID_VALUE 0
295 
297 typedef void (*CORO_ADDR)(CoroContext &, const void *);
298 
300 struct PROCESS {
303 
304  CoroContext state;
306 
307  int sleepTime;
308  uint32 pid;
309  uint32 pidWaiting[CORO_MAX_PID_WAITING];
310 #ifndef NO_CXX11_ALIGNAS
311  alignas(max_align_t)
312 #endif
313  char param[CORO_PARAM_SIZE];
314 };
315 typedef PROCESS *PPROCESS;
316 
317 
319 struct EVENT {
320  uint32 pid;
321  bool manualReset;
322  bool signalled;
323  bool pulsing;
324 };
325 
326 
330 class CoroutineScheduler : public Singleton<CoroutineScheduler> {
331 public:
333  typedef void (*VFPTRPP)(PROCESS *);
334 
335 private:
336  friend class Singleton<CoroutineScheduler>;
337 
342 
347 
348 
350  PROCESS *processList;
351 
353  PROCESS *active;
354 
356  PROCESS *pFreeProcesses;
357 
359  PROCESS *pCurrent;
360 
362  int pidCounter;
363 
365  Common::List<EVENT *> _events;
366 
367 #ifdef DEBUG
368 
369  int numProcs;
370  int maxProcs;
371 
376  void checkStack();
377 #endif
378 
383  VFPTRPP pRCfunction;
384 
385  PROCESS *getProcess(uint32 pid);
386  EVENT *getEvent(uint32 pid);
387 public:
391  void reset();
392 
393 #ifdef DEBUG
394 
397  void printStats();
398 #endif
399 
403  void schedule();
404 
408  void rescheduleAll();
409 
414  void reschedule(PPROCESS pReSchedProc = nullptr);
415 
421  void giveWay(PPROCESS pReSchedProc = nullptr);
422 
430  void waitForSingleObject(CORO_PARAM, int pid, uint32 duration, bool *expired = nullptr);
431 
441  void waitForMultipleObjects(CORO_PARAM, int nCount, uint32 *pidList, bool bWaitAll,
442  uint32 duration, bool *expired = nullptr);
443 
451  void sleep(CORO_PARAM, uint32 duration);
452 
461  PROCESS *createProcess(uint32 pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam);
462 
470  uint32 createProcess(CORO_ADDR coroAddr, const void *pParam, int sizeParam);
471 
478  uint32 createProcess(CORO_ADDR coroAddr, const void *pParam);
479 
485  void killProcess(PROCESS *pKillProc);
486 
490  PROCESS *getCurrentProcess();
491 
495  int getCurrentPID() const;
496 
505  int killMatchingProcess(uint32 pidKill, int pidMask = -1);
506 
516  void setResourceCallback(VFPTRPP pFunc);
517 
530  uint32 createEvent(bool bManualReset, bool bInitialState);
531 
536  void closeEvent(uint32 pidEvent);
537 
542  void setEvent(uint32 pidEvent);
543 
548  void resetEvent(uint32 pidEvent);
549 
559  void pulseEvent(uint32 pidEvent);
560 };
561 
566 } // end of namespace Common
567 
568 #endif // COMMON_COROUTINES_H
CoroContext state
State of the coroutine.
Definition: coroutines.h:304
Definition: coroutines.h:319
Definition: list.h:44
void(* CORO_ADDR)(CoroContext &, const void *)
Definition: coroutines.h:297
Definition: coroutines.h:330
PROCESS * pPrevious
Pointer to the previous process in an active or free list.
Definition: coroutines.h:302
CoroContext nullContext
CoroBaseContext(const char *func)
PROCESS * pNext
Pointer to the next process in an active or free list.
Definition: coroutines.h:301
#define CORO_PARAM
Definition: coroutines.h:107
Definition: coroutines.h:300
Definition: algorithm.h:29
int sleepTime
Number of scheduler cycles to sleep.
Definition: coroutines.h:307
uint32 pid
Process ID.
Definition: coroutines.h:308
Definition: coroutines.h:54
#define CORO_PARAM_SIZE
Definition: coroutines.h:286
Definition: coroutines.h:90
CORO_ADDR coroAddr
Entry point of the coroutine.
Definition: coroutines.h:305
Definition: singleton.h:42