bool CBOINCClientManager::AutoRestart() { double timeNow, timeDiff; if (IsBOINCCoreRunning()) return true; #if ! (defined(__WXMAC__) || defined(__WXMSW__)) // Mac and Windows can restart Client as a daemon, but // Linux may not know Client's location if it didn't start the Client if (!m_bBOINCStartedByManager) return false; #endif // Alert user if Client crashes 3 times in CLIENT_3_CRASH_MAX_TIME timeNow = dtime(); timeDiff = timeNow - m_fAutoRestart1Time; if ((timeDiff) < (CLIENT_3_CRASH_MAX_TIME * 60)) { int response; ClientCrashDlg *dlg = new ClientCrashDlg(timeDiff); if (dlg) { CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); if (!pFrame->IsShown()) { pFrame->Show(); } response = dlg->ShowModal(); dlg->Destroy(); if (response == wxID_CANCEL) return false; timeNow = 0; m_fAutoRestart1Time = 0; m_fAutoRestart2Time = 0; } } m_lBOINCCoreProcessId = 0; m_fAutoRestart1Time = m_fAutoRestart2Time; m_fAutoRestart2Time = timeNow; StartupBOINCCore(); return true; }
int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { std::vector<ASYNC_RPC_REQUEST>::iterator iter; int retval = 0; int response = wxID_OK; wxMutexError mutexErr = wxMUTEX_NO_ERROR; long delayTimeRemaining, timeToSleep; bool shown = false; if (!m_RPCThread) return -1; if ( (request.rpcType < RPC_TYPE_WAIT_FOR_COMPLETION) || (request.rpcType >= NUM_RPC_TYPES) ) { wxASSERT(false); return -1; } // If we are quitting, cancel any pending RPCs if (request.which_rpc == RPC_QUIT) { if (current_rpc_request.isActive) { RPC_requests.erase(RPC_requests.begin()+1, RPC_requests.end()); } else { RPC_requests.clear(); } } // Check if a duplicate request is already on the queue for (iter=RPC_requests.begin(); iter!=RPC_requests.end(); iter++) { if (iter->isSameAs(request)) { return 0; } } if ((request.rpcType == RPC_TYPE_WAIT_FOR_COMPLETION) && (request.resultPtr == NULL)) { request.resultPtr = &retval; } if (hasPriority) { // We may want to set hasPriority for some user-initiated events. // Since the user is waiting, insert this at head of request queue. // As of 8/14/08, hasPriority is never set true, so hasn't been tested. iter = RPC_requests.insert(RPC_requests.begin(), request); } else { RPC_requests.push_back(request); } // Start this RPC if no other RPC is already in progress. if (RPC_requests.size() == 1) { // Wait for thread to unlock mutex with m_pRPC_Thread_Condition->Wait() mutexErr = m_pRPC_Thread_Mutex->Lock(); // Blocks until thread unlocks the mutex wxASSERT(mutexErr == wxMUTEX_NO_ERROR); // Make sure activation is an atomic operation request.isActive = false; current_rpc_request = request; current_rpc_request.isActive = true; m_pRPC_Thread_Condition->Signal(); // Unblock the thread // m_pRPC_Thread_Condition->Wait() will Lock() the mutex upon receiving Signal(), // causing it to block again if we still have our lock on the mutex. mutexErr = m_pRPC_Thread_Mutex->Unlock(); wxASSERT(mutexErr == wxMUTEX_NO_ERROR); } // If this is a user-initiated event wait for completion but show // a dialog allowing the user to cancel. if (request.rpcType == RPC_TYPE_WAIT_FOR_COMPLETION) { // TODO: proper handling if a second user request is received while first is pending ?? if (m_bWaitingForRPC) { wxLogMessage(wxT("Second user RPC request while another was pending")); wxASSERT(false); return -1; } // Don't show dialog if RPC completes before RPC_WAIT_DLG_DELAY // or while BOINC is minimized CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); wxStopWatch Dlgdelay = wxStopWatch(); m_RPCWaitDlg = new AsyncRPCDlg(); m_bWaitingForRPC = true; // Allow RPC_WAIT_DLG_DELAY seconds for Demand RPC to complete before // displaying "Please Wait" dialog, but keep checking for completion. delayTimeRemaining = RPC_WAIT_DLG_DELAY; while (true) { if (delayTimeRemaining >= 0) { // Prevent overflow if minimized for a very long time delayTimeRemaining = RPC_WAIT_DLG_DELAY - Dlgdelay.Time(); } if (pFrame) { shown = pFrame->IsShown(); } else { shown = false; } if (shown) { if (delayTimeRemaining <= 0) break; // Display the Please Wait dialog timeToSleep = delayTimeRemaining; } else { // Don't show dialog while Manager is minimized, but do // process events so user can maximize the manager. // // NOTE: CBOINCGUIApp::FilterEvent() discards those events // which might cause posting of more RPC requests while // we are in this loop, to prevent undesirable recursion. // Since the manager is minimized, we don't have to worry about // discarding crucial drawing or command events. // The filter does allow the the Open Manager menu item from // the system tray icon and wxEVT_RPC_FINISHED event. // timeToSleep = DELAY_WHEN_MINIMIZED; // Allow user to maximize Manager wxSafeYield(NULL, true); } // OnRPCComplete() clears m_bWaitingForRPC if RPC completed if (! m_bWaitingForRPC) { return retval; } mutexErr = m_pRPC_Request_Mutex->Lock(); wxASSERT(mutexErr == wxMUTEX_NO_ERROR); // Simulate handling of CRPCFinishedEvent but don't allow any other // events (so no user activity) to prevent undesirable recursion. // Since we don't need to filter and discard events, they remain on // the queue until it is safe to process them. // Allow RPC thread to run while we wait for it. if (!current_rpc_request.isActive) { mutexErr = m_pRPC_Request_Mutex->Unlock(); wxASSERT(mutexErr == wxMUTEX_NO_ERROR); HandleCompletedRPC(); continue; } // Wait for RPC thread to wake us // This does the following: // (1) Unlocks the Mutex and puts the main thread to sleep as an atomic operation. // (2) On Signal from RPC thread: locks Mutex again and wakes the main thread. m_pRPC_Request_Condition->WaitTimeout(timeToSleep); mutexErr = m_pRPC_Request_Mutex->Unlock(); wxASSERT(mutexErr == wxMUTEX_NO_ERROR); } // Demand RPC has taken longer than RPC_WAIT_DLG_DELAY seconds and // Manager is not minimized, so display the "Please Wait" dialog // with a Cancel button. If the RPC does complete while the dialog // is up, HandleCompletedRPC() will call EndModal with wxID_OK. // // NOTE: the Modal dialog permits processing of all events, but // CBOINCGUIApp::FilterEvent() blocks those events which might cause // posting of more RPC requests while in this dialog, to prevent // undesirable recursion. // if (m_RPCWaitDlg) { response = m_RPCWaitDlg->ShowModal(); // Remember time the dialog was closed for use by RunPeriodicRPCs() m_dtLasAsyncRPCDlgTime = wxDateTime::Now(); if (response != wxID_OK) { // TODO: If user presses Cancel in Please Wait dialog but request // has not yet been started, should we just remove it from queue? // If we make that change, should we also add a separate menu item // to reset the RPC connection (or does one already exist)? retval = -1; // If the RPC continues to get data after we return to // our caller, it may try to write into a buffer or struct // which the caller has already deleted. To prevent this, // we close the socket (disconnect) and kill the RPC thread. // This is ugly but necessary. We must then reconnect and // start a new RPC thread. if (current_rpc_request.isActive) { current_rpc_request.isActive = false; rpcClient.close(); RPC_requests.clear(); current_rpc_request.clear(); m_bNeedRefresh = false; m_bNeedTaskBarRefresh = false; // We will be reconnected to the same client (if possible) by // CBOINCDialUpManager::OnPoll() and CNetworkConnection::Poll(). m_pNetworkConnection->SetStateDisconnected(); } if (response == wxID_EXIT) { pFrame = wxGetApp().GetFrame(); wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, wxID_EXIT); s_bSkipExitConfirmation = true; pFrame->AddPendingEvent(evt); } } if (m_RPCWaitDlg) { m_RPCWaitDlg->Destroy(); } m_RPCWaitDlg = NULL; m_bWaitingForRPC = false; } } return retval; }
void CBOINCDialUpManager::OnPoll() { CMainDocument* pDoc = wxGetApp().GetDocument(); CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); static bool bAlreadyRunningLoop = false; bool bIsOnline = false; bool bWantConnection = false; bool bWantDisconnect = false; wxString strDialogMessage = wxEmptyString; CC_STATUS cc_status; // We are ready to rock and roll. if (!bAlreadyRunningLoop && pDoc) { wxASSERT(wxDynamicCast(pDoc, CMainDocument)); wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame)); bAlreadyRunningLoop = true; // cache the various states // The dialup manager tells us if we are still dialing or if we have // successfully connected. IsNetworkAlive/IsOnline both report the // success or failure of the dialup device to establish a connection // to the outside world. pDoc->GetCoreClientStatus(cc_status); bIsOnline = (cc_status.network_status == NETWORK_STATUS_ONLINE); bWantConnection = (cc_status.network_status == NETWORK_STATUS_WANT_CONNECTION); bWantDisconnect = (cc_status.network_status == NETWORK_STATUS_WANT_DISCONNECT); // The timers are used to keep from spamming the user with the same // messages over each iteration of the poll loop. we only need to // reset them during a connect event in case we randomly loose // a connection. if (m_bResetTimers) { wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - Resetting dial-up notification timers")); m_bResetTimers = false; m_bSetConnectionTimer = false; ResetReminderTimers(); } // Log out the trace information for debugging purposes. /* wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - Dialup Flags")); wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - -- bIsOnline = '%d', bIsDialing = '%d', m_bWasDialing = '%d', iNetworkStatus = '%d', bWantConnection = '%d'"), bIsOnline, bIsDialing, m_bWasDialing, iNetworkStatus, bWantConnection ); wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - -- m_bResetTimers = '%d', m_bNotifyConnectionAvailable = '%d', m_bConnectedSuccessfully = '%d'"), m_bResetTimers, m_bNotifyConnectionAvailable, m_bConnectedSuccessfully ); wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - -- confirm_before_connecting = '%d', hangup_if_dialed = '%d'"), pDoc->state.global_prefs.confirm_before_connecting, pDoc->state.global_prefs.hangup_if_dialed ); */ #ifndef __WXMSW__ // notification logic for non MS-Windows systems if (!bIsOnline && bWantConnection) { // Make sure window is visable and active, don't want the message box // to pop up on top of anything else wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - Notify need Internet Connection")); if (pFrame->IsShown() && wxGetApp().IsActive()) { NotifyUserNeedConnection(false); } /* // this section commented out until taskbar/systray notification alerts are implemented else { // window is not visible, show alert if (pTaskbar && pTaskbar->IsBalloonsSupported()) { NotifyUserNeedConnection(true); } } */ } #else // dialer stuff for MS-Windows systems bool bIsDialing = m_pDialupManager->IsDialing(); if (!bIsOnline && !bIsDialing && !m_bWasDialing && bWantConnection) { wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - !bIsOnline && !bIsDialing && !m_bWasDialing && bWantConnection")); if (!pFrame->IsShown()) { // BOINC Manager is hidden and displaying a dialog might interupt what they // are doing. NotifyUserNeedConnection(true); } else { // BOINC Manager is visable and can process user input. m_bSetConnectionTimer = true; Connect(); } } else if (!bIsDialing && !m_bWasDialing) { // We are not doing anything now, were we up to something before? if (bIsOnline && m_bConnectedSuccessfully && m_bNotifyConnectionAvailable) { // Ah ha, we are online and we initiated the connection, so we need to // notify the CC that the network is available. wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bIsOnline && m_bConnectedSuccessfully && m_bNotifyConnectionAvailable")); NetworkAvailable(); } else if (bWantDisconnect && m_bConnectedSuccessfully) { // We are online, and the CC says it is safe to disconnect. Since we // initiated the connection we need to disconnect now. wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bWantDisconnect && m_bConnectedSuccessfully")); Disconnect(); } } else if (!bIsDialing && m_bWasDialing) { // We initiated a connection attempt and now we are either online or failed to // connect because of a modem error or a users credentials were wrong. wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - !bIsDialing && m_bWasDialing")); if (m_bSetConnectionTimer) { m_bSetConnectionTimer = false; m_dtDialupConnectionTimeout = wxDateTime::Now(); m_iConnectAttemptRetVal = ERR_NO_NETWORK_CONNECTION; } wxTimeSpan tsTimeout = wxDateTime::Now() - m_dtDialupConnectionTimeout; if (30 > tsTimeout.GetSeconds()) { if(m_iConnectAttemptRetVal != BOINC_SUCCESS) { return; } } m_bWasDialing = false; m_bResetTimers = true; if (!m_iConnectAttemptRetVal) { ConnectionSucceeded(); } else { ConnectionFailed(); } } else if (bIsDialing && !m_bWasDialing) { // Setup the state machine so that it knows when we have finished the connection // attempt. wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bIsDialing && !m_bWasDialing")); m_bWasDialing = true; } #endif bAlreadyRunningLoop = false; } }