synchronize access to memory cards between mounting thread and main thread Profile Load/Save

This commit is contained in:
Chris Danford
2004-06-06 02:41:16 +00:00
parent 5c7dd115ad
commit 110ec3d331
11 changed files with 190 additions and 143 deletions
+9
View File
@@ -295,6 +295,15 @@ CString MemoryCardManager::GetName( PlayerNumber pn ) const
return m_Device[pn].sName;
}
void MemoryCardManager::PauseMountingThread()
{
m_pDriver->PauseMountingThread();
}
void MemoryCardManager::UnPauseMountingThread()
{
m_pDriver->UnPauseMountingThread();
}
bool IsAnyPlayerUsingMemoryCard()
{
+3
View File
@@ -37,6 +37,9 @@ public:
void LockCards( bool bLock ); // prevent removing or changing of memory cards
void PauseMountingThread(); // call this before reading or writing to memory card
void UnPauseMountingThread(); // call this when done reading or writing to memory card
void FlushAndReset(); // force all files to be written to mounted memory cards
bool PathIsMemCard( CString sDir ) const;
+14 -1
View File
@@ -84,6 +84,9 @@ bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIs
ASSERT( !sProfileDir.empty() );
ASSERT( sProfileDir.Right(1) == "/" );
if( bIsMemCard )
MEMCARDMAN->PauseMountingThread();
m_sProfileDir[pn] = sProfileDir;
m_bWasLoadedFromMemoryCard[pn] = bIsMemCard;
@@ -92,6 +95,8 @@ bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIs
else
m_Profile[pn].LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
MEMCARDMAN->UnPauseMountingThread();
LOG->Trace( "Done loading profile." );
return true;
@@ -200,7 +205,15 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) const
if( m_sProfileDir[pn].empty() )
return false;
return m_Profile[pn].SaveAllToDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
if( ProfileWasLoadedFromMemoryCard(pn) )
MEMCARDMAN->PauseMountingThread();
bool b = m_Profile[pn].SaveAllToDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
if( ProfileWasLoadedFromMemoryCard(pn) )
MEMCARDMAN->UnPauseMountingThread();
return b;
}
void ProfileManager::UnloadProfile( PlayerNumber pn )
@@ -57,6 +57,8 @@ public:
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint ) = 0;
virtual void Flush( UsbStorageDevice* pDevice ) = 0;
virtual void ResetUsbStorage() = 0;
virtual void PauseMountingThread() = 0;
virtual void UnPauseMountingThread() = 0;
};
#endif
@@ -5,12 +5,6 @@
#include "RageFileManager.h"
int MemoryCardDriverThreaded::MountThread_Start( void *p )
{
((MemoryCardDriverThreaded*)p)->MountThreadMain();
return 0;
}
template<class T>
bool VectorsAreEqual( const T &a, const T &b )
{
@@ -27,9 +21,11 @@ bool VectorsAreEqual( const T &a, const T &b )
}
MemoryCardDriverThreaded::MemoryCardDriverThreaded() :
m_mutexStorageDevices("StorageDevices")
m_mutexPause("Pause"),
m_mutexStorageDevices("StorageDevices")
{
m_bShutdown = false;
m_bShutdownNextUpdate = false;
m_bResetNextUpdate = false;
m_bStorageDevicesChanged = false;
}
@@ -41,12 +37,42 @@ void MemoryCardDriverThreaded::StartThread()
MemoryCardDriverThreaded::~MemoryCardDriverThreaded()
{
m_bShutdown = true;
m_bShutdownNextUpdate = true;
LOG->Trace( "Shutting down Mount thread..." );
m_threadMemoryCardMount.Wait();
LOG->Trace( "Mount thread shut down." );
}
void MemoryCardDriverThreaded::PauseMountingThread()
{
m_mutexPause.Lock();
}
void MemoryCardDriverThreaded::UnPauseMountingThread()
{
m_mutexPause.Unlock();
}
int MemoryCardDriverThreaded::MountThread_Start( void *p )
{
((MemoryCardDriverThreaded*)p)->MountThreadMain();
return 0;
}
void MemoryCardDriverThreaded::MountThreadMain()
{
while( !m_bShutdownNextUpdate )
{
LockMut( m_mutexPause ); // wait until we're unpaused
if( m_bResetNextUpdate )
{
this->MountThreadReset();
m_bResetNextUpdate = false;
}
this->MountThreadDoOneUpdate();
}
}
bool MemoryCardDriverThreaded::StorageDevicesChanged()
{
LockMut( m_mutexStorageDevices );
@@ -86,6 +112,11 @@ bool MemoryCardDriverThreaded::MountAndTestWrite( UsbStorageDevice* pDevice, CSt
return true;
}
void MemoryCardDriverThreaded::ResetUsbStorage()
{
m_bResetNextUpdate = true;
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
@@ -21,18 +21,32 @@ class MemoryCardDriverThreaded : public MemoryCardDriver
public:
MemoryCardDriverThreaded();
~MemoryCardDriverThreaded();
void StartThread(); // call this in the derived constructor to start the mounting thread
virtual bool StorageDevicesChanged();
virtual void GetStorageDevices( vector<UsbStorageDevice>& vStorageDevicesOut );
virtual bool MountAndTestWrite( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void ResetUsbStorage();
virtual void PauseMountingThread();
virtual void UnPauseMountingThread();
private:
static int MountThread_Start( void *p );
protected:
virtual void MountThreadMain() = 0;
virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint ) = 0;
void MountThreadMain();
RageThread m_threadMemoryCardMount;
bool m_bShutdown;
bool m_bShutdownNextUpdate;
bool m_bResetNextUpdate;
// Aquire this before detecting devices or reading/writing devices.
// Calling Pause() and Unpause will lock/unlock this so that the mounting thread
// will temporarily halt.
RageMutex m_mutexPause;
protected:
void StartThread(); // call this in the derived constructor to start the mounting thread
virtual void MountThreadReset() = 0;
virtual void MountThreadDoOneUpdate() = 0; // this will get called as fast as possible
virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint ) = 0;
vector<UsbStorageDeviceEx> m_vStorageDevices;
bool m_bStorageDevicesChanged;
@@ -124,41 +124,56 @@ static bool ExecuteCommand( CCStringRef sCommand )
return ret == 0;
}
void MemoryCardDriverThreaded_Linux::MountThreadMain()
MemoryCardDriverThreaded_Linux::MemoryCardDriverThreaded_Linux()
{
int fd = open(USB_DEVICE_LIST_FILE, O_RDONLY);
if( fd == -1 )
m_fd = open(USB_DEVICE_LIST_FILE, O_RDONLY);
if( m_fd == -1 )
{
LOG->Warn( "Failed to open \"%s\": %s", USB_DEVICE_LIST_FILE, strerror(errno) );
return;
}
this->StartThread();
}
void MemoryCardDriverThreaded_Linux::MountThreadReset()
{
//
// if usb-storage gets in a bad state, resetting usb-storage will sometimes fix it.
//
LockMut( m_mutexStorageDevices );
// unmount all devices before trying to remove the module
for( unsigned i=0; i<m_vStorageDevices.size(); i++ )
{
UsbStorageDeviceEx &d = m_vStorageDevices[i];
CString sCommand = "umount " + d.sOsMountDir;
ExecuteCommand( sCommand );
}
vector<UsbStorageDeviceEx> vDevicesLastSeen;
while( !m_bShutdown )
{
if( m_bReset )
ExecuteCommand( "rmmod usb-storage" );
ExecuteCommand( "modprobe usb-storage" );
m_vDevicesLastSeen.clear(); // redetect all devices
}
void MemoryCardDriverThreaded_Linux::MountThreadDoOneUpdate()
{
if( m_fd == -1 )
return;
pollfd pfd = { m_fd, POLLIN, 0 };
int ret = poll( &pfd, 1, 100 );
switch( ret )
{
// force all to be re-detected
vDevicesLastSeen.clear();
m_bReset = false;
}
else
{
pollfd pfd = { fd, POLLIN, 0 };
int ret = poll( &pfd, 1, 100 );
switch( ret )
{
case 1:
// file changed. Fall through.
break;
case 0: // no change. Poll again.
continue;
case -1:
if( errno != EINTR )
LOG->Warn( "Error polling: %s", strerror(errno) );
continue;
}
case 1:
// file changed. Fall through.
break;
case 0: // no change. Poll again.
return;
case -1:
if( errno != EINTR )
LOG->Warn( "Error polling: %s", strerror(errno) );
return;
}
// TRICKY: We're waiting for a change in the USB device list, but
@@ -172,7 +187,7 @@ void MemoryCardDriverThreaded_Linux::MountThreadMain()
GetNewStorageDevices( vDevicesNow );
vector<UsbStorageDeviceEx> &vNew = vDevicesNow;
vector<UsbStorageDeviceEx> &vOld = vDevicesLastSeen;
vector<UsbStorageDeviceEx> &vOld = m_vDevicesLastSeen;
// check for disconnects
vector<UsbStorageDeviceEx*> vDisconnects;
@@ -246,18 +261,11 @@ void MemoryCardDriverThreaded_Linux::MountThreadMain()
}
}
vDevicesLastSeen = vDevicesNow;
}
m_vDevicesLastSeen = vDevicesNow;
CHECKPOINT;
}
MemoryCardDriverThreaded_Linux::MemoryCardDriverThreaded_Linux()
{
m_bReset = false;
this->StartThread();
}
bool ReadUsbStorageDescriptor( CString fn, int iScsiIndex, vector<UsbStorageDeviceEx>& vDevicesOut )
{
LOG->Trace( "ReadUsbStorageDescriptor %s", fn.c_str() );
@@ -631,30 +639,6 @@ void MemoryCardDriverThreaded_Linux::Flush( UsbStorageDevice* pDevice )
ExecuteCommand( "mount -o remount " + pDevice->sOsMountDir );
}
void MemoryCardDriverThreaded_Linux::ResetUsbStorage()
{
//
// if usb-storage gets in a bad state, resetting usb-storage will sometimes fix it.
//
LockMut( m_mutexStorageDevices );
// unmount all devices before trying to remove the module
for( unsigned i=0; i<m_vStorageDevices.size(); i++ )
{
UsbStorageDeviceEx &d = m_vStorageDevices[i];
CString sCommand = "umount " + d.sOsMountDir;
ExecuteCommand( sCommand );
}
ExecuteCommand( "rmmod usb-storage" );
ExecuteCommand( "modprobe usb-storage" );
m_bReset = true;
// let the mounting thread re-mount everything
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
@@ -10,12 +10,13 @@ public:
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void Flush( UsbStorageDevice* pDevice );
virtual void ResetUsbStorage();
protected:
virtual void MountThreadMain();
virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void MountThreadReset();
virtual void MountThreadDoOneUpdate();
bool m_bReset;
int m_fd;
vector<UsbStorageDeviceEx> m_vDevicesLastSeen;
};
#endif
@@ -7,14 +7,13 @@
#include "RageLog.h"
#include "Profile.h"
#include "PrefsManager.h"
#include <windows.h>
const CString TEMP_MOUNT_POINT = "@mctemp/";
MemoryCardDriverThreaded_Windows::MemoryCardDriverThreaded_Windows()
{
m_bReset = false;
m_dwLastLogicalDrives = 0;
StartThread();
}
@@ -55,65 +54,59 @@ static bool TestWrite( CCStringRef sDrive )
return true;
}
void MemoryCardDriverThreaded_Windows::MountThreadMain()
void MemoryCardDriverThreaded_Windows::MountThreadReset()
{
DWORD dwLastLogicalDrives = 0;
while( !m_bShutdown )
m_dwLastLogicalDrives = 0;
}
void MemoryCardDriverThreaded_Windows::MountThreadDoOneUpdate()
{
DWORD dwNewLogicalDrives = ::GetLogicalDrives();
if( dwNewLogicalDrives != m_dwLastLogicalDrives )
{
if( m_bReset )
vector<UsbStorageDeviceEx> vNewStorageDevices;
const int MAX_DRIVES = 26;
for( int i=2; i<MAX_DRIVES; i++ ) // skip 'a:" and "b:"
{
dwLastLogicalDrives = 0;
m_bReset = false;
DWORD mask = (1 << i);
if( dwNewLogicalDrives & mask ) // drive letter is valid
{
CString sDrive = ssprintf( "%c:\\", 'a'+i%26 );
LOG->Trace( "Found drive %s", sDrive.c_str() );
if( GetDriveType(sDrive) != DRIVE_REMOVABLE ) // is a removable drive
continue;
if( !TestReady(sDrive) )
continue;
UsbStorageDeviceEx usbd;
usbd.sOsMountDir = sDrive;
usbd.bWriteTestSucceeded = TestWrite( sDrive );
// read name
this->Mount( &usbd, TEMP_MOUNT_POINT );
FILEMAN->FlushDirCache( TEMP_MOUNT_POINT );
Profile profile;
CString sProfileDir = TEMP_MOUNT_POINT + PREFSMAN->m_sMemoryCardProfileSubdir + '/';
profile.LoadEditableDataFromDir( sProfileDir );
usbd.sName = profile.GetDisplayName();
vNewStorageDevices.push_back( usbd );
}
}
DWORD dwNewLogicalDrives = ::GetLogicalDrives();
if( dwNewLogicalDrives != dwLastLogicalDrives )
{
vector<UsbStorageDeviceEx> vNewStorageDevices;
const int MAX_DRIVES = 26;
for( int i=2; i<MAX_DRIVES; i++ ) // skip 'a:" and "b:"
{
DWORD mask = (1 << i);
if( dwNewLogicalDrives & mask ) // drive letter is valid
{
CString sDrive = ssprintf( "%c:\\", 'a'+i%26 );
LOG->Trace( "Found drive %s", sDrive.c_str() );
if( GetDriveType(sDrive) != DRIVE_REMOVABLE ) // is a removable drive
continue;
if( !TestReady(sDrive) )
continue;
UsbStorageDeviceEx usbd;
usbd.sOsMountDir = sDrive;
usbd.bWriteTestSucceeded = TestWrite( sDrive );
// read name
this->Mount( &usbd, TEMP_MOUNT_POINT );
FILEMAN->FlushDirCache( TEMP_MOUNT_POINT );
Profile profile;
CString sProfileDir = TEMP_MOUNT_POINT + PREFSMAN->m_sMemoryCardProfileSubdir + '/';
profile.LoadEditableDataFromDir( sProfileDir );
usbd.sName = profile.GetDisplayName();
vNewStorageDevices.push_back( usbd );
}
}
{
LockMut( m_mutexStorageDevices );
m_bStorageDevicesChanged = true;
m_vStorageDevices = vNewStorageDevices;
}
}
dwLastLogicalDrives = dwNewLogicalDrives;
::Sleep( 100 );
LockMut( m_mutexStorageDevices );
m_bStorageDevicesChanged = true;
m_vStorageDevices = vNewStorageDevices;
}
}
m_dwLastLogicalDrives = dwNewLogicalDrives;
::Sleep( 100 );
}
void MemoryCardDriverThreaded_Windows::Mount( UsbStorageDevice* pDevice, CString sMountPoint )
@@ -149,11 +142,6 @@ void MemoryCardDriverThreaded_Windows::Flush( UsbStorageDevice* pDevice )
// Windows flushes automatically every ~2 seconds. -Chris
}
void MemoryCardDriverThreaded_Windows::ResetUsbStorage()
{
m_bReset = true;
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
@@ -2,6 +2,7 @@
#define MemoryCardDriverThreaded_Windows_H 1
#include "MemoryCardDriverThreaded.h"
#include <windows.h>
class MemoryCardDriverThreaded_Windows : public MemoryCardDriverThreaded
{
@@ -10,12 +11,12 @@ public:
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void Flush( UsbStorageDevice* pDevice );
virtual void ResetUsbStorage();
protected:
virtual void MountThreadMain();
virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void MountThreadReset();
virtual void MountThreadDoOneUpdate();
bool m_bReset;
DWORD m_dwLastLogicalDrives;
};
#endif
@@ -13,7 +13,8 @@ public:
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint ) {}
virtual void Flush( UsbStorageDevice* pDevice ) {}
virtual void ResetUsbStorage() {}
virtual void PauseMountingThread() {}
virtual void UnPauseMountingThread() {}
};
#endif