[Scummvm-cvs-logs] SF.net SVN: scummvm:[44277] scummvm/branches/branch-1-0-0/backends

joostp at users.sourceforge.net joostp at users.sourceforge.net
Wed Sep 23 22:31:24 CEST 2009


Revision: 44277
          http://scummvm.svn.sourceforge.net/scummvm/?rev=44277&view=rev
Author:   joostp
Date:     2009-09-23 20:31:23 +0000 (Wed, 23 Sep 2009)

Log Message:
-----------
backport PSP improved suspend/resume support

Modified Paths:
--------------
    scummvm/branches/branch-1-0-0/backends/fs/psp/psp-fs.cpp
    scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.cpp
    scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.h
    scummvm/branches/branch-1-0-0/backends/fs/stdiostream.h
    scummvm/branches/branch-1-0-0/backends/platform/psp/osys_psp_gu.cpp
    scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.cpp
    scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.h
    scummvm/branches/branch-1-0-0/backends/platform/psp/trace.cpp
    scummvm/branches/branch-1-0-0/backends/platform/psp/trace.h
    scummvm/branches/branch-1-0-0/backends/saves/psp/psp-saves.cpp

Modified: scummvm/branches/branch-1-0-0/backends/fs/psp/psp-fs.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/fs/psp/psp-fs.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/fs/psp/psp-fs.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -27,7 +27,6 @@
 #include "engines/engine.h"
 #include "backends/fs/abstract-fs.h"
 #include "backends/fs/psp/psp-stream.h"
-#include "backends/platform/psp/powerman.h"
 
 #include <sys/stat.h>
 #include <unistd.h>
@@ -38,7 +37,6 @@
 
 #include "backends/platform/psp/trace.h"
 
-
 /**
  * Implementation of the ScummVM file system API based on PSPSDK API.
  *
@@ -98,7 +96,8 @@
 
 	if (verify) {
 		struct stat st;
-		PowerMan.beginCriticalSection();
+		if(PowerMan.beginCriticalSection()==PowerManager::Blocked)
+			PSPDebugSuspend("Suspended in PSPFilesystemNode::PSPFilesystemNode\n");
 		_isValid = (0 == stat(_path.c_str(), &st));
 		PowerMan.endCriticalSection();
 		_isDirectory = S_ISDIR(st.st_mode);
@@ -108,7 +107,9 @@
 bool PSPFilesystemNode::exists() const {
 	int ret = 0;
 
-	PowerMan.beginCriticalSection();	// Make sure to block in case of suspend
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+		PSPDebugSuspend("Suspended in PSPFilesystemNode::exists()\n");	// Make sure to block in case of suspend
+
 	ret = access(_path.c_str(), F_OK);
 	PowerMan.endCriticalSection();
 	
@@ -118,7 +119,9 @@
 bool PSPFilesystemNode::isReadable() const {
 	int ret = 0;
 
-	PowerMan.beginCriticalSection();	// Make sure to block in case of suspend
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+			PSPDebugSuspend("Suspended in PSPFilesystemNode::isReadable()\n");	// Make sure to block in case of suspend
+
 	ret = access(_path.c_str(), R_OK);
 	PowerMan.endCriticalSection();
 	
@@ -128,7 +131,9 @@
 bool PSPFilesystemNode::isWritable() const {
 	int ret = 0;
 
-	PowerMan.beginCriticalSection();	// Make sure to block in case of suspend
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+		PSPDebugSuspend("Suspended in PSPFilesystemNode::isWritable()\n");	// Make sure to block in case of suspend
+
 	ret = access(_path.c_str(), W_OK);
 	PowerMan.endCriticalSection();
 	
@@ -156,8 +161,9 @@
 
 	bool ret = true;
 
-	PowerMan.beginCriticalSection();	// Make sure to block in case of suspend
-	
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+		PSPDebugSuspend("Suspended in PSPFilesystemNode::getChildren\n");	// Make sure to block in case of suspend
+
 	int dfd  = sceIoDopen(_path.c_str());
 	if (dfd > 0) {
 		SceIoDirent dir;

Modified: scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -24,8 +24,13 @@
  */
 #ifdef __PSP__
 
+#include <SDL/SDL_thread.h>
+#include <SDL/SDL_mutex.h>
+
+#include "backends/platform/psp/trace.h"
+#include "backends/platform/psp/powerman.h"
 #include "backends/fs/psp/psp-stream.h"
-#include "backends/platform/psp/trace.h"
+
 #include <errno.h>
 
 PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode)
