move memory card mounting and unmounting into a separate thread

This commit is contained in:
Chris Danford
2004-03-21 22:32:16 +00:00
parent 0e75311fd0
commit 7b78dbcf1c
3 changed files with 148 additions and 50 deletions
@@ -7,6 +7,7 @@ struct UsbStorageDevice
void MakeBlank() void MakeBlank()
{ {
// -1 means "don't know"
iBus = -1; iBus = -1;
iDeviceOnBus = -1; iDeviceOnBus = -1;
iPortOnHub = -1; iPortOnHub = -1;
@@ -23,17 +24,18 @@ struct UsbStorageDevice
bool IsBlank() { return sOsMountDir.empty(); } bool IsBlank() { return sOsMountDir.empty(); }
bool operator==(const UsbStorageDevice& other) bool operator==(const UsbStorageDevice& other) const
{ {
// ugly... if( (iBus!=-1 || other.iBus!=-1) && iBus != other.iBus )
#if _WINDOWS return false;
// we don't have hub/port number info on Windows if( (iDeviceOnBus!=-1 || other.iDeviceOnBus!=-1) && iDeviceOnBus != other.iDeviceOnBus )
return sOsMountDir==other.sOsMountDir; // every time a device is plugged in, it gets a unique device number return false;
#else // LINUX or other return sOsMountDir==other.sOsMountDir; // every time a device is plugged in, it gets a unique device number
return iBus==other.iBus &&
iDeviceOnBus==other.iDeviceOnBus; // every time a device is plugged in, it gets a unique device number
#endif
} }
bool operator!=(const UsbStorageDevice& other) const
{
return !operator==(other);
}
}; };
class MemoryCardDriver class MemoryCardDriver
@@ -14,50 +14,138 @@
#include <fstream> #include <fstream>
static const char *USB_DEVICE_LIST_FILE = "/proc/bus/usb/devices"; static const char *USB_DEVICE_LIST_FILE = "/proc/bus/usb/devices";
static const char *ETC_MTAB = "/etc/mtab";
MemoryCardDriver_Linux::MemoryCardDriver_Linux() int MemoryCardDriver_Linux::MountThread_Start( void *p )
{ {
m_lastModTime = 0; ((MemoryCardDriver_Linux*)p)->MountThreadMain();
m_fds = open(USB_DEVICE_LIST_FILE, O_RDONLY); return 0;
if( m_fds == -1 ) }
LOG->Trace( "Failed to open \"%s\": %s", USB_DEVICE_LIST_FILE, strerror(errno) );
void MemoryCardDriver_Linux::MountThreadMain()
{
int fd = open(USB_DEVICE_LIST_FILE, O_RDONLY);
if( fd == -1 )
{
LOG->Warn( "Failed to open \"%s\": %s", USB_DEVICE_LIST_FILE, strerror(errno) );
return;
}
time_t lastModTime = 0;
vector<UsbStorageDevice> vDevicesLastSeen;
while( !shutdown )
{
struct stat st;
if( fstat(fd, &st) == -1 )
{
LOG->Warn( "stat '%s' failed: %s", USB_DEVICE_LIST_FILE, strerror(errno) );
close( fd );
return;
}
bool bChanged = st.st_mtime != lastModTime;
lastModTime = st.st_mtime;
if( bChanged )
{
// TRICKY: We're waiting for a change in the USB device list, but
// the usb-storage descriptors take a bit longer to update. It's more convenient to wait
// on the USB device list because the usb-storage descriptors are separate files per
// device. So, sleep for a little bit of time after we detect a new USB device and give
// usb-storage a chance to initialize.
usleep(1000*300);
vector<UsbStorageDevice> vDevicesNow;
this->GetStorageDevices( vDevicesNow );
bool bDevicesChanged = false;
if( vDevicesLastSeen.size() != vDevicesNow.size() )
{
bDevicesChanged = true;
}
else
{
for( unsigned i=0; i<vDevicesLastSeen.size(); i++ )
{
const UsbStorageDevice d1 = vDevicesLastSeen[i];
const UsbStorageDevice d2 = vDevicesNow[i];
if( d1 != d2 )
{
bDevicesChanged = true;
break;
}
}
}
if( bDevicesChanged )
{
// unmount all old devices
for( unsigned i=0; i<vDevicesLastSeen.size(); i++ )
{
const UsbStorageDevice d = vDevicesLastSeen[i];
CString sCommand = "umount " + d.sOsMountDir;
LOG->Trace( "executing '%s'", sCommand.c_str() );
if( system(sCommand) == -1 )
LOG->Warn( "failed to execute '%s'", sCommand.c_str() );
}
for( unsigned i=0; i<vDevicesNow.size(); i++ )
{
const UsbStorageDevice d = vDevicesNow[i];
CString sCommand = "mount " + d.sOsMountDir;
LOG->Trace( "executing '%s'", sCommand.c_str() );
if( system(sCommand) == -1 )
LOG->Warn( "failed to execute '%s'", sCommand.c_str() );
}
{
LockMut( m_StorageDevicesChangedMutex );
m_bStorageDevicesChanged = true;
}
}
vDevicesLastSeen = vDevicesNow;
}
usleep( 1000*100 ); // 100 ms
}
CHECKPOINT;
}
MemoryCardDriver_Linux::MemoryCardDriver_Linux() :
m_StorageDevicesChangedMutex("StorageDevicesChanged")
{
shutdown = false;
m_bStorageDevicesChanged = false;
MountThread.SetName("MemCard Mount thread");
MountThread.Create( MountThread_Start, this );
} }
MemoryCardDriver_Linux::~MemoryCardDriver_Linux() MemoryCardDriver_Linux::~MemoryCardDriver_Linux()
{ {
if( m_fds != -1 ) shutdown = true;
{ LOG->Trace( "Shutting down Mount thread..." );
close( m_fds ); MountThread.Wait();
m_fds = -1; LOG->Trace( "Mount thread shut down." );
}
} }
bool MemoryCardDriver_Linux::StorageDevicesChanged() bool MemoryCardDriver_Linux::StorageDevicesChanged()
{ {
// has USB_DEVICE_LIST_FILE changed? LockMut( m_StorageDevicesChangedMutex );
if( m_fds == -1 ) // file not opened if( m_bStorageDevicesChanged )
return false; // we'll never know... {
m_bStorageDevicesChanged = false;
struct stat st; return true;
if( fstat(m_fds, &st) == -1 ) }
{ else
LOG->Warn( "stat '%s' failed: %s", USB_DEVICE_LIST_FILE, strerror(errno) ); {
return false; return false;
} }
bool bChanged = st.st_mtime != m_lastModTime;
m_lastModTime = st.st_mtime;
return bChanged;
} }
void MemoryCardDriver_Linux::GetStorageDevices( vector<UsbStorageDevice>& vDevicesOut ) void MemoryCardDriver_Linux::GetStorageDevices( vector<UsbStorageDevice>& vDevicesOut )
{ {
/* If we couldn't open it before, we probably can't open it now; don't
* output more errors. */
if( m_fds == -1 )
return;
vDevicesOut.clear(); vDevicesOut.clear();
{ {
@@ -235,12 +323,13 @@ bool MemoryCardDriver_Linux::MountAndTestWrite( UsbStorageDevice* pDevice, CStri
if( pDevice->sOsMountDir.empty() ) if( pDevice->sOsMountDir.empty() )
return false; return false;
CString sCommand = "umount " + pDevice->sOsMountDir; // Already mounted by the mount thread
LOG->Trace( "executing '%s'", sCommand.c_str() ); //CString sCommand = "umount " + pDevice->sOsMountDir;
system( sCommand ); //LOG->Trace( "executing '%s'", sCommand.c_str() );
sCommand = "mount " + pDevice->sOsMountDir; //system( sCommand );
LOG->Trace( "executing '%s'", sCommand.c_str() ); //sCommand = "mount " + pDevice->sOsMountDir;
system( sCommand ); //LOG->Trace( "executing '%s'", sCommand.c_str() );
//system( sCommand );
// Try to write a file. // Try to write a file.
// TODO: Can we use RageFile for this? // TODO: Can we use RageFile for this?
@@ -277,9 +366,10 @@ void MemoryCardDriver_Linux::Unmount( UsbStorageDevice* pDevice, CString sMountP
if( pDevice->sOsMountDir.empty() ) if( pDevice->sOsMountDir.empty() )
return; return;
CString sCommand = "umount " + pDevice->sOsMountDir; // already unmounted by the mounting thread
LOG->Trace( "executing '%s'", sCommand.c_str() ); //CString sCommand = "umount " + pDevice->sOsMountDir;
system( sCommand ); //LOG->Trace( "executing '%s'", sCommand.c_str() );
//system( sCommand );
} }
void MemoryCardDriver_Linux::Flush( UsbStorageDevice* pDevice ) void MemoryCardDriver_Linux::Flush( UsbStorageDevice* pDevice )
@@ -2,6 +2,7 @@
#define MEMORY_CARD_DRIVER_LINUX_H 1 #define MEMORY_CARD_DRIVER_LINUX_H 1
#include "MemoryCardDriver.h" #include "MemoryCardDriver.h"
#include "RageThreads.h"
class MemoryCardDriver_Linux : public MemoryCardDriver class MemoryCardDriver_Linux : public MemoryCardDriver
{ {
@@ -14,9 +15,14 @@ public:
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint ); virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint );
virtual void Flush( UsbStorageDevice* pDevice ); virtual void Flush( UsbStorageDevice* pDevice );
virtual void ResetUsbStorage(); virtual void ResetUsbStorage();
static int MountThread_Start( void *p );
void MountThreadMain();
protected: protected:
int m_fds; RageThread MountThread;
time_t m_lastModTime; bool shutdown;
RageMutex m_StorageDevicesChangedMutex;
bool m_bStorageDevicesChanged;
}; };
#endif #endif