move memory card mounting and unmounting into a separate thread
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user