static void InitThreads() { /* We don't have to worry about two threads calling this at once, since it's * called when we create a thread. */ static bool bInitialized = false; if( bInitialized ) return; g_ThreadSlotsLock.Lock(); /* Libraries might start threads on their own, which might call user callbacks, * which could come back here. Make sure we don't accidentally initialize twice. */ if( bInitialized ) { g_ThreadSlotsLock.Unlock(); return; } bInitialized = true; /* Register the "unknown thread" slot. */ int slot = FindEmptyThreadSlot(); strcpy( g_ThreadSlots[slot].name, "Unknown thread" ); g_ThreadSlots[slot].id = GetInvalidThreadId(); sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" ); g_pUnknownThreadSlot = &g_ThreadSlots[slot]; g_ThreadSlotsLock.Unlock(); }
/* Wait for the specified network event to occur, or cancellation, whichever * happens first. On cancellation, return -1; on error, return the error * code; on success, return 0. */ int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent ) { while(1) { int iRet = WaitForSingleObject( m_hCompletionEvent, INFINITE ); if( iRet != WAIT_OBJECT_0 ) continue; m_Mutex.Lock(); // This will reset the event. Do this while we hold the lock. WSANETWORKEVENTS events; WSAEnumNetworkEvents( m_Socket, m_hCompletionEvent, &events ); // Was the event signalled due to cancellation? if( m_State == STATE_CANCELLED ) { m_Mutex.Unlock(); return -1; } m_Mutex.Unlock(); // If the event didn't actually occur, keep waiting. if( (events.lNetworkEvents & (1<<iEvent)) ) return events.iErrorCode[iEvent]; /* If the socket was closed while we were waiting, stop. Note that when the * connection closes immediately after sending data, we'll receive both this * message and FD_READ at the same time. Only do this if the event we really * want hasn't happened yet. */ if( (events.lNetworkEvents & (1<<FD_CLOSE_BIT)) ) return WSAECONNRESET; } }
/* Set the timeout length, and reset the timer. */ void RageFileDriverTimeout::SetTimeout( float fSeconds ) { g_apWorkersMutex.Lock(); for( unsigned i = 0; i < g_apWorkers.size(); ++i ) g_apWorkers[i]->SetTimeout( fSeconds ); g_apWorkersMutex.Unlock(); }
const PolyphaseFilter *MakePolyphaseFilter( int iUpFactor, float fCutoffFrequency ) { PolyphaseFiltersLock.Lock(); pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency) ); FilterMap::const_iterator it = g_mapPolyphaseFilters.find(params); if( it != g_mapPolyphaseFilters.end() ) { /* We already have a filter for this upsampling factor and cutoff; use it. */ PolyphaseFilter *pPolyphase = it->second; PolyphaseFiltersLock.Unlock(); return pPolyphase; } int iWinSize = L*iUpFactor; float *pFIR = new float[iWinSize]; GenerateSincLowPassFilter( pFIR, iWinSize, fCutoffFrequency ); ApplyKaiserWindow( pFIR, iWinSize, 8 ); NormalizeVector( pFIR, iWinSize ); MultiplyVector( &pFIR[0], &pFIR[iWinSize], (float) iUpFactor ); PolyphaseFilter *pPolyphase = new PolyphaseFilter( iUpFactor ); pPolyphase->Generate( pFIR ); delete [] pFIR; g_mapPolyphaseFilters[params] = pPolyphase; PolyphaseFiltersLock.Unlock(); return pPolyphase; }
void RageSoundManager::Update(float delta) { FlushPosMapQueue(); /* Scan the owned_sounds list for sounds that are no longer playing, and delete them. */ g_SoundManMutex.Lock(); /* lock for access to owned_sounds */ set<RageSound *> ToDelete; for( set<RageSound *>::iterator it = owned_sounds.begin(); it != owned_sounds.end(); ++it ) { RageSound *pSound = *it; if( pSound->IsPlaying() ) continue; LOG->Trace("XXX: deleting '%s'", pSound->GetLoadedFilePath().c_str()); ToDelete.insert( pSound ); } for( set<RageSound *>::iterator it = ToDelete.begin(); it != ToDelete.end(); ++it ) owned_sounds.erase( *it ); g_SoundManMutex.Unlock(); /* finished with owned_sounds */ /* Be sure to release g_SoundManMutex before deleting sounds. */ for( set<RageSound *>::iterator it = ToDelete.begin(); it != ToDelete.end(); ++it ) delete *it; if( driver != NULL ) driver->Update(delta); }
RageSoundManager::~RageSoundManager() { g_SoundManMutex.Lock(); /* lock for access to owned_sounds */ set<RageSound *> sounds = owned_sounds; g_SoundManMutex.Unlock(); /* finished with owned_sounds */ /* Clear any sounds that we own and havn't freed yet. */ set<RageSound *>::iterator j = sounds.begin(); while(j != sounds.end()) delete *(j++); /* Don't lock while deleting the driver (the decoder thread might deadlock). */ delete driver; }
const PolyphaseFilter *FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency ) { /* Find a cached filter with the same iUpFactor and a nearby cutoff frequency. * Round the cutoff down, if possible; it's better to filter out too much than * too little. */ PolyphaseFiltersLock.Lock(); pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency + 0.0001f) ); FilterMap::const_iterator it = g_mapPolyphaseFilters.upper_bound( params ); if( it != g_mapPolyphaseFilters.begin() ) --it; ASSERT( it->first.first == iUpFactor ); PolyphaseFilter *pPolyphase = it->second; PolyphaseFiltersLock.Unlock(); return pPolyphase; }
bool ThreadedMemoryCardWorker::StorageDevicesChanged( vector<UsbStorageDevice> &aOut ) { UsbStorageDevicesMutex.Lock(); if( !m_bUsbStorageDevicesChanged ) { UsbStorageDevicesMutex.Unlock(); return false; } aOut = m_aUsbStorageDevices; m_aUsbStorageDevices.clear(); m_bUsbStorageDevicesChanged = false; UsbStorageDevicesMutex.Unlock(); return true; }
void NetworkStream_Win32::SetError( const RString &sError ) { m_Mutex.Lock(); if( m_State != STATE_CANCELLED ) { m_sError = sError; m_State = STATE_ERROR; } if( m_Socket != INVALID_SOCKET ) { closesocket( m_Socket ); m_Socket = INVALID_SOCKET; } m_Mutex.Unlock(); }
void ThreadedMemoryCardWorker::DoHeartbeat() { if( m_MountThreadState == paused ) return; // If true, detect and mount. If false, only detect. bool bMount = (m_MountThreadState == detect_and_mount); vector<UsbStorageDevice> aStorageDevices; //LOG->Trace("update"); if( !m_pDriver->DoOneUpdate( bMount, aStorageDevices ) ) return; UsbStorageDevicesMutex.Lock(); m_aUsbStorageDevices = aStorageDevices; m_bUsbStorageDevicesChanged = true; UsbStorageDevicesMutex.Unlock(); }
ThreadedFileWorker::~ThreadedFileWorker() { StopThread(); if( m_pChildDriver != NULL ) FILEMAN->ReleaseFileDriver( m_pChildDriver ); /* Unregister ourself. */ g_apWorkersMutex.Lock(); for( unsigned i = 0; i < g_apWorkers.size(); ++i ) { if( g_apWorkers[i] == this ) { g_apWorkers.erase( g_apWorkers.begin()+i ); break; } } g_apWorkersMutex.Unlock(); }
void NetworkStream_Win32::Close() { if( m_State == STATE_IDLE ) return; /* If we have an active, stable connection, make sure we flush any data * completely before closing. If you don't want to do this, call Cancel() * first. */ Shutdown(); m_Mutex.Lock(); if( m_State == STATE_CANCELLED ) return; if( m_Socket != INVALID_SOCKET ) closesocket( m_Socket ); m_Socket = INVALID_SOCKET; m_State = STATE_IDLE; m_Mutex.Unlock(); }
ThreadedFileWorker::ThreadedFileWorker( CString sPath ): RageWorkerThread( sPath ), m_DeletedFilesLock( sPath + "DeletedFilesLock" ) { /* Grab a reference to the child driver. We'll operate on it directly. */ m_pChildDriver = FILEMAN->GetFileDriver( sPath ); if( m_pChildDriver == NULL ) WARN( ssprintf("ThreadedFileWorker: Mountpoint \"%s\" not found", sPath.c_str()) ); m_pResultFile = NULL; m_pRequestFile = NULL; m_pResultBuffer = NULL; m_pRequestBuffer = NULL; g_apWorkersMutex.Lock(); g_apWorkers.push_back( this ); g_apWorkersMutex.Unlock(); StartThread(); }
void RageMutex::Lock() { if( m_LockedBy == (uint64_t) GetThisThreadId() ) { ++m_LockCnt; return; } if( !m_pMutex->Lock() ) { const ThreadSlot *ThisSlot = GetThreadSlotFromID( GetThisThreadId() ); const ThreadSlot *OtherSlot = GetThreadSlotFromID( m_LockedBy ); CString ThisSlotName = "(???" ")"; // stupid trigraph warnings CString OtherSlotName = "(???" ")"; // stupid trigraph warnings if( ThisSlot ) ThisSlotName = ssprintf( "%s (%i)", ThisSlot->GetThreadName(), (int) ThisSlot->id ); if( OtherSlot ) OtherSlotName = ssprintf( "%s (%i)", OtherSlot->GetThreadName(), (int) OtherSlot->id ); const CString sReason = ssprintf( "Thread deadlock on mutex %s between %s and %s", GetName().c_str(), ThisSlotName.c_str(), OtherSlotName.c_str() ); #if defined(CRASH_HANDLER) /* Don't leave g_ThreadSlotsLock when we call ForceCrashHandlerDeadlock. */ g_ThreadSlotsLock.Lock(); uint64_t CrashHandle = OtherSlot? OtherSlot->id:0; g_ThreadSlotsLock.Unlock(); /* Pass the crash handle of the other thread, so it can backtrace that thread. */ ForceCrashHandlerDeadlock( sReason, CrashHandle ); #else FAIL_M( sReason ); #endif } m_LockedBy = GetThisThreadId(); /* This has internal thread safety issues itself (eg. one thread may delete * a mutex while another locks one); disable for now. */ // MarkLockedMutex(); }
namespace PolyphaseFilterCache { /* Cache filter data, and reuse it without copying. All operations after creation * are const, so this doesn't cause thread-safety problems. */ typedef map<pair<int,float>, PolyphaseFilter *> FilterMap; static RageMutex PolyphaseFiltersLock("PolyphaseFiltersLock"); static FilterMap g_mapPolyphaseFilters; const PolyphaseFilter *MakePolyphaseFilter( int iUpFactor, float fCutoffFrequency ) { PolyphaseFiltersLock.Lock(); pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency) ); FilterMap::const_iterator it = g_mapPolyphaseFilters.find(params); if( it != g_mapPolyphaseFilters.end() ) { /* We already have a filter for this upsampling factor and cutoff; use it. */ PolyphaseFilter *pPolyphase = it->second; PolyphaseFiltersLock.Unlock(); return pPolyphase; } int iWinSize = L*iUpFactor; float *pFIR = new float[iWinSize]; GenerateSincLowPassFilter( pFIR, iWinSize, fCutoffFrequency ); ApplyKaiserWindow( pFIR, iWinSize, 8 ); NormalizeVector( pFIR, iWinSize ); MultiplyVector( &pFIR[0], &pFIR[iWinSize], (float) iUpFactor ); PolyphaseFilter *pPolyphase = new PolyphaseFilter( iUpFactor ); pPolyphase->Generate( pFIR ); delete [] pFIR; g_mapPolyphaseFilters[params] = pPolyphase; PolyphaseFiltersLock.Unlock(); return pPolyphase; } const PolyphaseFilter *FindNearestPolyphaseFilter( int iUpFactor, float fCutoffFrequency ) { /* Find a cached filter with the same iUpFactor and a nearby cutoff frequency. * Round the cutoff down, if possible; it's better to filter out too much than * too little. */ PolyphaseFiltersLock.Lock(); pair<int,float> params( make_pair(iUpFactor, fCutoffFrequency + 0.0001f) ); FilterMap::const_iterator it = g_mapPolyphaseFilters.upper_bound( params ); if( it != g_mapPolyphaseFilters.begin() ) --it; ASSERT( it->first.first == iUpFactor ); PolyphaseFilter *pPolyphase = it->second; PolyphaseFiltersLock.Unlock(); return pPolyphase; } }
void NetworkStream_Win32::Cancel() { m_Mutex.Lock(); // Mark cancellation. m_State = STATE_CANCELLED; // If resolving, abort the resolve. if( m_hResolve != NULL ) { /* When we cancel the request, no message at all will be sent to the window, * so we need to do it ourself to inform it that it was cancelled. Be sure * to only do this on successful cancel. */ if( WSACancelAsyncRequest(m_hResolve) == 0 ) PostMessage( m_hResolveHwnd, WM_USER+1, 0, 0 ); } // Break out if we're waiting in WaitForCompletionOrCancellation(). SetEvent( m_hCompletionEvent ); m_Mutex.Unlock(); }
void ThreadedFileWorker::Close( RageFileBasic *pFile ) { ASSERT( m_pChildDriver != NULL ); /* how did you get a file to begin with? */ if( pFile == NULL ) return; if( !IsTimedOut() ) { /* If we're not in a timed-out state, try to wait for the deletion to complete * before continuing. */ m_pRequestFile = pFile; if( !DoRequest(REQ_CLOSE) ) return; m_pRequestFile = NULL; } else { /* Delete the file when the timeout completes. */ m_DeletedFilesLock.Lock(); m_apDeletedFiles.push_back( pFile ); m_DeletedFilesLock.Unlock(); } }
void CachedObjectHelpers::Lock() { m_Mutex.Lock(); }
/* Register the given sound, and return a unique ID. */ void RageSoundManager::RegisterSound( RageSound *p ) { g_SoundManMutex.Lock(); /* lock for access to all_sounds */ all_sounds[p->GetID()] = p; g_SoundManMutex.Unlock(); /* finished with all_sounds */ }
void RageSoundManager::UnregisterSound( RageSound *p ) { g_SoundManMutex.Lock(); /* lock for access to all_sounds */ all_sounds.erase( p->GetID() ); g_SoundManMutex.Unlock(); /* finished with all_sounds */ }
void ScreenUserPacks::HandleScreenMessage( const ScreenMessage SM ) { #if 0 /* Not compatible with FileCopy callback system; was this ever used? -- vyhd */ if ( SM == SM_CancelTransfer ) { Dialog::OK("SM_CancelTransfer"); InterruptCopy(); InputEventArray throwaway; INPUTFILTER->GetInputEvents( throwaway ); LOG->Warn("Cancelled Transfer of user pack."); } #endif if ( SM == SM_LinkedMenuChange ) { m_pCurLOM = m_pCurLOM->SwitchToNextMenu(); return; } if ( SM == SM_ConfirmDeleteZip ) { SCREENMAN->Prompt( SM_AnswerConfirmDeleteZip, "Proceed to delete pack from machine?", PROMPT_YES_NO, ANSWER_NO ); } if ( SM == SM_AnswerConfirmDeleteZip ) { if (ScreenPrompt::s_LastAnswer == ANSWER_NO) return; CString sSelection = m_AddedZips.GetCurrentSelection(); g_CurSelection = sSelection; bool bSuccess = UPACKMAN->Remove( USER_PACK_SAVE_PATH + sSelection ); if (bSuccess) { m_SoundDelete.Play(); ReloadZips(); m_bRestart = true; } else { SCREENMAN->SystemMessage( "Failed to delete zip file from machine. Check your file permissions." ); } } if ( SM == SM_ConfirmAddZip ) { SCREENMAN->Prompt( SM_AnswerConfirmAddZip, "Proceed to add pack to machine?", PROMPT_YES_NO, ANSWER_NO ); } if ( SM == SM_AnswerConfirmAddZip ) { CString sError; m_bPrompt = false; if (ScreenPrompt::s_LastAnswer == ANSWER_NO) return; m_bStopThread = true; m_PlayerSongLoadThread.Wait(); MountMutex.Lock(); #if defined(LINUX) && defined(ITG_ARCADE) system( "mount -o remount,rw /itgdata" ); #endif MEMCARDMAN->LockCards(); MEMCARDMAN->MountCard(m_CurPlayer, 99999); CString sSelection = m_USBZips.GetCurrentSelection(); { //////////////////////// #define XFER_CLEANUP MEMCARDMAN->UnmountCard(m_CurPlayer); \ MEMCARDMAN->UnlockCards(); \ MountMutex.Unlock(); \ m_bStopThread = false; \ m_PlayerSongLoadThread.Create( InitSASSongThread, this ) //////////////////////// g_CurXferFile = MEM_CARD_MOUNT_POINT[m_CurPlayer] + "/" + USER_PACK_TRANSFER_PATH + sSelection; if ( !UPACKMAN->IsPackTransferable( sSelection, g_CurXferFile, sError ) || !UPACKMAN->IsPackMountable( g_CurXferFile, sError ) ) { SCREENMAN->SystemMessage( "Could not add pack to machine:\n" + sError ); XFER_CLEANUP; return; } sError = ""; // ?? RageTimer start; DrawTimer.Touch(); g_iLastCurrentBytes = 0; g_UpdateDuration.Touch(); if (!UPACKMAN->TransferPack( g_CurXferFile, sSelection, UpdateXferProgress, sError ) ) { SCREENMAN->SystemMessage( "Transfer error:\n" + sError ); XFER_CLEANUP; SCREENMAN->HideOverlayMessage(); SCREENMAN->ZeroNextUpdate(); return; } LOG->Debug( "Transferred %s in %f seconds.", g_CurXferFile.c_str(), start.Ago() ); } #if defined(LINUX) && defined(ITG_ARCADE) sync(); system( "mount -o remount,ro /itgdata" ); #endif SCREENMAN->HideOverlayMessage(); SCREENMAN->ZeroNextUpdate(); FILEMAN->FlushDirCache(USER_PACK_SAVE_PATH); m_bRestart = true; m_SoundTransferDone.Play(); ReloadZips(); XFER_CLEANUP; #undef XFER_CLEANUP } switch( SM ) { case SM_GoToNextScreen: case SM_GoToPrevScreen: SCREENMAN->SetNewScreen( PREV_SCREEN ); break; } }
void ThreadedFileWorker::HandleRequest( int iRequest ) { { m_DeletedFilesLock.Lock(); vector<RageFileBasic *> apDeletedFiles = m_apDeletedFiles; m_apDeletedFiles.clear(); m_DeletedFilesLock.Unlock(); for( unsigned i = 0; i < apDeletedFiles.size(); ++i ) delete apDeletedFiles[i]; } /* We have a request. */ switch( iRequest ) { case REQ_OPEN: ASSERT( m_pResultFile == NULL ); ASSERT( !m_sRequestPath.empty() ); m_iResultRequest = 0; m_pResultFile = m_pChildDriver->Open( m_sRequestPath, m_iRequestMode, m_iResultRequest ); break; case REQ_CLOSE: ASSERT( m_pRequestFile != NULL ); delete m_pRequestFile; /* Clear m_pRequestFile, so RequestTimedOut doesn't double-delete. */ m_pRequestFile = NULL; break; case REQ_GET_FILE_SIZE: ASSERT( m_pRequestFile != NULL ); m_iResultRequest = m_pRequestFile->GetFileSize(); break; case REQ_SEEK: ASSERT( m_pRequestFile != NULL ); m_iResultRequest = m_pRequestFile->Seek( m_iRequestPos ); m_sResultError = m_pRequestFile->GetError(); break; case REQ_READ: ASSERT( m_pRequestFile != NULL ); ASSERT( m_pResultBuffer != NULL ); m_iResultRequest = m_pRequestFile->Read( m_pResultBuffer, m_iRequestSize ); m_sResultError = m_pRequestFile->GetError(); break; case REQ_WRITE: ASSERT( m_pRequestFile != NULL ); ASSERT( m_pRequestBuffer != NULL ); m_iResultRequest = m_pRequestFile->Write( m_pRequestBuffer, m_iRequestSize ); m_sResultError = m_pRequestFile->GetError(); break; case REQ_FLUSH: ASSERT( m_pRequestFile != NULL ); m_iResultRequest = m_pRequestFile->Flush(); m_sResultError = m_pRequestFile->GetError(); break; case REQ_COPY: ASSERT( m_pRequestFile != NULL ); m_pResultFile = m_pRequestFile->Copy(); break; case REQ_POPULATE_FILE_SET: ASSERT( !m_sRequestPath.empty() ); m_ResultFileSet = FileSet(); m_pChildDriver->FDB->GetFileSetCopy( m_sRequestPath, m_ResultFileSet ); break; case REQ_FLUSH_DIR_CACHE: m_pChildDriver->FlushDirCache( m_sRequestPath ); break; case REQ_REMOVE: ASSERT( !m_sRequestPath.empty() ); m_iResultRequest = m_pChildDriver->Remove( m_sRequestPath )? 0:-1; break; case REQ_MOVE: ASSERT( !m_sRequestPath.empty() ); ASSERT( !m_sRequestPath2.empty() ); m_iResultRequest = m_pChildDriver->Move( m_sRequestPath, m_sRequestPath2 ) ? 0 : -1; break; default: FAIL_M( ssprintf("%i", iRequest) ); } }
void RageSoundManager::DeleteSoundWhenFinished( RageSound *pSound ) { g_SoundManMutex.Lock(); /* lock for access to owned_sounds */ owned_sounds.insert( pSound ); g_SoundManMutex.Unlock(); /* finished with owned_sounds */ }
void RageSoundManager::SetPrefs(float MixVol) { g_SoundManMutex.Lock(); /* lock for access to MixVolume */ MixVolume = MixVol; g_SoundManMutex.Unlock(); /* finished with MixVolume */ }
void CachedObjectHelpers::Unlock() { m_Mutex.Unlock(); }
void NetworkStream_Win32::Open( const RString &sHost, int iPort, ConnectionType ct ) { m_Mutex.Lock(); if( m_State == STATE_CANCELLED ) { m_Mutex.Unlock(); return; } // Always shut down a stream completely before reusing it. ASSERT_M( m_State == STATE_IDLE, ssprintf("%s:%i: %i", sHost.c_str(), iPort, m_State) ); m_sHost = sHost; m_iPort = iPort; // Look up the hostname. hostent *pHost = NULL; char pBuf[MAXGETHOSTSTRUCT]; { pHost = (hostent *) pBuf; ResolveMessageWindow mw; m_hResolve = WSAAsyncGetHostByName( mw.GetHwnd(), WM_USER, m_sHost, (char *) pHost, MAXGETHOSTSTRUCT ); m_hResolveHwnd = mw.GetHwnd(); m_Mutex.Unlock(); mw.Run(); m_Mutex.Lock(); m_hResolve = NULL; m_hResolveHwnd = NULL; if( m_State == STATE_CANCELLED ) { m_Mutex.Unlock(); return; } int iError = mw.GetResult(); if( iError ) { SetError( ssprintf("DNS error: %s", WinSockErrorToString(iError).c_str() ) ); m_Mutex.Unlock(); return; } m_Mutex.Unlock(); } { sockaddr_in addr; addr.sin_addr.s_addr = *(DWORD *)pHost->h_addr_list[0]; addr.sin_family = PF_INET; addr.sin_port = htons( (uint16_t) iPort ); m_Mutex.Lock(); m_Socket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if( m_Socket == INVALID_SOCKET ) { int iError = WSAGetLastError(); SetError( ssprintf("Error creating socket: %s", WinSockErrorToString(iError).c_str() ) ); return; } /* Set up the completion event to be signalled when these events occur. * This also sets the socket to nonblocking. */ WSAEventSelect( m_Socket, m_hCompletionEvent, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE ); //fcntl( m_Socket, O_NONBLOCK, 1 ); // Start opening the connection. int iResult = connect(m_Socket, (SOCKADDR *) &addr, sizeof(addr)); m_Mutex.Unlock(); // We expect EINPROGRESS/WSAEWOULDBLOCK. if( iResult == SOCKET_ERROR ) { // Block until the connection attempt completes. int iError = WSAGetLastError(); if( iError == WSAEWOULDBLOCK ) iError = WaitForCompletionOrCancellation( FD_CONNECT_BIT ); if( iError ) { SetError( ssprintf("Couldn't connect: %s", WinSockErrorToString(iError).c_str() ) ); return; } } } m_State = STATE_CONNECTED; }