@@ -34,148 +39,193 @@
 	assert(!path.empty());
 
 	_handle = (void *)0;		// Need to do this since base class asserts not 0.
+	_ferror = false;			
+	_feof = false;
+	_pos = 0;
 
-	PowerMan.registerSuspend(this);	 // Register with the powermanager to be suspended
-
+#ifdef __PSP_DEBUG_SUSPEND__		
+	_errorSuspend = 0;
+	_errorSource = 0;
+	_errorPos = 0;
+	_errorHandle = 0;
+	_suspendCount = 0;
+#endif
 }
 
 PSPIoStream::~PSPIoStream() {
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
+		PSPDebugSuspend("Suspended in PSPIoStream::~PSPIoStream()\n");
+
 	PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended
 								 // Must do this before fclose() or resume() will reopen.
 
-	fclose((FILE *)_handle);
+	fclose((FILE *)_handle);	// We don't need a critical section(?). Worst case, the handle gets closed on its own
+
+	PowerMan.endCriticalSection();
 }
 
 // Function to open the file pointed to by the path.
 //
 //
-void * PSPIoStream::open() {
-	if (PowerMan.beginCriticalSection()==PowerManager::Blocked) {
+void *PSPIoStream::open() {
+	if (PowerMan.beginCriticalSection() == PowerManager::Blocked) {
 		// No need to open. Just return the _handle resume() already opened.
-		PSPDebugTrace("Suspended in PSPIoStream::open\n");
-	} else {
-		_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); 	// open
-	}
-	
+		PSPDebugSuspend("Suspended in PSPIoStream::open\n");
+	} 
+
+	_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); 	// open
+
+	PowerMan.registerSuspend(this);	 // Register with the powermanager to be suspended
+
 	PowerMan.endCriticalSection();
 
 	return _handle;
 }
 
 bool PSPIoStream::err() const {
-	bool ret;
-
-	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::err()\n");
-
-	ret = ferror((FILE *)_handle) != 0;
-
-	PowerMan.endCriticalSection();
-
-	return ret;
+	if (_ferror)
+		PSPDebugSuspend("In PSPIoStream::err - mem_ferror=%d, source=%d, suspend error=%d, pos=%d, _errorPos=%d, _errorHandle=%p, suspendCount=%d _handle\n", 
+			_ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount);
+			
+	return _ferror;
 }
 
 void PSPIoStream::clearErr() {
-	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::clearErr()\n");
-
-	clearerr((FILE *)_handle);
-
-	PowerMan.endCriticalSection();
+	_ferror = false;	// Remove regular error bit
+	
 }
 
 bool PSPIoStream::eos() const {
-	bool ret;
-
-	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::eos()\n");
-
-	ret = feof((FILE *)_handle) != 0;
-
-	PowerMan.endCriticalSection();
-
-	return ret;
+	return _feof;
 }
 
 int32 PSPIoStream::pos() const {
-	int32 ret;
-
-	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::pos()\n");
-
-	ret = ftell((FILE *)_handle);
-
-	PowerMan.endCriticalSection();
-
-	return ret;
+	return _pos;
 }
 
 
 int32 PSPIoStream::size() const {
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::size()\n");
+		PSPDebugSuspend("Suspended in PSPIoStream::size()\n");
 
-	int32 oldPos = ftell((FILE *)_handle);
 	fseek((FILE *)_handle, 0, SEEK_END);
 	int32 length = ftell((FILE *)_handle);
-	fseek((FILE *)_handle, oldPos, SEEK_SET);
+	fseek((FILE *)_handle, _pos, SEEK_SET);
+	
+	if (_pos < 0 || length < 0) {	// Check for errors
+		PSPDebugSuspend("In PSPIoStream::size(). encountered an error!\n");
+		_ferror = true;
+		length = -1;				// If our oldPos is bad, we want length to be bad too to signal
+		clearerr((FILE *)_handle);
 
+#ifdef __PSP_DEBUG_SUSPEND__		
+		_errorSource = 2;
+#endif
+	}
+
 	PowerMan.endCriticalSection();
 
 	return length;
 }
 
 bool PSPIoStream::seek(int32 offs, int whence) {
-	int ret = 0;
-
 	// Check if we can access the file
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::seek()\n");
+		PSPDebugSuspend("Suspended in PSPIoStream::seek()\n");
 
-	ret = fseek((FILE *)_handle, offs, whence);
+	int ret = fseek((FILE *)_handle, offs, whence);
+	
+	if (ret != 0) {
+		_ferror = true;
+		PSPDebugSuspend("In PSPIoStream::seek(). encountered an error!\n");
+		clearerr((FILE *)_handle);
+		_feof = feof((FILE *)_handle);
 
+#ifdef __PSP_DEBUG_SUSPEND__				
+		_errorSource = 3;
+#endif
+	}
+	else {					// everything ok
+		_feof = false;		// Reset eof flag since we know it was ok
+	}
+	
+	_pos = ftell((FILE *)_handle);	// update pos
+
 	PowerMan.endCriticalSection();
 
 	return ret == 0;
 }
 
 uint32 PSPIoStream::read(void *ptr, uint32 len) {
-	int ret = 0;
-
 	// Check if we can access the file
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+		PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
 
-	ret = fread((byte *)ptr, 1, len, (FILE *)_handle);
+	size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle);	
+
+	_pos += ret;	// Update pos
 	
