diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp index d5eb115c39..9fe5c49557 100644 --- a/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp +++ b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp @@ -16,6 +16,7 @@ #include #include #include +#include const CString TEMP_MOUNT_POINT = "@mctemp/"; @@ -132,119 +133,113 @@ void MemoryCardDriverThreaded_Linux::MountThreadMain() LOG->Warn( "Failed to open \"%s\": %s", USB_DEVICE_LIST_FILE, strerror(errno) ); return; } - - time_t lastModTime = 0; - + vector vDevicesLastSeen; - + while( !m_bShutdown ) { - 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; - - // TRICKY: The file time only has a resolution of one second. So, if the file - // changes more than one time in one second, we'll only pick up the first change. - // Hack around this by continually scanning for changes in any second that we detect - // a change. - if( bChanged || time(NULL)+1 <= lastModTime ) + pollfd pfd = { fd, POLLIN, 0 }; + int ret = poll( &pfd, 1, 100 ); + switch( ret ) { - // 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; - GetNewStorageDevices( vDevicesNow ); - - vector &vNew = vDevicesNow; - vector &vOld = vDevicesLastSeen; - - // check for disconnects - vector vDisconnects; - for( unsigned i=0; iTrace( ssprintf("Disconnected bus %d port %d level %d path %s", old.iBus, old.iPort, old.iLevel, old.sOsMountDir.c_str()) ); - vDisconnects.push_back( &old ); - } - } - - // check for connects - vector vConnects; - for( unsigned i=0; iTrace( ssprintf("Connected bus %d port %d level %d path %s", newd.iBus, newd.iPort, newd.iLevel, newd.sOsMountDir.c_str()) ); - vConnects.push_back( &newd ); - } - } - - // unmount all disconnects - for( unsigned i=0; iMount( &d, TEMP_MOUNT_POINT ); - FILEMAN->FlushDirCache( TEMP_MOUNT_POINT ); - Profile profile; - CString sProfileDir = TEMP_MOUNT_POINT + PREFSMAN->m_sMemoryCardProfileSubdir + '/'; - profile.LoadEditableDataFromDir( sProfileDir ); - d.sName = profile.GetDisplayName(); - - LOG->Trace( "write test %s", d.bWriteTestSucceeded ? "succeeded" : "failed" ); - } - - if( !vDisconnects.empty() || !vConnects.empty() ) - { - LockMut( m_mutexStorageDevices ); - m_bStorageDevicesChanged = true; - m_vStorageDevices = vDevicesNow; - for( unsigned i=0; iTrace( "index %d, bWriteTestSucceeded %d", i, d.bWriteTestSucceeded ); - } - } - - vDevicesLastSeen = vDevicesNow; + case 1: + // file changed. Fall through. + break; + case 0: // no change. Poll again. + continue; + case -1: + LOG->Warn( "Error polling" ); + continue; } - usleep( 1000*100 ); // 100 ms + + // 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; + GetNewStorageDevices( vDevicesNow ); + + vector &vNew = vDevicesNow; + vector &vOld = vDevicesLastSeen; + + // check for disconnects + vector vDisconnects; + for( unsigned i=0; iTrace( ssprintf("Disconnected bus %d port %d level %d path %s", old.iBus, old.iPort, old.iLevel, old.sOsMountDir.c_str()) ); + vDisconnects.push_back( &old ); + } + } + + // check for connects + vector vConnects; + for( unsigned i=0; iTrace( ssprintf("Connected bus %d port %d level %d path %s", newd.iBus, newd.iPort, newd.iLevel, newd.sOsMountDir.c_str()) ); + vConnects.push_back( &newd ); + } + } + + // unmount all disconnects + for( unsigned i=0; iMount( &d, TEMP_MOUNT_POINT ); + FILEMAN->FlushDirCache( TEMP_MOUNT_POINT ); + Profile profile; + CString sProfileDir = TEMP_MOUNT_POINT + PREFSMAN->m_sMemoryCardProfileSubdir + '/'; + profile.LoadEditableDataFromDir( sProfileDir ); + d.sName = profile.GetDisplayName(); + + LOG->Trace( "write test %s", d.bWriteTestSucceeded ? "succeeded" : "failed" ); + } + + if( !vDisconnects.empty() || !vConnects.empty() ) + { + LockMut( m_mutexStorageDevices ); + m_bStorageDevicesChanged = true; + m_vStorageDevices = vDevicesNow; + for( unsigned i=0; iTrace( "index %d, bWriteTestSucceeded %d", i, d.bWriteTestSucceeded ); + } + } + + vDevicesLastSeen = vDevicesNow; } + CHECKPOINT; }