synchronize access to memory cards between mounting thread and main thread Profile Load/Save
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user