+	if (ret != len) {	// Check for eof
+		_feof = feof((FILE *)_handle);
+		if (!_feof) {	// It wasn't an eof. Must be an error
+			_ferror = true;
+			clearerr((FILE *)_handle);
+			_pos = ftell((FILE *)_handle);	// Update our position
+			PSPDebugSuspend("In PSPIoStream::read(). encountered an error!\n");
+
+#ifdef __PSP_DEBUG_SUSPEND__								
+			_errorSource = 4;
+#endif
+		}
+	}
+	
 	PowerMan.endCriticalSection();
 	
 	return ret;
 }
 
 uint32 PSPIoStream::write(const void *ptr, uint32 len) {
-	int ret = 0;
-
 	// Check if we can access the file
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+		PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
 
-	ret = fwrite(ptr, 1, len, (FILE *)_handle);
+	size_t ret = fwrite(ptr, 1, len, (FILE *)_handle);
 
+	_pos += ret;
+
+	if (ret != len) {	// Set error
+		_ferror = true;
+		clearerr((FILE *)_handle);
+		_pos = ftell((FILE *)_handle);	// Update pos
+		PSPDebugTrace("In PSPIoStream::write(). encountered an error!\n");
+
+#ifdef __PSP_DEBUG_SUSPEND__								
+		_errorSource = 5;
+#endif
+	}
+
 	PowerMan.endCriticalSection();
 
 	return ret;
 }
 
 bool PSPIoStream::flush() {
-	int ret = 0;
-
-	// Check if we can access the file
+	// Enter critical section
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
-		PSPDebugTrace("Suspended in PSPIoStream::read()\n");
+		PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
 
-	ret = fflush((FILE *)_handle);
+	int ret = fflush((FILE *)_handle);
 
+	if (ret != 0) {
+		_ferror = true;
+		clearerr((FILE *)_handle);
+		PSPDebugSuspend("In PSPIoStream::flush(). encountered an error!\n");
+
+#ifdef __PSP_DEBUG_SUSPEND__							
+		_errorSource = 6;
+#endif
+	}
+
 	PowerMan.endCriticalSection();
 
 	return ret == 0;
@@ -199,10 +249,19 @@
  *  Function to suspend the IO stream (called by PowerManager)
  */
 int PSPIoStream::suspend() {
+#ifdef __PSP_DEBUG_SUSPEND__
+	_suspendCount++;
+
+	if (_handle > 0 && _pos < 0) {
+		_errorSuspend = SuspendError;
+		_errorPos = _pos;
+		_errorHandle = _handle;
+	}	
+#endif /* __PSP_DEBUG_SUSPEND__ */
+
 	if (_handle > 0) {
-		_pos = ftell((FILE *)_handle);	// Save our position
 		fclose((FILE *)_handle);		// close our file descriptor
-		_handle = 0;					// Set handle to null
+		_handle = (void *)0xFFFFFFFF;	// Set handle to non-null invalid value so makeFromPath doesn't return error
 	}
 
 	return 0;
@@ -213,18 +272,32 @@
  */
 int PSPIoStream::resume() {
 	int ret = 0;
-
+#ifdef __PSP_DEBUG_SUSPEND__
+	_suspendCount--;
+#endif
+	
 	// We reopen our file descriptor
 	_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb");
 	if (_handle <= 0) {
-		PSPDebugTrace("PSPIoStream::resume(): Couldn't reopen file %s\n", _path.c_str());
-		ret = -1;;
+		PSPDebugSuspend("PSPIoStream::resume(): Couldn't reopen file %s\n", _path.c_str());
 	}
 
 	// Resume our previous position
-	if(_handle > 0) fseek((FILE *)_handle, _pos, SEEK_SET);
+	if (_handle > 0 && _pos > 0) {
+		ret = fseek((FILE *)_handle, _pos, SEEK_SET);
 
+#ifdef __PSP_DEBUG_SUSPEND__
+		if (ret != 0) {		// Check for problem
+			_errorSuspend = ResumeError;
+			_errorPos = _pos;
+			_errorHandle = _handle;
+		}
+#endif
+
+	}
+
 	return ret;
 }
 
+
 #endif /* __PSP__ */

Modified: scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.h
===================================================================
--- scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.h	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/fs/psp/psp-stream.h	2009-09-23 20:31:23 UTC (rev 44277)
@@ -37,8 +37,24 @@
 protected:
 	Common::String _path;			/* Need to maintain for reopening after suspend */
 	bool _writeMode;				/* "" */
-	unsigned int _pos;				/* "" */
+	int _pos;						/* "" */
+	mutable int _ferror;			/* Save file ferror */
+	mutable bool _feof;						/* and eof */
 
+	enum {
+		SuspendError = 2,
+		ResumeError = 3
+	};
+
+	int _errorSuspend;
+	mutable int _errorSource;
+	
+#ifdef __PSP_DEBUG_SUSPEND__	
+	int _errorPos;
+	void * _errorHandle;			
+	int _suspendCount;
+#endif /* __PSP_DEBUG_SUSPEND__ */	
+
 public:
 	/**
 	 * Given a path, invoke fopen on that path and wrap the result in a

Modified: scummvm/branches/branch-1-0-0/backends/fs/stdiostream.h
===================================================================
--- scummvm/branches/branch-1-0-0/backends/fs/stdiostream.h	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/fs/stdiostream.h	2009-09-23 20:31:23 UTC (rev 44277)
@@ -46,17 +46,17 @@
 	StdioStream(void *handle);
 	virtual ~StdioStream();
 
-	bool err() const;
-	void clearErr();
-	bool eos() const;
+	virtual bool err() const;
+	virtual void clearErr();
+	virtual bool eos() const;
 
 	virtual uint32 write(const void *dataPtr, uint32 dataSize);
 	virtual bool flush();
 
 	virtual int32 pos() const;
 	virtual int32 size() const;
-	bool seek(int32 offs, int whence = SEEK_SET);
-	uint32 read(void *dataPtr, uint32 dataSize);
+	virtual bool seek(int32 offs, int whence = SEEK_SET);
+	virtual uint32 read(void *dataPtr, uint32 dataSize);
 };
 
 #endif

Modified: scummvm/branches/branch-1-0-0/backends/platform/psp/osys_psp_gu.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/platform/psp/osys_psp_gu.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/platform/psp/osys_psp_gu.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -23,6 +23,7 @@
  */
 
 #include "osys_psp_gu.h"
+#include "powerman.h"
 #include "trace.h"
 #include "common/events.h"
 
@@ -575,6 +576,13 @@
 	float nub_angle = -1;
 	int x, y;
 
+	// If we're polling for events, we should check for pausing the engine
+	// Pausing the engine is a necessary fix for games that use the timer for music synchronization
+	//      recovering many hours later causes the game to crash. We're polling without mutexes since it's not critical to
+	//  get it right now.
+
+	PowerMan.pollPauseEngine();
+
 	sceCtrlSetSamplingCycle(0);
 	sceCtrlSetSamplingMode(1);
 	sceCtrlReadBufferPositive(&pad, 1);

Modified: scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -23,17 +23,33 @@
  *
  */
 
+#include <psppower.h>
+#include <pspthreadman.h>
+ 
 #include "./powerman.h"
 #include "./trace.h"
+#include "engine.h"
 
 DECLARE_SINGLETON(PowerManager);
 
+#ifdef __PSP_DEBUG_SUSPEND__
+void PowerManager::debugPM() {
+	PSPDebugTrace("PM status is %d. Listcount is %d. CriticalCount is %d. ThreadId is %x. Error = %d\n", _PMStatus, _listCounter,
+		_criticalCounter, sceKernelGetThreadId(), _error);
+}
+#else
+	#define debugPM()
+	#define PMStatusSet(x)
+#endif /* __PSP_DEBUG_SUSPEND__ */
+
+
  /*******************************************
 *
 *	Constructor
 *
 ********************************************/ 
 PowerManager::PowerManager() {
+	
 	_flagMutex = NULL;					/* Init mutex handle */
 	_listMutex = NULL;					/* Init mutex handle */
 	_condSuspendable = NULL;			/* Init condition variable */
@@ -41,26 +57,33 @@
 	
 	_condSuspendable = SDL_CreateCond();
 	if (_condSuspendable <= 0) {
-		PSPDebugTrace("PowerManager::PowerManager(): Couldn't create condSuspendable\n");
+		PSPDebugSuspend("PowerManager::PowerManager(): Couldn't create condSuspendable\n");
 	}
 	
 	_condPM = SDL_CreateCond();
 	if (_condPM <= 0) {
-		PSPDebugTrace("PowerManager::PowerManager(): Couldn't create condPM\n");
+		PSPDebugSuspend("PowerManager::PowerManager(): Couldn't create condPM\n");
 	}
 
 	_flagMutex = SDL_CreateMutex();
 	if (_flagMutex <= 0) {
-		PSPDebugTrace("PowerManager::PowerManager(): Couldn't create flagMutex\n");
+		PSPDebugSuspend("PowerManager::PowerManager(): Couldn't create flagMutex\n");
 	}
 
 	_listMutex = SDL_CreateMutex();
 	if (_listMutex <= 0) {
-		PSPDebugTrace("PowerManager::PowerManager(): Couldn't create listMutex\n");
+		PSPDebugSuspend("PowerManager::PowerManager(): Couldn't create listMutex\n");
 	}
 
 	_suspendFlag = false;
 	_criticalCounter = 0;
+	_pauseFlag = 0; _pauseFlagOld = 0; _pauseClientState = 0;
+
+#ifdef __PSP_DEBUG_SUSPEND__	
+	_listCounter = 0;
+	PMStatusSet(kInitDone);
+	_error = 0;	
+#endif
  }
  
 /*******************************************
@@ -70,20 +93,25 @@
 ********************************************/ 
 int PowerManager::registerSuspend(Suspendable *item) {
 	// Register in list
-	PSPDebugTrace("In registerSuspend\n");
+	PSPDebugSuspend("In registerSuspend\n");
+	debugPM();
 
 	if (SDL_mutexP(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::registerSuspend(): Couldn't lock _listMutex %d\n", _listMutex);
 	}
 
 	_suspendList.push_front(item);
+#ifdef __PSP_DEBUG_SUSPEND__
+	_listCounter++;
+#endif
 
 	if (SDL_mutexV(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::registerSuspend(): Couldn't unlock _listMutex %d\n", _listMutex);
 	}
 
-	PSPDebugTrace("Out of registerSuspend\n");
-
+	PSPDebugSuspend("Out of registerSuspend\n");
+	debugPM();
+	
 	return 0;
 }
 
@@ -94,7 +122,8 @@
 ********************************************/  
 int PowerManager::unregisterSuspend(Suspendable *item) {
 
-	PSPDebugTrace("In unregisterSuspend\n");
+	PSPDebugSuspend("In unregisterSuspend\n");
+	debugPM();
 
 	 // Unregister from stream list
 	if (SDL_mutexP(_listMutex) != 0) {
@@ -102,13 +131,17 @@
 	}
 
 	_suspendList.remove(item);
-
+#ifdef __PSP_DEBUG_SUSPEND__
+	_listCounter--;
+#endif	
+	
 	if (SDL_mutexV(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::unregisterSuspend(): Couldn't unlock _listMutex %d\n", _listMutex);
 	}
 
-	PSPDebugTrace("Out of unregisterSuspend\n");
-
+	PSPDebugSuspend("Out of unregisterSuspend\n");
+	debugPM();
+	
 	return 0;
  }
  
@@ -118,6 +151,11 @@
 *
 ********************************************/ 
  PowerManager::~PowerManager() {
+
+#ifdef __PSP_DEBUG_SUSPEND__
+	PMStatusSet(kDestroyPM);
+#endif
+ 
 	SDL_DestroyCond(_condSuspendable);
 	_condSuspendable = 0;
 	
@@ -130,48 +168,84 @@
 	SDL_DestroyMutex(_listMutex);
 	_listMutex = 0;
  }
+
+/*******************************************
+*
+*	Unsafe function to poll for a pause event (first stage of suspending)
+*   Only for pausing the engine, which doesn't need high synchronization ie. we don't care if it misreads
+*   the flag a couple of times since there is NO mutex protection (for performance reasons). 
+*   Polling the engine happens regularly.
+*	On the other hand, we don't know if there will be ANY polling which prevents us from using proper events.
+*
+********************************************/  
+void PowerManager::pollPauseEngine() {
+
+	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);
+			PSPDebugSuspend("Pausing engine in PowerManager::pollPauseEngine()\n");
+			_pauseClientState = PowerManager::Paused;		// Tell PM we're done pausing
+		}
+		else if (!pause && _pauseClientState == PowerManager::Paused) {
+			g_engine->pauseEngine(false);
+			PSPDebugSuspend("Unpausing for resume in PowerManager::pollPauseEngine()\n");
+			_pauseClientState = PowerManager::Unpaused;	// Tell PM we're in the middle of pausing
+		}
+			
+		_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
-  */
-int PowerManager::beginCriticalSection(bool justBlock) {
-	int ret = PowerManager::NotBlocked;
+/*******************************************
+*
+*	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.
+********************************************/  
 
+  int PowerManager::beginCriticalSection(bool justBlock) {
+	int ret = NotBlocked;
+
 	if (SDL_mutexP(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't lock flagMutex %d\n", _flagMutex);
-		ret = PowerManager::Error;
+		ret = Error;
 	}
 
 	// Check the access flag
 	if (_suspendFlag == true) {
-		PSPDebugTrace("Blocking!!\n");
-		ret = PowerManager::Blocked;
+		PSPDebugSuspend("We're being blocked!\n");
+		debugPM();
+		ret = Blocked;
 
 		// If it's true, we wait for a signal to continue
-		if( SDL_CondWait(_condSuspendable, _flagMutex) != 0) {
+		if (SDL_CondWait(_condSuspendable, _flagMutex) != 0) {
 			PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't wait on cond %d\n", _condSuspendable);
 		}
 
-		PSPDebugTrace("We got blocked!!\n");
+		PSPDebugSuspend("We got blocked!!\n");
+		debugPM();
 	}
 	
-	// Now put the pm to sleep
+	// Now prevent the PM from suspending until we're done
 	if (justBlock == false)
 		_criticalCounter++;
 
 	if (SDL_mutexV(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::blockOnSuspend(): Couldn't unlock flagMutex %d\n", _flagMutex);
-		ret = PowerManager::Error;
+		ret = Error;
 	}
 
 	return ret;
@@ -182,25 +256,32 @@
 
 	if (SDL_mutexP(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::endCriticalSection(): Couldn't lock flagMutex %d\n", _flagMutex);
-		ret = PowerManager::Error;
+		ret = Error;
 	}
 
 	// We're done with our critical section
 	_criticalCounter--;
 	
 	if (_criticalCounter <= 0) {
-		if(_suspendFlag == true) PSPDebugTrace("Waking up the PM and suspendFlag is true\n");
+		if (_suspendFlag == true) {	// If the PM is sleeping, this flag must be set
+			PSPDebugSuspend("Unblocked thread waking up the PM.\n");
+			debugPM();
 
-		SDL_CondBroadcast(_condPM);
+			SDL_CondBroadcast(_condPM);
+			
+			PSPDebugSuspend("Woke up the PM\n");
+			debugPM();
+		}
 
-		if (_criticalCounter < 0) {
+		if (_criticalCounter < 0) {	// Check for bad usage of critical sections
 			PSPDebugTrace("PowerManager::endCriticalSection(): Error! Critical counter is %d\n", _criticalCounter);
+			debugPM();
 		}
 	}
 
 	if (SDL_mutexV(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::endCriticalSection(): Couldn't unlock flagMutex %d\n", _flagMutex);
-		ret = PowerManager::Error;
+		ret = Error;
 	}
 
 	return ret;
@@ -213,40 +294,86 @@
 ********************************************/  
 int PowerManager::suspend() {
 	int ret = 0;
+	
+	if (_pauseFlag) return ret;	// Very important - make sure we only suspend once
 
-	// First we set the suspend flag to true
+	scePowerLock(0);			// 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);
+	
+	// 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
+	
+	if (_pauseClientState == Pausing) {	// Our event has been acknowledged. Let's wait until the client is done.
+		PMStatusSet(kWaitForClientToFinishPausing);
+
+		while (_pauseClientState != Paused)
+			sceKernelDelayThread(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.
+	
+	PMStatusSet(kGettingFlagMutexSuspend);
+	
+	// Now we set the suspend flag to true to cause reading threads to block
+	
 	if (SDL_mutexP(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::suspend(): Couldn't lock flagMutex %d\n", _flagMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
 
+	PMStatusSet(kGotFlagMutexSuspend);
+	
 	_suspendFlag = true;
 	
-	if (_criticalCounter > 0)
+	// 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);
+	}
 
 	if (SDL_mutexV(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::suspend(): Couldn't unlock flagMutex %d\n", _flagMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
 
+	PMStatusSet(kGettingListMutexSuspend);
+	
 	// Loop over list, calling suspend()
 	if (SDL_mutexP(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::suspend(): Couldn't lock listMutex %d\n", _listMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
-
+	PMStatusSet(kIteratingListSuspend);
+	// Iterate
 	Common::List<Suspendable *>::iterator i = _suspendList.begin();
 
 	for (; i != _suspendList.end(); i++) {
 		(*i)->suspend();
 	}
+	
+	PMStatusSet(kDoneIteratingListSuspend);
 
 	if (SDL_mutexV(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::suspend(): Couldn't unlock listMutex %d\n", _listMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
+	PMStatusSet(kDoneSuspend);
 
+	scePowerUnlock(0);				// Allow the PSP to go to sleep now
+	
 	return ret;
 }
 
@@ -258,40 +385,67 @@
 int PowerManager::resume() {
 	int ret = 0;
 
+	// Make sure we can't get another suspend
+	scePowerLock(0);
+	
+	if (!_pauseFlag) return ret;				// Make sure we can only resume once
+	
+	PMStatusSet(kGettingListMutexResume);
+	
 	// First we notify our Suspendables. Loop over list, calling resume()
 	if (SDL_mutexP(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::resume(): Couldn't lock listMutex %d\n", _listMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
-
+	PMStatusSet(kIteratingListResume);
+	// Iterate
 	Common::List<Suspendable *>::iterator i = _suspendList.begin();
 
 	for (; i != _suspendList.end(); i++) {
 		(*i)->resume();
 	}
+	
+	PMStatusSet(kDoneIteratingListResume);
 
 	if (SDL_mutexV(_listMutex) != 0) {
 		PSPDebugTrace("PowerManager::resume(): Couldn't unlock listMutex %d\n", _listMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
+	
+	PMStatusSet(kGettingFlagMutexResume);
 
 	// Now we set the suspend flag to false
 	if (SDL_mutexP(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::resume(): Couldn't lock flagMutex %d\n", _flagMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
+	PMStatusSet(kGotFlagMutexResume);
+	
 	_suspendFlag = false;
 
+	PMStatusSet(kSignalSuspendedThreadsResume);
+	
 	// Signal the other threads to wake up
 	if (SDL_CondBroadcast(_condSuspendable) != 0) {
 		PSPDebugTrace("PowerManager::resume(): Couldn't broadcast condition %d\n", _condSuspendable);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
+	PMStatusSet(kDoneSignallingSuspendedThreadsResume);
 
 	if (SDL_mutexV(_flagMutex) != 0) {
 		PSPDebugTrace("PowerManager::resume(): Couldn't unlock flagMutex %d\n", _flagMutex);
-		ret = -1;
+		_error = Error;
+		ret = Error;
 	}
+	PMStatusSet(kDoneResume);
+	
+	_pauseFlag = false;	// Signal engine to unpause
 
+	scePowerUnlock(0);	// Allow new suspends
+	
 	return ret;
 }

Modified: scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.h
===================================================================
--- scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.h	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/platform/psp/powerman.h	2009-09-23 20:31:23 UTC (rev 44277)
@@ -50,20 +50,7 @@
  *
  *******************************************************************************************************/
  class PowerManager: public Common::Singleton<PowerManager> {
-private:
-	friend class Common::Singleton<PowerManager>;
-	PowerManager();
-	~PowerManager();
 
-	Common::List<Suspendable *> _suspendList;		/* list to register in */
-
-	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 */
-	int _criticalCounter;							/* Counter of how many threads are in a critical section */
-
 public:
 	int blockOnSuspend();								/* block if suspending */
 	int beginCriticalSection(bool justBlock = false);	/* Use a critical section to block (if suspend was already pressed) */
@@ -72,13 +59,78 @@
 	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 */
+	// Functions for pausing the engine
+	void pollPauseEngine();							/* Poll whether the engine should be paused */
 	
 	enum {
 		Error = -1,
 		NotBlocked = 0,
-		Blocked = 1		
+		Blocked = 1
 	};
-		
+	
+	enum PauseState {
+		Unpaused = 0,
+		PauseEvent,
+		UnpauseEvent,
+		Pausing,
+		Paused
+	};
+	
+ private:
+	friend class Common::Singleton<PowerManager>;
+	PowerManager();
+	~PowerManager();
+
+	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 _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 */
+	
+	// States for PM to be in (used for debugging)
+	enum PMState {
+		kInitDone = 1 , 
+		kDestroyPM,
+		kWaitForClientPause,
+		kWaitForClientToFinishPausing,
+		kGettingFlagMutexSuspend,
+		kGotFlagMutexSuspend,
+		kWaitCritSectionSuspend,
+		kDoneWaitingCritSectionSuspend,
+		kGettingListMutexSuspend,
+		kIteratingListSuspend,
+		kDoneIteratingListSuspend,
+		kDoneSuspend,
+		kGettingListMutexResume,
+		kIteratingListResume,
+		kDoneIteratingListResume,
+		kGettingFlagMutexResume,
+		kGotFlagMutexResume,
+		kSignalSuspendedThreadsResume,
+		kDoneSignallingSuspendedThreadsResume,
+		kDoneResume
+	};	
+#ifdef __PSP_DEBUG_SUSPEND__
+
+	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() { return _PMStatus; }
+ 
+#endif /* __PSP_DEBUG_SUSPEND__ */		
+			
  };
  
  // For easy access

Modified: scummvm/branches/branch-1-0-0/backends/platform/psp/trace.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/platform/psp/trace.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/platform/psp/trace.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -27,10 +27,8 @@
 #include "./trace.h"
 
 
-//#define __DEBUG__
-
 void PSPDebugTrace (const char *format, ...) {
-#ifdef __DEBUG__
+#ifdef __PSP_DEBUG__
 	va_list	opt;
 	char		buff[2048];
 	int			bufsz, fd;
@@ -46,11 +44,11 @@
 
 	sceIoWrite(fd, (const void*)buff, bufsz);
 	sceIoClose(fd);
-#endif
+#endif /* __PSP_DEBUG__ */
 }
 
 void PSPDebugTrace (const char * filename, const char *format, ...) {
-#ifdef __DEBUG__
+#ifdef __PSP_DEBUG__
 	va_list	opt;
 	char		buff[2048];
 	int			bufsz, fd;
@@ -66,5 +64,5 @@
 
 	sceIoWrite(fd, (const void*)buff, bufsz);
 	sceIoClose(fd);
-#endif
+#endif /* __PSP_DEBUG__ */
 }

Modified: scummvm/branches/branch-1-0-0/backends/platform/psp/trace.h
===================================================================
--- scummvm/branches/branch-1-0-0/backends/platform/psp/trace.h	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/platform/psp/trace.h	2009-09-23 20:31:23 UTC (rev 44277)
@@ -33,8 +33,21 @@
 #include <stdarg.h>
 #include <pspdebug.h>
 
+// Use these defines for debugging
+
+//#define __PSP_DEBUG__
+//#define __PSP_DEBUG_SUSPEND__
+
 void PSPDebugTrace (const char *filename, const char *format, ...);
 void PSPDebugTrace (const char *format, ...);
 
+#ifdef __PSP_DEBUG_SUSPEND__
+#define PSPDebugSuspend(format,...)		PSPDebugTrace(format, ## __VA_ARGS__)
+#else
+#define PSPDegbugSuspend(x)
+#define PSPDebugSuspend(format,...)
+#endif /* __PSP_DEBUG_SUSPEND__ */
+
+
 #endif // TRACE_H
 

Modified: scummvm/branches/branch-1-0-0/backends/saves/psp/psp-saves.cpp
===================================================================
--- scummvm/branches/branch-1-0-0/backends/saves/psp/psp-saves.cpp	2009-09-23 16:11:23 UTC (rev 44276)
+++ scummvm/branches/branch-1-0-0/backends/saves/psp/psp-saves.cpp	2009-09-23 20:31:23 UTC (rev 44277)
@@ -26,6 +26,7 @@
 #ifdef __PSP__
 
 #include "backends/saves/psp/psp-saves.h"
+#include "backends/platform/psp/powerman.h"
 
 #include "common/config-manager.h"
 #include "common/savefile.h"
@@ -49,6 +50,8 @@
 	const char *savePath = dir.getPath().c_str();
 	clearError();
 
+	PowerMan.beginCriticalSection();
+	
 	//check if the save directory exists
 	SceUID fd = sceIoDopen(savePath);
 	if (fd < 0) {
@@ -58,6 +61,8 @@
 		//it exists, so close it again.
 		sceIoDclose(fd);
 	}
+	
+	PowerMan.endCriticalSection();
 }
 #endif
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list