diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriver.h b/stepmania/src/arch/MemoryCard/MemoryCardDriver.h index e4067d30b0..8be79b8a2e 100644 --- a/stepmania/src/arch/MemoryCard/MemoryCardDriver.h +++ b/stepmania/src/arch/MemoryCard/MemoryCardDriver.h @@ -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 diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.cpp b/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.cpp index df37b35c5e..407e373684 100644 --- a/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.cpp +++ b/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.cpp @@ -14,50 +14,138 @@ #include 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 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 vDevicesNow; + this->GetStorageDevices( vDevicesNow ); + + bool bDevicesChanged = false; + if( vDevicesLastSeen.size() != vDevicesNow.size() ) + { + bDevicesChanged = true; + } + else + { + for( unsigned i=0; iTrace( "executing '%s'", sCommand.c_str() ); + if( system(sCommand) == -1 ) + LOG->Warn( "failed to execute '%s'", sCommand.c_str() ); + } + + for( unsigned i=0; iTrace( "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& 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 ) diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.h b/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.h index f5bb4ec336..b9aa9125a1 100644 --- a/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.h +++ b/stepmania/src/arch/MemoryCard/MemoryCardDriver_Linux.h @@ -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