From 69dac1d4f22f9a63a5a9030d4405ba071e5e8b89 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 24 Jul 2008 08:59:17 +0000 Subject: Moved scheduler / process managment code into a new class Scheduler svn-id: r33259 --- engines/tinsel/coroutine.h | 69 ++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'engines/tinsel/coroutine.h') diff --git a/engines/tinsel/coroutine.h b/engines/tinsel/coroutine.h index 4a8997fe00..e0292735bb 100644 --- a/engines/tinsel/coroutine.h +++ b/engines/tinsel/coroutine.h @@ -30,15 +30,36 @@ namespace Tinsel { -// The following is loosely based on , -// Proper credit to Simon Tatham shall be given. - /* + * The following is loosely based on an article by Simon Tatham: + * . + * However, many improvements and tweaks have been made, in particular + * by taking advantage of C++ features not available in C. + * + * Why is this code here? Well, the Tinsel engine apparently used + * setjmp/longjmp based coroutines as a core tool from the start, and + * so they are deeply ingrained into the whole code base. When we + * started to get Tinsel ready for ScummVM, we had to deal with that. + * It soon got clear that we could not simply rewrite the code to work + * without some form of coroutines. While possible in principle, it + * would have meant a major restructuring of the entire code base, a + * rather daunting task. Also, it would have very likely introduced + * tons of regressons. + * + * So instead of getting rid of the coroutines, we chose to implement + * them in an alternate way, using Simon Tatham's trick as described + * above. While the trick is dirty, the result seems to be clear enough, + * we hope; plus, it allowed us to stay relatively close to the + * original structure of the code, which made it easier to avoid + * regressions, and will be helpful in the future when comparing things + * against the original code base. + */ - * `ccr' macros for re-entrant coroutines. +/** + * The core of any coroutine context which captures the 'state' of a coroutine. + * Private use only */ - struct CoroBaseContext { int _line; int _sleep; @@ -53,16 +74,28 @@ typedef CoroBaseContext *CoroContext; /** * Wrapper class which holds a pointer to a pointer to a CoroBaseContext. * The interesting part is the destructor, which kills the context being held, - * but ONLY if the _sleep val of that context is zero. + * but ONLY if the _sleep val of that context is zero. This way, a coroutine + * can just 'return' w/o having to worry about freeing the allocated context + * (in Simon Tatham's original code, one had to use a special macro to + * return from a coroutine). */ -struct CoroContextHolder { +class CoroContextHolder { CoroContext &_ctx; +public: CoroContextHolder(CoroContext &ctx) : _ctx(ctx) {} - ~CoroContextHolder() { if (_ctx && _ctx->_sleep == 0) { delete _ctx; _ctx = 0; } } + ~CoroContextHolder() { + if (_ctx && _ctx->_sleep == 0) { + delete _ctx; + _ctx = 0; + } + } }; + #define CORO_PARAM CoroContext &coroParam +#define CORO_SUBCTX coroParam->_subctx + #define CORO_BEGIN_CONTEXT struct CoroContextTag : CoroBaseContext { int DUMMY #define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam @@ -80,19 +113,18 @@ struct CoroContextHolder { #define CORO_SLEEP(delay) \ do {\ - coroParam->_line=__LINE__;\ - coroParam->_sleep=delay;\ + coroParam->_line = __LINE__;\ + coroParam->_sleep = delay;\ return; case __LINE__:;\ } while (0) -// Stop the currently running coroutine +/** Stop the currently running coroutine */ #define CORO_KILL_SELF() do { coroParam->_sleep = -1; return; } while(0) -//#define CORO_ABORT() do { delete (ctx); ctx = 0; } while (0) - +/** Invoke another coroutine */ #define CORO_INVOKE_ARGS(subCoro, ARGS) \ do {\ - coroParam->_line=__LINE__;\ + coroParam->_line = __LINE__;\ coroParam->_subctx = 0;\ do {\ subCoro ARGS;\ @@ -102,21 +134,12 @@ struct CoroContextHolder { } while(1);\ } while (0) -#define CORO_SUBCTX coroParam->_subctx - #define CORO_INVOKE_0(subCoroutine) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX)) #define CORO_INVOKE_1(subCoroutine, a0) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0)) #define CORO_INVOKE_2(subCoroutine, a0,a1) \ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1)) -#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2)) -#define CORO_INVOKE_4(subCoroutine, a0,a1,a2,a3) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3)) -#define CORO_INVOKE_5(subCoroutine, a0,a1,a2,a3,a4) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2,a3,a4)) - } // end of namespace Tinsel -- cgit v1.2.3