ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

coroutines.h

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifndef COMMON_COROUTINES_H
00024 #define COMMON_COROUTINES_H
00025 
00026 #include "common/scummsys.h"
00027 #include "common/util.h"    // for SCUMMVM_CURRENT_FUNCTION
00028 #include "common/list.h"
00029 #include "common/singleton.h"
00030 
00031 namespace Common {
00032 
00042 
00043 #define CoroScheduler (Common::CoroutineScheduler::instance())
00044 
00045 
00046 // Enable this macro to enable some debugging support in the coroutine code.
00047 //#define COROUTINE_DEBUG
00048 
00053 struct CoroBaseContext {
00054     int _line;
00055     int _sleep;
00056     CoroBaseContext *_subctx;
00057 #ifdef COROUTINE_DEBUG
00058     const char *_funcName;
00059 #endif
00060 
00063     CoroBaseContext(const char *func);
00064 
00068     virtual ~CoroBaseContext();
00069 };
00070 
00071 typedef CoroBaseContext *CoroContext;
00072 
00073 
00079 extern CoroContext nullContext;
00080 
00089 class CoroContextHolder {
00090     CoroContext &_ctx;
00091 public:
00092     CoroContextHolder(CoroContext &ctx) : _ctx(ctx) {
00093         assert(ctx);
00094         assert(ctx->_sleep >= 0);
00095         ctx->_sleep = 0;
00096     }
00097     ~CoroContextHolder() {
00098         if (_ctx && _ctx->_sleep == 0) {
00099             delete _ctx;
00100             _ctx = nullptr;
00101         }
00102     }
00103 };
00104 
00106 #define CORO_PARAM    Common::CoroContext &coroParam
00107 
00108 
00130 #define CORO_BEGIN_CONTEXT  \
00131     struct CoroContextTag : Common::CoroBaseContext { \
00132  CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) { DUMMY = 0; } \
00133         int DUMMY
00134 
00140 #define CORO_END_CONTEXT(x)    } *x = (CoroContextTag *)coroParam
00141 
00147 #define CORO_BEGIN_CODE(x) \
00148     if (&coroParam == &Common::nullContext) assert(!Common::nullContext); \
00149     if (!x) { coroParam = x = new CoroContextTag(); } \
00150     x->DUMMY = 0; \
00151     Common::CoroContextHolder tmpHolder(coroParam); \
00152     switch (coroParam->_line) { case 0:;
00153 
00158 #define CORO_END_CODE \
00159     if (&coroParam == &Common::nullContext) { \
00160         delete Common::nullContext; \
00161         Common::nullContext = NULL; \
00162     } \
00163     }
00164 
00168 #define CORO_SLEEP(delay) \
00169     do { \
00170         coroParam->_line = __LINE__; \
00171         coroParam->_sleep = delay; \
00172         assert(&coroParam != &Common::nullContext); \
00173         return; case __LINE__:; \
00174     } while (0)
00175 
00176 #define CORO_GIVE_WAY do { CoroScheduler.giveWay(); CORO_SLEEP(1); } while (0)
00177 #define CORO_RESCHEDULE do { CoroScheduler.reschedule(); CORO_SLEEP(1); } while (0)
00178 
00187 #define CORO_KILL_SELF() \
00188     do { if (&coroParam != &Common::nullContext) { coroParam->_sleep = -1; } return; } while (0)
00189 
00190 
00195 #define CORO_SUBCTX   coroParam->_subctx
00196 
00217 #define CORO_INVOKE_ARGS(subCoro, ARGS) \
00218     do { \
00219         coroParam->_line = __LINE__; \
00220         coroParam->_subctx = 0; \
00221         do { \
00222             subCoro ARGS; \
00223             if (!coroParam->_subctx) break; \
00224             coroParam->_sleep = coroParam->_subctx->_sleep; \
00225             assert(&coroParam != &Common::nullContext); \
00226             return; case __LINE__:; \
00227         } while (1); \
00228     } while (0)
00229 
00236 #define CORO_INVOKE_ARGS_V(subCoro, RESULT, ARGS) \
00237     do { \
00238         coroParam->_line = __LINE__; \
00239         coroParam->_subctx = 0; \
00240         do { \
00241             subCoro ARGS; \
00242             if (!coroParam->_subctx) break; \
00243             coroParam->_sleep = coroParam->_subctx->_sleep; \
00244             assert(&coroParam != &Common::nullContext); \
00245             return RESULT; case __LINE__:; \
00246         } while (1); \
00247     } while (0)
00248 
00253 #define CORO_INVOKE_0(subCoroutine) \
00254     CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX))
00255 
00260 #define CORO_INVOKE_1(subCoroutine, a0) \
00261     CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0))
00262 
00267 #define CORO_INVOKE_2(subCoroutine, a0,a1) \
00268     CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1))
00269 
00274 #define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \
00275     CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1, a2))
00276 
00281 #define CORO_INVOKE_4(subCoroutine, a0,a1,a2,a3) \
00282     CORO_INVOKE_ARGS(subCoroutine, (CORO_SUBCTX, a0, a1, a2, a3))
00283 
00284 
00285 
00286 // the size of process specific info
00287 #define CORO_PARAM_SIZE 32
00288 
00289 // the maximum number of processes
00290 #define CORO_NUM_PROCESS    100
00291 #define CORO_MAX_PROCESSES  100
00292 #define CORO_MAX_PID_WAITING 5
00293 
00294 #define CORO_INFINITE 0xffffffff
00295 #define CORO_INVALID_PID_VALUE 0
00296 
00298 typedef void (*CORO_ADDR)(CoroContext &, const void *);
00299 
00301 struct PROCESS {
00302     PROCESS *pNext;     
00303     PROCESS *pPrevious; 
00304 
00305     CoroContext state;      
00306     CORO_ADDR  coroAddr;    
00307 
00308     int sleepTime;      
00309     uint32 pid;         
00310     uint32 pidWaiting[CORO_MAX_PID_WAITING];    
00311     char param[CORO_PARAM_SIZE];    
00312 };
00313 typedef PROCESS *PPROCESS;
00314 
00315 
00317 struct EVENT {
00318     uint32 pid;
00319     bool manualReset;
00320     bool signalled;
00321     bool pulsing;
00322 };
00323 
00324 
00328 class CoroutineScheduler : public Singleton<CoroutineScheduler> {
00329 public:
00331     typedef void (*VFPTRPP)(PROCESS *);
00332 
00333 private:
00334     friend class Singleton<CoroutineScheduler>;
00335 
00339     CoroutineScheduler();
00340 
00344     ~CoroutineScheduler();
00345 
00346 
00348     PROCESS *processList;
00349 
00351     PROCESS *active;
00352 
00354     PROCESS *pFreeProcesses;
00355 
00357     PROCESS *pCurrent;
00358 
00360     int pidCounter;
00361 
00363     Common::List<EVENT *> _events;
00364 
00365 #ifdef DEBUG
00366     // diagnostic process counters
00367     int numProcs;
00368     int maxProcs;
00369 
00374     void checkStack();
00375 #endif
00376 
00381     VFPTRPP pRCfunction;
00382 
00383     PROCESS *getProcess(uint32 pid);
00384     EVENT *getEvent(uint32 pid);
00385 public:
00389     void reset();
00390 
00391 #ifdef DEBUG
00392 
00395     void printStats();
00396 #endif
00397 
00401     void schedule();
00402 
00406     void rescheduleAll();
00407 
00412     void reschedule(PPROCESS pReSchedProc = nullptr);
00413 
00419     void giveWay(PPROCESS pReSchedProc = nullptr);
00420 
00428     void waitForSingleObject(CORO_PARAM, int pid, uint32 duration, bool *expired = nullptr);
00429 
00439     void waitForMultipleObjects(CORO_PARAM, int nCount, uint32 *pidList, bool bWaitAll,
00440                                 uint32 duration, bool *expired = nullptr);
00441 
00449     void sleep(CORO_PARAM, uint32 duration);
00450 
00459     PROCESS *createProcess(uint32 pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam);
00460 
00468     uint32 createProcess(CORO_ADDR coroAddr, const void *pParam, int sizeParam);
00469 
00476     uint32 createProcess(CORO_ADDR coroAddr, const void *pParam);
00477 
00483     void killProcess(PROCESS *pKillProc);
00484 
00488     PROCESS *getCurrentProcess();
00489 
00493     int getCurrentPID() const;
00494 
00503     int killMatchingProcess(uint32 pidKill, int pidMask = -1);
00504 
00514     void setResourceCallback(VFPTRPP pFunc);
00515 
00516     /* Event methods */
00526     uint32 createEvent(bool bManualReset, bool bInitialState);
00527 
00532     void closeEvent(uint32 pidEvent);
00533 
00538     void setEvent(uint32 pidEvent);
00539 
00544     void resetEvent(uint32 pidEvent);
00545 
00555     void pulseEvent(uint32 pidEvent);
00556 };
00557 
00559 
00560 } // end of namespace Common
00561 
00562 #endif // COMMON_COROUTINES_H


Generated on Sat Dec 14 2019 05:00:32 for ResidualVM by doxygen 1.7.1
curved edge   curved edge