From 97a4a65b26c56737d44d32431af2fb41879d8008 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 6 Feb 2005 08:48:55 +0000 Subject: [PATCH] Unmount cards if we time out. "Locking" and "finalizing" are the same; merge them. (They're both enabled and disabled in the same place.) Pause the memory card thread during gameplay, so any changes will wait until the current stage finishes (so we don't interrupt the player with a noise and possibly skip). Work on making MemoryCardManager::LockCards() block if the card is in CHECKING. --- stepmania/src/GameState.cpp | 5 +- stepmania/src/MemoryCardManager.cpp | 125 ++++++++++++++-------------- stepmania/src/MemoryCardManager.h | 12 ++- stepmania/src/ScreenGameplay.cpp | 7 ++ 4 files changed, 75 insertions(+), 74 deletions(-) diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index d1d1bcae16..192f0ecce5 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -115,7 +115,6 @@ void GameState::Reset() m_pCurStyle = NULL; FOREACH_PlayerNumber( p ) m_bSideIsJoined[p] = false; - MEMCARDMAN->SetPlayersFinalized( false ); MEMCARDMAN->UnlockCards(); // m_iCoins = 0; // don't reset coin count! m_MasterPlayerNumber = PLAYER_INVALID; @@ -230,11 +229,9 @@ void GameState::BeginGame() void GameState::PlayersFinalized() { - if( MEMCARDMAN->GetPlayersFinalized() ) + if( MEMCARDMAN->GetCardsLocked() ) return; - MEMCARDMAN->SetPlayersFinalized( true ); - MEMCARDMAN->LockCards(); // apply saved default modifiers if any diff --git a/stepmania/src/MemoryCardManager.cpp b/stepmania/src/MemoryCardManager.cpp index e591c1dbc1..9ef7d9a507 100644 --- a/stepmania/src/MemoryCardManager.cpp +++ b/stepmania/src/MemoryCardManager.cpp @@ -73,6 +73,8 @@ private: bool m_bUsbStorageDevicesChanged; vector m_aUsbStorageDevices; + vector m_aMountedDevices; + enum { REQ_MOUNT, @@ -135,11 +137,20 @@ void ThreadedMemoryCardWorker::HandleRequest( int iRequest ) { case REQ_MOUNT: m_bResult = m_pDriver->Mount( &m_RequestDevice ); + m_aMountedDevices.push_back( m_RequestDevice ); break; case REQ_UNMOUNT: + { m_pDriver->Unmount( &m_RequestDevice ); + vector::iterator it = + find( m_aMountedDevices.begin(), m_aMountedDevices.end(), m_RequestDevice ); + if( it == m_aMountedDevices.end() ) + LOG->Warn( "Unmounted a device that wasn't mounted" ); + else + m_aMountedDevices.erase( it ); break; + } case REQ_FLUSH: m_pDriver->Flush( &m_RequestDevice ); @@ -152,6 +163,13 @@ void ThreadedMemoryCardWorker::HandleRequest( int iRequest ) void ThreadedMemoryCardWorker::RequestTimedOut() { + /* We timed out, so the current operation will abort. The unmount request + * may be skipped, if it's attempted during the timeout, so unmount all + * mounted devices. */ + for( unsigned i = 0; i < m_aMountedDevices.size(); ++i ) + m_pDriver->Unmount( &m_aMountedDevices[i] ); + + m_aMountedDevices.clear(); } void ThreadedMemoryCardWorker::DoHeartbeat() @@ -244,8 +262,6 @@ MemoryCardManager::MemoryCardManager() m_State[p] = MEMORY_CARD_STATE_NO_CARD; } - m_bPlayersFinalized = false; - /* These can play at any time. Preload them, so we don't cause a skip in gameplay. */ m_soundReady.Load( THEME->GetPathS("MemoryCardManager","ready"), true ); m_soundError.Load( THEME->GetPathS("MemoryCardManager","error"), true ); @@ -396,7 +412,7 @@ void MemoryCardManager::CheckStateChanges() MemoryCardState state = MEMORY_CARD_STATE_INVALID; - if( m_bPlayersFinalized ) + if( m_bCardsLocked ) { if( m_FinalDevice[p].m_State == UsbStorageDevice::STATE_NONE ) { @@ -482,6 +498,44 @@ void MemoryCardManager::LockCards() if( m_bCardsLocked ) return; + g_pWorker->SetTimeout( 5 ); + + /* If either player's card is in STATE_CHECKING, we need to give it a chance + * to finish up before returning. */ + while( !g_pWorker->IsTimedOut() ) + { + /* Check for changes. */ + Update(0); + + bool bEitherPlayerIsChecking = false; + FOREACH_PlayerNumber( p ) + if( m_Device[p].m_State == UsbStorageDevice::STATE_CHECKING ) + bEitherPlayerIsChecking = true; + if( !bEitherPlayerIsChecking ) + break; + + /* Only if we need to, wait for something to happen. If we time out waiting for + *a heartbeat, give up. */ + if( !g_pWorker->WaitForOneHeartbeat() ) + break; + } + + g_pWorker->SetTimeout( -1 ); + + /* Set the final state. */ + CheckStateChanges(); + + FOREACH_PlayerNumber( p ) + { + /* If the card in this player's slot is ready, then use it. If there is + * no card ready when we finalize, clear m_FinalDevice. */ + if( m_Device[p].m_State == UsbStorageDevice::STATE_READY ) + m_FinalDevice[p] = m_Device[p]; + else + m_FinalDevice[p] = UsbStorageDevice(); + } + + /* Set this last, since it changes the behavior of CheckStateChanges. */ m_bCardsLocked = true; } @@ -489,11 +543,10 @@ void MemoryCardManager::UnlockCards() { m_bCardsLocked = false; - // clear too late flag -// FOREACH_PlayerNumber( p ) -// m_State[p] = MEMORY_CARD_STATE_NO_CARD; - g_pWorker->SetMountThreadState( ThreadedMemoryCardWorker::detect_and_mount ); + + /* If a memory card was inserted too late last game, allow it now. */ + CheckStateChanges(); } /* Called just before reading or writing to the memory card. Should block. */ @@ -553,7 +606,7 @@ void MemoryCardManager::UnmountCard( PlayerNumber pn ) if( !m_bMounted[pn] ) return; - /* Leave our own filesystem drivers mounted. */ + /* Leave our own filesystem drivers mounted. Unmount the kernel mount. */ g_pWorker->Unmount( &m_Device[pn] ); m_bMounted[pn] = false; @@ -582,58 +635,6 @@ void MemoryCardManager::FlushAndReset() g_pWorker->Reset(); // forces cards to be re-detected } -void MemoryCardManager::SetPlayersFinalized( bool bOn ) -{ - m_bPlayersFinalized = bOn; - - if( !bOn ) - { - m_bPlayersFinalized = false; - - /* If a memory card was inserted too late last game, allow it now. */ - CheckStateChanges(); - return; - } - -// g_pWorker->SetTimeout( 10 ); -// ASSERT( g_pWorker->TimeoutEnabled() ); - - /* XXX: wait */ - - FOREACH_PlayerNumber( p ) - { - /* If the card in this player's slot is ready, then use it. */ - // XXX: share code with Update(): keep updating until timed out or - // STATE_READY or STATE_NONE - UsbStorageDevice &d = m_Device[p]; - - /* Set the final state. */ - switch( d.m_State ) - { - case UsbStorageDevice::STATE_READY: - m_State[p] = MEMORY_CARD_STATE_READY; - m_FinalDevice[p] = d; - break; - - case UsbStorageDevice::STATE_NONE: - m_State[p] = MEMORY_CARD_STATE_NO_CARD; - break; - - case UsbStorageDevice::STATE_CHECKING: - case UsbStorageDevice::STATE_WRITE_ERROR: - m_State[p] = MEMORY_CARD_STATE_WRITE_ERROR; - break; - - default: - FAIL_M( ssprintf("%i", d.m_State) ); - } - - /* If there is no card ready when we finalize, the final device must be blank. */ - if( m_State[p] != MEMORY_CARD_STATE_READY ) - m_FinalDevice[p] = UsbStorageDevice(); - } -} - bool MemoryCardManager::PathIsMemCard( CString sDir ) const { FOREACH_PlayerNumber( p ) @@ -663,9 +664,7 @@ void MemoryCardManager::PauseMountingThread() void MemoryCardManager::UnPauseMountingThread() { - g_pWorker->SetMountThreadState( - m_bCardsLocked ? - ThreadedMemoryCardWorker::detect_and_dont_mount : ThreadedMemoryCardWorker::detect_and_mount ); + g_pWorker->SetMountThreadState( ThreadedMemoryCardWorker::detect_and_mount ); /* End the timeout period. */ g_pWorker->SetTimeout( -1 ); diff --git a/stepmania/src/MemoryCardManager.h b/stepmania/src/MemoryCardManager.h index 720b05ef38..eac9566d70 100644 --- a/stepmania/src/MemoryCardManager.h +++ b/stepmania/src/MemoryCardManager.h @@ -23,12 +23,14 @@ public: void UnlockCards(); void MountCard( PlayerNumber pn ); void UnmountCard( PlayerNumber pn ); + + /* When paused, no changes in memory card state will be noticed until unpaused. */ + void PauseMountingThread(); + void UnPauseMountingThread(); void FlushAndReset(); // force all files to be flushed to mounted memory cards - /* If bOn is true, and a card is still initializing, block until it's ready. */ - void SetPlayersFinalized( bool bOn ); - bool GetPlayersFinalized() const { return m_bPlayersFinalized; } + bool GetCardsLocked() const { return m_bCardsLocked; } bool PathIsMemCard( CString sDir ) const; @@ -36,8 +38,6 @@ public: CString GetName( PlayerNumber pn ) const; protected: - void PauseMountingThread(); // call this before mouting, reading, or writing to memory card - void UnPauseMountingThread(); // call this when done mouting, reading, or writing to memory card void CheckStateChanges(); vector m_vStorageDevices; // all currently connected @@ -51,8 +51,6 @@ protected: MemoryCardState m_State[NUM_PLAYERS]; - bool m_bPlayersFinalized; - RageSound m_soundReady; RageSound m_soundError; RageSound m_soundTooLate; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index b4e9d9dbe0..cc2ee9c041 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -46,6 +46,7 @@ #include "GameplayMessages.h" #include "Style.h" #include "LuaManager.h" +#include "MemoryCardManager.h" // // Defines @@ -96,6 +97,10 @@ void ScreenGameplay::Init() { Screen::Init(); + /* Pause MEMCARDMAN. If a memory card is remove, we don't want to interrupt the + * player by making a noise until the game finishes. */ + MEMCARDMAN->PauseMountingThread(); + if( GAMESTATE->m_bDemonstrationOrJukebox ) LIGHTSMAN->SetLightsMode( LIGHTSMODE_DEMONSTRATION ); else @@ -779,6 +784,8 @@ ScreenGameplay::~ScreenGameplay() LOG->Trace( "ScreenGameplay::~ScreenGameplay()" ); + MEMCARDMAN->UnPauseMountingThread(); + FOREACH_PlayerNumber(p) { SAFE_DELETE( m_pLifeMeter[p] );