diff options
author | Yotam Barnoy | 2010-06-15 13:10:00 +0000 |
---|---|---|
committer | Yotam Barnoy | 2010-06-15 13:10:00 +0000 |
commit | a21b9c7b96a29d3be9285b4217e91f835fed31ec (patch) | |
tree | bb58c2221ce5631d98bddd354cc2ba715493c159 /backends | |
parent | 891b568fde51c7f1732c86fd34cc40efcd4314ce (diff) | |
download | scummvm-rg350-a21b9c7b96a29d3be9285b4217e91f835fed31ec.tar.gz scummvm-rg350-a21b9c7b96a29d3be9285b4217e91f835fed31ec.tar.bz2 scummvm-rg350-a21b9c7b96a29d3be9285b4217e91f835fed31ec.zip |
PSP: fixed up PowerManager and removed dependency on SDL
svn-id: r49852
Diffstat (limited to 'backends')
-rw-r--r-- | backends/fs/psp/psp-stream.cpp | 14 | ||||
-rw-r--r-- | backends/platform/psp/powerman.cpp | 352 | ||||
-rw-r--r-- | backends/platform/psp/powerman.h | 75 | ||||
-rw-r--r-- | backends/platform/psp/thread.cpp | 56 | ||||
-rw-r--r-- | backends/platform/psp/thread.h | 20 |
5 files changed, 232 insertions, 285 deletions
diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp index 83ff095aa8..67c73beeaa 100644 --- a/backends/fs/psp/psp-stream.cpp +++ b/backends/fs/psp/psp-stream.cpp @@ -81,10 +81,10 @@ PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode) PSPIoStream::~PSPIoStream() { DEBUG_ENTER_FUNC(); - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) + if (PowerMan.beginCriticalSection()) PSP_DEBUG_PRINT_FUNC("Suspended\n"); - PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended + PowerMan.unregisterForSuspend(this); // Unregister with powermanager to be suspended // Must do this before fclose() or resume() will reopen. fclose((FILE *)_handle); // We don't need a critical section. Worst case, the handle gets closed on its own @@ -100,7 +100,7 @@ PSPIoStream::~PSPIoStream() { */ void *PSPIoStream::open() { DEBUG_ENTER_FUNC(); - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) { + if (PowerMan.beginCriticalSection()) { // No need to open. Just return the _handle resume() already opened. PSP_DEBUG_PRINT_FUNC("Suspended\n"); } @@ -118,7 +118,7 @@ void *PSPIoStream::open() { _cache = (char *)memalign(64, CACHE_SIZE); } - PowerMan.registerSuspend(this); // Register with the powermanager to be suspended + PowerMan.registerForSuspend(this); // Register with the powermanager to be suspended PowerMan.endCriticalSection(); @@ -233,7 +233,7 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { } } - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) + if (PowerMan.beginCriticalSection()) PSP_DEBUG_PRINT_FUNC("Suspended\n"); @@ -309,7 +309,7 @@ inline bool PSPIoStream::isOffsetInCache(uint32 offset) { uint32 PSPIoStream::write(const void *ptr, uint32 len) { DEBUG_ENTER_FUNC(); // Check if we can access the file - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) + if (PowerMan.beginCriticalSection()) PSP_DEBUG_PRINT_FUNC("Suspended\n"); PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x]\n", _path.c_str(), len); @@ -346,7 +346,7 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) { bool PSPIoStream::flush() { DEBUG_ENTER_FUNC(); // Enter critical section - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) + if (PowerMan.beginCriticalSection()) PSP_DEBUG_PRINT_FUNC("Suspended\n"); int ret = fflush((FILE *)_handle); diff --git a/backends/platform/psp/powerman.cpp b/backends/platform/psp/powerman.cpp index df8da12f6d..eaadad16c5 100644 --- a/backends/platform/psp/powerman.cpp +++ b/backends/platform/psp/powerman.cpp @@ -23,16 +23,16 @@ * */ -//#define __PSP_DEBUG_FUNCS__ /* can put this locally too */ -//#define __PSP_DEBUG_PRINT__ -#include "backends/platform/psp/trace.h" - #include <psppower.h> #include <pspthreadman.h> #include "backends/platform/psp/powerman.h" #include "engine.h" +//#define __PSP_DEBUG_FUNCS__ /* can put this locally too */ +//#define __PSP_DEBUG_PRINT__ +#include "backends/platform/psp/trace.h" + DECLARE_SINGLETON(PowerManager) // Function to debug the Power Manager (we have no output to screen) @@ -47,68 +47,30 @@ inline void PowerManager::debugPM() { * Constructor * ********************************************/ -PowerManager::PowerManager() { - DEBUG_ENTER_FUNC(); - - _flagMutex = NULL; /* Init mutex handle */ - _listMutex = NULL; /* Init mutex handle */ - _condSuspendable = NULL; /* Init condition variable */ - _condPM = NULL; - - _condSuspendable = SDL_CreateCond(); - if (_condSuspendable <= 0) { - PSP_ERROR("Couldn't create Suspendable condition variable\n"); - } - - _condPM = SDL_CreateCond(); - if (_condPM <= 0) { - PSP_ERROR("Couldn't create PM condition variable\n"); - } - - _flagMutex = SDL_CreateMutex(); - if (_flagMutex <= 0) { - PSP_ERROR("Couldn't create flag Mutex\n"); - } - - _listMutex = SDL_CreateMutex(); - if (_listMutex <= 0) { - PSP_ERROR("Couldn't create list Mutex\n"); - } - - _suspendFlag = false; - _criticalCounter = 0; // How many are in the critical section - _pauseFlag = 0; - _pauseFlagOld = 0; - _pauseClientState = 0; - _listCounter = 0; - PMStatusSet(kInitDone); - _error = 0; -} +PowerManager::PowerManager() : _pauseFlag(false), _pauseFlagOld(false), _pauseClientState(UNPAUSED), + _suspendFlag(false), _flagMutex(true), _listMutex(true), + _criticalCounter(0), _listCounter(0), _error(0), _PMStatus(kInitDone) {} /******************************************* * * Function to register to be notified when suspend/resume time comes * ********************************************/ -int PowerManager::registerSuspend(Suspendable *item) { +bool PowerManager::registerForSuspend(Suspendable *item) { DEBUG_ENTER_FUNC(); // Register in list debugPM(); - if (SDL_mutexP(_listMutex) != 0) { - PSP_ERROR("Couldn't lock _listMutex[%p]\n", _listMutex); - } + _listMutex.lock(); _suspendList.push_front(item); _listCounter++; - if (SDL_mutexV(_listMutex) != 0) { - PSP_ERROR("Couldn't unlock _listMutex[%p]\n", _listMutex); - } + _listMutex.unlock(); debugPM(); - return 0; + return true; } /******************************************* @@ -116,26 +78,20 @@ int PowerManager::registerSuspend(Suspendable *item) { * Function to unregister to be notified when suspend/resume time comes * ********************************************/ -int PowerManager::unregisterSuspend(Suspendable *item) { +bool PowerManager::unregisterForSuspend(Suspendable *item) { DEBUG_ENTER_FUNC(); debugPM(); // Unregister from stream list - if (SDL_mutexP(_listMutex) != 0) { - PSP_ERROR("Couldn't unlock _listMutex[%p]\n", _listMutex); - } - + _listMutex.lock(); + _suspendList.remove(item); _listCounter--; - if (SDL_mutexV(_listMutex) != 0) { - PSP_ERROR("Couldn't unlock _listMutex[%p]\n", _listMutex); - } + _listMutex.unlock(); - PSP_DEBUG_PRINT("Out of unregisterSuspend\n"); debugPM(); - - return 0; + return true; } /******************************************* @@ -144,21 +100,7 @@ int PowerManager::unregisterSuspend(Suspendable *item) { * ********************************************/ PowerManager::~PowerManager() { - DEBUG_ENTER_FUNC(); - - PMStatusSet(kDestroyPM); - - SDL_DestroyCond(_condSuspendable); - _condSuspendable = 0; - - SDL_DestroyCond(_condPM); - _condPM = 0; - - SDL_DestroyMutex(_flagMutex); - _flagMutex = 0; - - SDL_DestroyMutex(_listMutex); - _listMutex = 0; + _PMStatus = kDestroyPM; } /******************************************* @@ -171,114 +113,92 @@ PowerManager::~PowerManager() { * ********************************************/ void PowerManager::pollPauseEngine() { - + DEBUG_ENTER_FUNC(); + + bool pause = _pauseFlag; // We copy so as not to have multiple values - if ((pause != _pauseFlagOld) && g_engine) { // Check to see if we have an engine - if (pause && _pauseClientState == PowerManager::Unpaused) { - _pauseClientState = PowerManager::Pausing; // Tell PM we're in the middle of pausing - g_engine->pauseEngine(true); - PSP_DEBUG_PRINT_FUNC("Pausing engine\n"); - _pauseClientState = PowerManager::Paused; // Tell PM we're done pausing - } else if (!pause && _pauseClientState == PowerManager::Paused) { - g_engine->pauseEngine(false); - PSP_DEBUG_PRINT_FUNC("Unpausing for resume\n"); - _pauseClientState = PowerManager::Unpaused; // Tell PM we're in the middle of pausing + if (pause != _pauseFlagOld) { + if (g_engine) { // Check to see if we have an engine + if (pause && _pauseClientState == UNPAUSED) { + _pauseClientState = PAUSING; // Tell PM we're in the middle of pausing + g_engine->pauseEngine(true); + PSP_DEBUG_PRINT_FUNC("Pausing engine\n"); + _pauseClientState = PAUSED; // Tell PM we're done pausing + } else if (!pause && _pauseClientState == PAUSED) { + g_engine->pauseEngine(false); + PSP_DEBUG_PRINT_FUNC("Unpausing for resume\n"); + _pauseClientState = UNPAUSED; // Tell PM we're unpaused + } } - _pauseFlagOld = pause; } } /******************************************* * -* Function to be called by threads wanting to block on the PSP entering suspend -* Use this for small critical sections where you can easily restore the previous state. -* -********************************************/ -int PowerManager::blockOnSuspend() { - return beginCriticalSection(true); -} - -/******************************************* -* * Function to block on a suspend, then start a non-suspendable critical section * Use this for large or REALLY critical critical-sections. * Make sure to call endCriticalSection or the PSP won't suspend. +* returns true if blocked, false if not blocked ********************************************/ -int PowerManager::beginCriticalSection(bool justBlock) { +bool PowerManager::beginCriticalSection() { DEBUG_ENTER_FUNC(); - int ret = NotBlocked; - - if (SDL_mutexP(_flagMutex) != 0) { - PSP_ERROR("PowerManager::blockOnSuspend(): Couldn't lock flagMutex[%p]\n", _flagMutex); - ret = Error; - } + bool ret = false; + + _flagMutex.lock(); // Check the access flag - if (_suspendFlag == true) { - PSP_DEBUG_PRINT("We're being blocked!\n"); - debugPM(); - ret = Blocked; + if (_suspendFlag) { + ret = true; - // If it's true, we wait for a signal to continue - if (SDL_CondWait(_condSuspendable, _flagMutex) != 0) { - PSP_DEBUG_PRINT("PowerManager::blockOnSuspend(): Couldn't wait on cond[%p]\n", _condSuspendable); - } + PSP_DEBUG_PRINT("I got blocked. ThreadId[%x]\n", sceKernelGetThreadId()); + debugPM(); + + _threadSleep.wait(_flagMutex); - PSP_DEBUG_PRINT("We got blocked!!\n"); + PSP_DEBUG_PRINT_FUNC("I got released. ThreadId[%x]\n", sceKernelGetThreadId()); debugPM(); } // Now prevent the PM from suspending until we're done - if (justBlock == false) - _criticalCounter++; + _criticalCounter++; - if (SDL_mutexV(_flagMutex) != 0) { - PSP_ERROR("PowerManager::blockOnSuspend(): Couldn't unlock flagMutex[%p]\n", _flagMutex); - ret = Error; - } + _flagMutex.unlock(); return ret; } -int PowerManager::endCriticalSection() { +// returns success = true +void PowerManager::endCriticalSection() { DEBUG_ENTER_FUNC(); - int ret = 0; - if (SDL_mutexP(_flagMutex) != 0) { - PSP_ERROR("PowerManager::endCriticalSection(): Couldn't lock flagMutex[%p]\n", _flagMutex); - ret = Error; - } + _flagMutex.lock(); // We're done with our critical section _criticalCounter--; if (_criticalCounter <= 0) { - if (_suspendFlag == true) { // If the PM is sleeping, this flag must be set - PSP_DEBUG_PRINT("Unblocked thread waking up the PM.\n"); - debugPM(); - - SDL_CondBroadcast(_condPM); - - PSP_DEBUG_PRINT("Woke up the PM\n"); - debugPM(); + if (_suspendFlag) { // If the PM is sleeping, this flag must be set + PSP_DEBUG_PRINT_FUNC("PM is asleep. Waking it up.\n"); + debugPM(); + + _pmSleep.releaseAll(); + + PSP_DEBUG_PRINT_FUNC("Woke up the PM\n"); + + debugPM(); } if (_criticalCounter < 0) { // Check for bad usage of critical sections - PSP_ERROR("Critical counter[%d]\n", _criticalCounter); + PSP_ERROR("Critical counter[%d]!!!\n", _criticalCounter); debugPM(); } } - if (SDL_mutexV(_flagMutex) != 0) { - PSP_ERROR("Couldn't unlock flagMutex[%p]\n", _flagMutex); - ret = Error; - } - - return ret; + _flagMutex.unlock(); } /******************************************* @@ -286,90 +206,77 @@ int PowerManager::endCriticalSection() { * Callback function to be called to put every Suspendable to suspend * ********************************************/ -int PowerManager::suspend() { +void PowerManager::suspend() { DEBUG_ENTER_FUNC(); - int ret = 0; - if (_pauseFlag) return ret; // Very important - make sure we only suspend once + if (_pauseFlag) + return; // Very important - make sure we only suspend once - scePowerLock(0); // Critical to make sure PSP doesn't suspend before we're done + scePowerLock(0); // Also critical to make sure PSP doesn't suspend before we're done // The first stage of suspend is pausing the engine if possible. We don't want to cause files // to block, or we might not get the engine to pause. On the other hand, we might wait for polling // and it'll never happen. We also want to do this w/o mutexes (for speed) which is ok in this case. _pauseFlag = true; - PMStatusSet(kWaitForClientPause); + _PMStatus = kWaitForClientPause; // Now we wait, giving the engine thread some time to find our flag. - for (int i = 0; i < 10 && _pauseClientState == Unpaused; i++) - sceKernelDelayThread(50000); // We wait 50 msec x 10 times = 0.5 seconds + for (int i = 0; i < 10 && _pauseClientState == UNPAUSED; i++) + PspThread::delayMicros(50000); // We wait 50 msec x 10 times = 0.5 seconds - if (_pauseClientState == Pausing) { // Our event has been acknowledged. Let's wait until the client is done. - PMStatusSet(kWaitForClientToFinishPausing); + if (_pauseClientState == PAUSING) { // Our event has been acknowledged. Let's wait until the client is done. + _PMStatus = kWaitForClientToFinishPausing; - while (_pauseClientState != Paused) - sceKernelDelayThread(50000); // We wait 50 msec at a time + while (_pauseClientState != PAUSED) + PspThread::delayMicros(50000); // We wait 50 msec at a time } - // It's possible that the polling thread missed our pause event, but there's nothing we can do about that. - // We can't know if there's polling going on or not. It's usually not a critical thing anyway. + // It's possible that the polling thread missed our pause event, but there's + // nothing we can do about that. + // We can't know if there's polling going on or not. + // It's usually not a critical thing anyway. - PMStatusSet(kGettingFlagMutexSuspend); + _PMStatus = kGettingFlagMutexSuspend; // Now we set the suspend flag to true to cause reading threads to block + _flagMutex.lock(); - if (SDL_mutexP(_flagMutex) != 0) { - PSP_ERROR("Couldn't lock flagMutex[%p]\n", _flagMutex); - _error = Error; - ret = Error; - } - - PMStatusSet(kGotFlagMutexSuspend); + _PMStatus = kGotFlagMutexSuspend; _suspendFlag = true; // Check if anyone is in a critical section. If so, we'll wait for them if (_criticalCounter > 0) { - PMStatusSet(kWaitCritSectionSuspend); - SDL_CondWait(_condPM, _flagMutex); - PMStatusSet(kDoneWaitingCritSectionSuspend); - } + _PMStatus = kWaitCritSectionSuspend; + + _pmSleep.wait(_flagMutex); + + _PMStatus = kDoneWaitingCritSectionSuspend; + } + + _flagMutex.unlock(); - if (SDL_mutexV(_flagMutex) != 0) { - PSP_ERROR("Couldn't unlock flagMutex[%p]\n", _flagMutex); - _error = Error; - ret = Error; - } - - PMStatusSet(kGettingListMutexSuspend); + _PMStatus = kGettingListMutexSuspend; // Loop over list, calling suspend() - if (SDL_mutexP(_listMutex) != 0) { - PSP_ERROR("Couldn't lock listMutex[%p]\n", _listMutex); - _error = Error; - ret = Error; - } - PMStatusSet(kIteratingListSuspend); + _listMutex.lock(); + + _PMStatus = kIteratingListSuspend; // Iterate Common::List<Suspendable *>::iterator i; for (i = _suspendList.begin(); i != _suspendList.end(); ++i) { (*i)->suspend(); } + _PMStatus = kDoneIteratingListSuspend; - PMStatusSet(kDoneIteratingListSuspend); - - if (SDL_mutexV(_listMutex) != 0) { - PSP_ERROR("Couldn't unlock listMutex[%p]\n", _listMutex); - _error = Error; - ret = Error; - } - PMStatusSet(kDoneSuspend); + _listMutex.unlock(); + _PMStatus = kDoneSuspend; scePowerUnlock(0); // Allow the PSP to go to sleep now - - return ret; + + _PMStatus = kDonePowerUnlock; } /******************************************* @@ -377,24 +284,26 @@ int PowerManager::suspend() { * Callback function to resume every Suspendable * ********************************************/ -int PowerManager::resume() { +void PowerManager::resume() { DEBUG_ENTER_FUNC(); - int ret = 0; + + _PMStatus = kBeginResume; // Make sure we can't get another suspend scePowerLock(0); - if (!_pauseFlag) return ret; // Make sure we can only resume once + _PMStatus = kCheckingPauseFlag; + + if (!_pauseFlag) + return; // Make sure we can only resume once - PMStatusSet(kGettingListMutexResume); + _PMStatus = kGettingListMutexResume; // First we notify our Suspendables. Loop over list, calling resume() - if (SDL_mutexP(_listMutex) != 0) { - PSP_ERROR("Couldn't lock listMutex[%p]\n", _listMutex); - _error = Error; - ret = Error; - } - PMStatusSet(kIteratingListResume); + _listMutex.lock(); + + _PMStatus = kIteratingListResume; + // Iterate Common::List<Suspendable *>::iterator i = _suspendList.begin(); @@ -402,46 +311,31 @@ int PowerManager::resume() { (*i)->resume(); } - PMStatusSet(kDoneIteratingListResume); + _PMStatus = kDoneIteratingListResume; - if (SDL_mutexV(_listMutex) != 0) { - PSP_ERROR("Couldn't unlock listMutex[%p]\n", _listMutex); - _error = Error; - ret = Error; - } - - PMStatusSet(kGettingFlagMutexResume); + _listMutex.unlock(); + + _PMStatus = kGettingFlagMutexResume; // Now we set the suspend flag to false - if (SDL_mutexP(_flagMutex) != 0) { - PSP_ERROR("Couldn't lock flagMutex %p\n", _flagMutex); - _error = Error; - ret = Error; - } - PMStatusSet(kGotFlagMutexResume); + _flagMutex.lock(); + + _PMStatus = kGotFlagMutexResume; _suspendFlag = false; - PMStatusSet(kSignalSuspendedThreadsResume); + _PMStatus = kSignalSuspendedThreadsResume; - // Signal the other threads to wake up - if (SDL_CondBroadcast(_condSuspendable) != 0) { - PSP_ERROR("Couldn't broadcast condition[%p]\n", _condSuspendable); - _error = Error; - ret = Error; - } - PMStatusSet(kDoneSignallingSuspendedThreadsResume); + // Signal the threads to wake up + _threadSleep.releaseAll(); + + _PMStatus = kDoneSignallingSuspendedThreadsResume; - if (SDL_mutexV(_flagMutex) != 0) { - PSP_ERROR("Couldn't unlock flagMutex[%p]\n", _flagMutex); - _error = Error; - ret = Error; - } - PMStatusSet(kDoneResume); + _flagMutex.unlock(); + + _PMStatus = kDoneResume; - _pauseFlag = false; // Signal engine to unpause + _pauseFlag = false; // Signal engine to unpause -- no mutex needed scePowerUnlock(0); // Allow new suspends - - return ret; } diff --git a/backends/platform/psp/powerman.h b/backends/platform/psp/powerman.h index af3134adee..5f09bc7794 100644 --- a/backends/platform/psp/powerman.h +++ b/backends/platform/psp/powerman.h @@ -26,8 +26,7 @@ #ifndef POWERMAN_H #define POWERMAN_H -#include <SDL/SDL_thread.h> -#include <SDL/SDL_mutex.h> +#include "backends/platform/psp/thread.h" #include "common/singleton.h" #include "common/list.h" @@ -53,12 +52,12 @@ class PowerManager: public Common::Singleton<PowerManager> { public: int blockOnSuspend(); /* block if suspending */ - int beginCriticalSection(bool justBlock = false); /* Use a critical section to block (if suspend was already pressed) */ - int endCriticalSection(); /* and to prevent the PSP from suspending in a particular section */ - int registerSuspend(Suspendable *item); /* register to be called to suspend/resume */ - int unregisterSuspend(Suspendable *item); /* remove from suspend/resume list */ - int suspend(); /* callback to have all items in list suspend */ - int resume(); /* callback to have all items in list resume */ + bool beginCriticalSection(); /* Use a critical section to block (if suspend was already pressed) */ + void endCriticalSection(); /* and to prevent the PSP from suspending in a particular section */ + bool registerForSuspend(Suspendable *item); /* register to be called to suspend/resume */ + bool unregisterForSuspend(Suspendable *item); /* remove from suspend/resume list */ + void suspend(); /* callback to have all items in list suspend */ + void resume(); /* callback to have all items in list resume */ // Functions for pausing the engine void pollPauseEngine(); /* Poll whether the engine should be paused */ @@ -69,11 +68,9 @@ public: }; enum PauseState { - Unpaused = 0, - PauseEvent, - UnpauseEvent, - Pausing, - Paused + UNPAUSED = 0, + PAUSING, + PAUSED }; private: @@ -81,34 +78,38 @@ private: PowerManager(); ~PowerManager(); - Common::List<Suspendable *> _suspendList; /* list to register in */ + Common::List<Suspendable *> _suspendList; // list to register in - volatile bool _pauseFlag; /* For pausing, which is before suspending */ - volatile bool _pauseFlagOld; /* Save the last state of the flag while polling */ - volatile int _pauseClientState; /* Pause state of the target */ + volatile bool _pauseFlag; // For pausing, which is before suspending + volatile bool _pauseFlagOld; // Save the last state of the flag while polling + volatile PauseState _pauseClientState; // Pause state of the target - volatile bool _suspendFlag; /* protected variable */ - SDL_mutex *_flagMutex; /* mutex to access access flag */ - SDL_mutex *_listMutex; /* mutex to access Suspendable list */ - SDL_cond *_condSuspendable; /* signal to synchronize accessing threads */ - SDL_cond *_condPM; /* signal to wake up the PM from a critical section */ - volatile int _criticalCounter; /* Counter of how many threads are in a critical section */ - int _error; /* error code - PM can't talk to us. For debugging */ + volatile bool _suspendFlag; // protected variable + PspMutex _flagMutex; // mutex to access access flag + PspMutex _listMutex; // mutex to access Suspendable list + PspCondition _threadSleep; // signal to synchronize accessing threads + PspCondition _pmSleep; // signal to wake up the PM from a critical section + volatile int _criticalCounter; // Counter of how many threads are in a critical section + int _error; // error code - PM can't talk to us. For debugging + volatile int _PMStatus; // What the PM is doing. for debugging // States for PM to be in (used for debugging) enum PMState { - kInitDone = 1 , - kDestroyPM, - kWaitForClientPause, - kWaitForClientToFinishPausing, - kGettingFlagMutexSuspend, - kGotFlagMutexSuspend, - kWaitCritSectionSuspend, - kDoneWaitingCritSectionSuspend, - kGettingListMutexSuspend, - kIteratingListSuspend, - kDoneIteratingListSuspend, - kDoneSuspend, + kInitDone = 1, + kDestroyPM = 2, + kWaitForClientPause = 3, + kWaitForClientToFinishPausing = 4, + kGettingFlagMutexSuspend = 5, + kGotFlagMutexSuspend = 6, + kWaitCritSectionSuspend = 7, + kDoneWaitingCritSectionSuspend = 8, + kGettingListMutexSuspend = 9, + kIteratingListSuspend = 10, + kDoneIteratingListSuspend = 11, + kDoneSuspend = 12, + kDonePowerUnlock, + kBeginResume, + kCheckingPauseFlag, kGettingListMutexResume, kIteratingListResume, kDoneIteratingListResume, @@ -122,8 +123,6 @@ private: volatile int _listCounter; /* How many people are in the list - just for debugging */ void debugPM(); /* print info about the PM */ - void PMStatusSet(PMState s) { _PMStatus = s; } - volatile int _PMStatus; /* What the PM is doing */ public: int getPMStatus() const { return _PMStatus; } diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp index d20df45215..43e3b931c3 100644 --- a/backends/platform/psp/thread.cpp +++ b/backends/platform/psp/thread.cpp @@ -47,10 +47,10 @@ void PspThread::delayMicros(uint32 us) { #include "backends/platform/psp/trace.h" -PspSemaphore::PspSemaphore(int initialValue, int maxValue) { +PspSemaphore::PspSemaphore(int initialValue, int maxValue/*=255*/) { DEBUG_ENTER_FUNC(); _handle = 0; - _handle = sceKernelCreateSema("ScummVM Sema", 0 /* attr */, + _handle = (uint32)sceKernelCreateSema("ScummVM Sema", 0 /* attr */, initialValue, maxValue, 0 /*option*/); if (!_handle) @@ -60,7 +60,7 @@ PspSemaphore::PspSemaphore(int initialValue, int maxValue) { PspSemaphore::~PspSemaphore() { DEBUG_ENTER_FUNC(); if (_handle) - if (sceKernelDeleteSema(_handle) < 0) + if (sceKernelDeleteSema((SceUID)_handle) < 0) PSP_ERROR("failed to delete semaphore.\n"); } @@ -69,7 +69,7 @@ int PspSemaphore::numOfWaitingThreads() { SceKernelSemaInfo info; info.numWaitThreads = 0; - if (sceKernelReferSemaStatus(_handle, &info) < 0) + if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0) PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle); return info.numWaitThreads; @@ -80,7 +80,7 @@ int PspSemaphore::getValue() { SceKernelSemaInfo info; info.currentCount = 0; - if (sceKernelReferSemaStatus(_handle, &info) < 0) + if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0) PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle); return info.currentCount; @@ -88,7 +88,7 @@ int PspSemaphore::getValue() { bool PspSemaphore::pollForValue(int value) { DEBUG_ENTER_FUNC(); - if (sceKernelPollSema(_handle, value) < 0) + if (sceKernelPollSema((SceUID)_handle, value) < 0) return false; return true; @@ -107,10 +107,10 @@ bool PspSemaphore::takeWithTimeOut(uint32 timeOut) { return true; } -bool PspSemaphore::give(int num) { +bool PspSemaphore::give(int num /*=1*/) { DEBUG_ENTER_FUNC(); - if (sceKernelSignalSema(_handle, num) < 0) + if (sceKernelSignalSema((SceUID)_handle, num) < 0) return false; return true; } @@ -152,6 +152,46 @@ bool PspMutex::unlock() { return ret; } +// Class PspCondition ------------------------------------------------- + +// Release all threads waiting on the condition +void PspCondition::releaseAll() { + _mutex.lock(); + if (_waitingThreads > _signaledThreads) { // we have signals to issue + int numWaiting = _waitingThreads - _signaledThreads; // threads we haven't signaled + _signaledThreads = _waitingThreads; + + _waitSem.give(numWaiting); + _mutex.unlock(); + for (int i=0; i<numWaiting; i++) // wait for threads to tell us they're awake + _doneSem.take(); + } else { + _mutex.unlock(); + } +} + +// Mutex must be taken before entering wait +void PspCondition::wait(PspMutex &externalMutex) { + _mutex.lock(); + _waitingThreads++; + _mutex.unlock(); + + externalMutex.unlock(); // must unlock external mutex + + _waitSem.take(); // sleep on the wait semaphore + + // let the signaling thread know we're done + _mutex.lock(); + if (_signaledThreads > 0 ) { + _doneSem.give(); // let the thread know + _signaledThreads--; + } + _waitingThreads--; + _mutex.unlock(); + + externalMutex.lock(); // must lock external mutex here for continuation +} + //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index 33b3f6ce53..bd7a60b6ed 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -36,13 +36,13 @@ public: class PspSemaphore { private: - SceUID _handle; + uint32 _handle; public: - PspSemaphore(int initialValue, int maxValue); + PspSemaphore(int initialValue, int maxValue=255); ~PspSemaphore(); bool take() { return takeWithTimeOut(0); } bool takeWithTimeOut(uint32 timeOut); - bool give(int num); + bool give(int num=1); bool pollForValue(int value); // check for a certain value int numOfWaitingThreads(); int getValue(); @@ -62,6 +62,20 @@ public: bool getValue() { return (bool)_semaphore.getValue(); } }; +class PspCondition { +private: + PspMutex _mutex; + int _waitingThreads; + int _signaledThreads; + PspSemaphore _waitSem; + PspSemaphore _doneSem; +public: + PspCondition() : _mutex(true), _waitingThreads(0), _signaledThreads(0), + _waitSem(0), _doneSem(0) {} + void wait(PspMutex &externalMutex); + void releaseAll(); +}; + class PspRtc { private: |