From 3570a0153dfa1034fc8acece5f755038487a5886 Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Tue, 28 Aug 2012 09:19:10 +0200 Subject: TONY: Improve Take/ReleaseOwnership. This releases all held 'mutexes' when processes die, and keeps track of the lock count too, just in case. --- engines/tony/custom.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++---- engines/tony/globals.cpp | 1 - engines/tony/globals.h | 10 +++++++++- engines/tony/tony.cpp | 1 + 4 files changed, 55 insertions(+), 6 deletions(-) (limited to 'engines/tony') diff --git a/engines/tony/custom.cpp b/engines/tony/custom.cpp index fcb304c623..3031fc342b 100644 --- a/engines/tony/custom.cpp +++ b/engines/tony/custom.cpp @@ -2052,12 +2052,39 @@ DECLARE_CUSTOM_FUNCTION(StartDialog)(CORO_PARAM, uint32 nDialog, uint32 nStartGr */ DECLARE_CUSTOM_FUNCTION(TakeOwnership)(CORO_PARAM, uint32 num, uint32, uint32, uint32) { - // The event is operating as a mutex, so if the event is already set, wait until it's reset - CoroScheduler.waitForSingleObject(coroParam, GLOBALS._mut[num], CORO_INFINITE); + CORO_BEGIN_CONTEXT; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + if (GLOBALS._mut[num]._ownerPid != (uint32)CoroScheduler.getCurrentPID()) { + // The mutex is currently owned by a different process. + // Wait for the event to be signalled, which means the mutex is free. + CORO_INVOKE_2(CoroScheduler.waitForSingleObject, GLOBALS._mut[num]._eventId, CORO_INFINITE); + GLOBALS._mut[num]._ownerPid = (uint32)CoroScheduler.getCurrentPID(); + } + + GLOBALS._mut[num]._lockCount++; + + CORO_END_CODE; } DECLARE_CUSTOM_FUNCTION(ReleaseOwnership)(CORO_PARAM, uint32 num, uint32, uint32, uint32) { - CoroScheduler.setEvent(GLOBALS._mut[num]); + if (!GLOBALS._mut[num]._lockCount) { + warning("ReleaseOwnership tried to release mutex %d, which isn't held", num); + return; + } + + if (GLOBALS._mut[num]._ownerPid != (uint32)CoroScheduler.getCurrentPID()) + error("ReleaseOwnership tried to release mutex %d, which is held by a different process", num); + + GLOBALS._mut[num]._lockCount--; + if (!GLOBALS._mut[num]._lockCount) { + GLOBALS._mut[num]._ownerPid = 0; + + // Signal the event, to wake up processes waiting for the lock. + CoroScheduler.setEvent(GLOBALS._mut[num]._eventId); + } } /* @@ -2524,6 +2551,19 @@ ASSIGN(201, MustSkipIdleEnd); END_CUSTOM_FUNCTION_MAP() +void processKilledCallback(Common::PROCESS *p) { + for (uint i = 0; i < 10; i++) + if (GLOBALS._mut[i]._ownerPid == p->pid) { + // Handle scripts which don't call ReleaseOwnership, such as + // the one in loc37's vEnter when Tony is chasing the mouse. + debug(DEBUG_BASIC, "Force-releasing mutex %d after process died", i); + + GLOBALS._mut[i]._ownerPid = 0; + GLOBALS._mut[i]._lockCount = 0; + CoroScheduler.setEvent(GLOBALS._mut[i]._eventId); + } +} + void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation *loc, RMInventory *inv, RMInput *input) { GLOBALS._tony = tony; GLOBALS._pointer = ptr; @@ -2549,8 +2589,9 @@ void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation GLOBALS._bAlwaysDisplay = false; int i; + CoroScheduler.setResourceCallback(processKilledCallback); for (i = 0; i < 10; i++) - GLOBALS._mut[i] = CoroScheduler.createEvent(false, true); + GLOBALS._mut[i]._eventId = CoroScheduler.createEvent(false, true); for (i = 0; i < 200; i++) GLOBALS._ambiance[i] = 0; diff --git a/engines/tony/globals.cpp b/engines/tony/globals.cpp index ba2698a50b..dd35d8c5ec 100644 --- a/engines/tony/globals.cpp +++ b/engines/tony/globals.cpp @@ -67,7 +67,6 @@ Globals::Globals() { _curSoundEffect = 0; _bFadeOutStop = false; - Common::fill(&_mut[0], &_mut[10], 0); _bSkipIdle = false; _hSkipIdle = 0; _lastMusic = 0; diff --git a/engines/tony/globals.h b/engines/tony/globals.h index 02bd79eee7..483ced1817 100644 --- a/engines/tony/globals.h +++ b/engines/tony/globals.h @@ -155,6 +155,14 @@ typedef CFCALL *LPCFCALL; typedef LPCFCALL *LPLPCFCALL; +struct CoroutineMutex { + CoroutineMutex() : _eventId(0), _ownerPid(0), _lockCount(0) { } + + uint32 _eventId; + uint32 _ownerPid; + uint32 _lockCount; +}; + /****************************************************************************\ * Global variables \****************************************************************************/ @@ -236,7 +244,7 @@ public: RMTony::CharacterTalkType _nTonyNextTalkType; RMPoint _startLocPos[256]; - uint32 _mut[10]; + CoroutineMutex _mut[10]; bool _bSkipIdle; uint32 _hSkipIdle; diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp index b0ca074c16..b9d12beb11 100644 --- a/engines/tony/tony.cpp +++ b/engines/tony/tony.cpp @@ -89,6 +89,7 @@ TonyEngine::~TonyEngine() { // Reset the coroutine scheduler CoroScheduler.reset(); + CoroScheduler.setResourceCallback(NULL); delete _debugger; } -- cgit v1.2.3