move memory card mounting and unmounting into a separate thread
This commit is contained in:
@@ -7,6 +7,7 @@ struct UsbStorageDevice
|
||||
|
||||
void MakeBlank()
|
||||
{
|
||||
// -1 means "don't know"
|
||||
iBus = -1;
|
||||
iDeviceOnBus = -1;
|
||||
iPortOnHub = -1;
|
||||
@@ -23,17 +24,18 @@ struct UsbStorageDevice
|
||||
|
||||
bool IsBlank() { return sOsMountDir.empty(); }
|
||||
|
||||
bool operator==(const UsbStorageDevice& other)
|
||||
bool operator==(const UsbStorageDevice& other) const
|
||||
{
|
||||
// ugly...
|
||||
#if _WINDOWS
|
||||
// we don't have hub/port number info on Windows
|
||||
return sOsMountDir==other.sOsMountDir; // every time a device is plugged in, it gets a unique device number
|
||||
#else // LINUX or other
|
||||
return iBus==other.iBus &&
|
||||
iDeviceOnBus==other.iDeviceOnBus; // every time a device is plugged in, it gets a unique device number
|
||||
#endif
|
||||
if( (iBus!=-1 || other.iBus!=-1) && iBus != other.iBus )
|
||||
return false;
|
||||
if( (iDeviceOnBus!=-1 || other.iDeviceOnBus!=-1) && iDeviceOnBus != other.iDeviceOnBus )
|
||||
return false;
|
||||
return sOsMountDir==other.sOsMountDir; // every time a device is plugged in, it gets a unique device number
|
||||
}
|
||||
bool operator!=(const UsbStorageDevice& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryCardDriver
|
||||
|
||||
@@ -14,50 +14,138 @@
|
||||
#include <fstream>
|
||||
|
||||
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;
|
||||
m_fds = open(USB_DEVICE_LIST_FILE, O_RDONLY);
|
||||
if( m_fds == -1 )
|
||||
LOG->Trace( "Failed to open \"%s\": %s", USB_DEVICE_LIST_FILE, strerror(errno) );
|
||||
((MemoryCardDriver_Linux*)p)->MountThreadMain();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if( m_fds != -1 )
|
||||
{
|
||||
close( m_fds );
|
||||
m_fds = -1;
|
||||
}
|
||||
shutdown = true;
|
||||
LOG->Trace( "Shutting down Mount thread..." );
|
||||
MountThread.Wait();
|
||||
LOG->Trace( "Mount thread shut down." );
|
||||
}
|
||||
|
||||
bool MemoryCardDriver_Linux::StorageDevicesChanged()
|
||||
{
|
||||
// has USB_DEVICE_LIST_FILE changed?
|
||||
if( m_fds == -1 ) // file not opened
|
||||
return false; // we'll never know...
|
||||
|
||||
struct stat st;
|
||||
if( fstat(m_fds, &st) == -1 )
|
||||
{
|
||||
LOG->Warn( "stat '%s' failed: %s", USB_DEVICE_LIST_FILE, strerror(errno) );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bChanged = st.st_mtime != m_lastModTime;
|
||||
m_lastModTime = st.st_mtime;
|
||||
|
||||
return bChanged;
|
||||
LockMut( m_StorageDevicesChangedMutex );
|
||||
if( m_bStorageDevicesChanged )
|
||||
{
|
||||
m_bStorageDevicesChanged = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
{
|
||||
@@ -235,12 +323,13 @@ bool MemoryCardDriver_Linux::MountAndTestWrite( UsbStorageDevice* pDevice, CStri
|
||||
if( pDevice->sOsMountDir.empty() )
|
||||
return false;
|
||||
|
||||
CString sCommand = "umount " + pDevice->sOsMountDir;
|
||||
LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
system( sCommand );
|
||||
sCommand = "mount " + pDevice->sOsMountDir;
|
||||
LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
system( sCommand );
|
||||
// Already mounted by the mount thread
|
||||
//CString sCommand = "umount " + pDevice->sOsMountDir;
|
||||
//LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
//system( sCommand );
|
||||
//sCommand = "mount " + pDevice->sOsMountDir;
|
||||
//LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
//system( sCommand );
|
||||
|
||||
// Try to write a file.
|
||||
// TODO: Can we use RageFile for this?
|
||||
@@ -277,9 +366,10 @@ void MemoryCardDriver_Linux::Unmount( UsbStorageDevice* pDevice, CString sMountP
|
||||
if( pDevice->sOsMountDir.empty() )
|
||||
return;
|
||||
|
||||
CString sCommand = "umount " + pDevice->sOsMountDir;
|
||||
LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
system( sCommand );
|
||||
// already unmounted by the mounting thread
|
||||
//CString sCommand = "umount " + pDevice->sOsMountDir;
|
||||
//LOG->Trace( "executing '%s'", sCommand.c_str() );
|
||||
//system( sCommand );
|
||||
}
|
||||
|
||||
void MemoryCardDriver_Linux::Flush( UsbStorageDevice* pDevice )
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MEMORY_CARD_DRIVER_LINUX_H 1
|
||||
|
||||
#include "MemoryCardDriver.h"
|
||||
#include "RageThreads.h"
|
||||
|
||||
class MemoryCardDriver_Linux : public MemoryCardDriver
|
||||
{
|
||||
@@ -14,9 +15,14 @@ public:
|
||||
virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint );
|
||||
virtual void Flush( UsbStorageDevice* pDevice );
|
||||
virtual void ResetUsbStorage();
|
||||
static int MountThread_Start( void *p );
|
||||
void MountThreadMain();
|
||||
protected:
|
||||
int m_fds;
|
||||
time_t m_lastModTime;
|
||||
RageThread MountThread;
|
||||
bool shutdown;
|
||||
|
||||
RageMutex m_StorageDevicesChangedMutex;
|
||||
bool m_bStorageDevicesChanged;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user