From 9bde2e1b448ed2763a9ae7f0e50869a3e5d34dd4 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Thu, 31 Jul 2008 01:35:17 +0000 Subject: [PATCH] MGR: async GUI RPCs: Suspend RPC thread when not in use. svn path=/workspaces/charlief/; revision=15720 --- checkin_notes | 2 ++ clientgui/AsyncRPC.cpp | 42 ++++++++------------------------------ clientgui/AsyncRPC.h | 1 - clientgui/MainDocument.cpp | 7 +++++++ clientgui/MainDocument.h | 2 -- 5 files changed, 17 insertions(+), 37 deletions(-) diff --git a/checkin_notes b/checkin_notes index f32443443f..ccf1abb0ae 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6188,7 +6188,9 @@ David 30 July 2008 Charlie 30 July 2008 - MGR: async GUI RPCs: under SimpleGUI, call acct_mgr_info RPC every 10 minutes. + - MGR: async GUI RPCs: Suspend RPC thread when not in use. clientgui/ + AsyncRPC.cpp MainDocument.cpp,.h sg_ProjectsComponent.cpp diff --git a/clientgui/AsyncRPC.cpp b/clientgui/AsyncRPC.cpp index 3ede5d2d56..843d0afff7 100644 --- a/clientgui/AsyncRPC.cpp +++ b/clientgui/AsyncRPC.cpp @@ -135,7 +135,7 @@ void *RPCThread::Entry() { if (! m_Doc->GetCurrentRPCRequest()->isActive) { // Wait until CMainDocument issues next RPC request - Yield(); + Pause(); continue; } @@ -145,11 +145,14 @@ void *RPCThread::Entry() { } retval = ProcessRPCRequest(); - -// RPC_done_event.SetInt(retval); wxPostEvent( wxTheApp, RPC_done_event ); } + // Use a critical section to prevent a crash during + // manager shutdown due to a rare race condition + m_Doc->m_critsect.Enter(); + m_Doc->m_critsect.Leave(); + return NULL; } @@ -379,18 +382,9 @@ int RPCThread::ProcessRPCRequest() { break; } -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS - m_Doc->m_critsect.Enter(); - current_request->retval = retval; - current_request->isActive = false; - - m_Doc->m_critsect.Leave(); -#else // Deactivation is an atomic operation current_request->retval = retval; current_request->isActive = false; - -#endif return retval; } @@ -434,17 +428,11 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { // Start this RPC if no other RPC is already in progress. if (RPC_requests.size() == 1) { -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS - m_critsect.Enter(); - current_rpc_request = request; - current_rpc_request.isActive = true; - m_critsect.Leave(); -#else // Make sure activation is an atomic operation request.isActive = false; current_rpc_request = request; current_rpc_request.isActive = true; -#endif + m_RPCThread->Resume(); } // If no completion event specified, this is a user-initiated event so @@ -506,19 +494,11 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { // start a new RPC thread. if (current_rpc_request.isActive) { current_rpc_request.isActive = false; -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS - // Killing a thread while it is in a critical section - // usually causes an unrecoverable deadlock situation - m_critsect.Enter(); -#endif m_RPCThread->Pause(); // Needed on Windows rpcClient.close(); m_RPCThread->Kill(); #ifdef __WXMSW__ m_RPCThread->Delete(); // Needed on Windows, crashes on Mac/Linux -#endif -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS - m_critsect.Leave(); #endif m_RPCThread = NULL; RPC_requests.clear(); @@ -719,17 +699,11 @@ void CMainDocument::OnRPCComplete(CRPCFinishedEvent& event) { // Start the next RPC request. if (RPC_requests.size() > 0) { -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS - m_critsect.Enter(); - current_rpc_request = RPC_requests[0]; - current_rpc_request.isActive = true; - m_critsect.Leave(); -#else // Make sure activation is an atomic operation RPC_requests[0].isActive = false; current_rpc_request = RPC_requests[0]; current_rpc_request.isActive = true; -#endif + m_RPCThread->Resume(); } if (! stillWaitingForPendingRequests) { diff --git a/clientgui/AsyncRPC.h b/clientgui/AsyncRPC.h index f08bafab3c..ba3ae156c7 100644 --- a/clientgui/AsyncRPC.h +++ b/clientgui/AsyncRPC.h @@ -32,7 +32,6 @@ //#include "gui_rpc_client.h" #define USE_RPC_DLG_TIMER 0 -#define USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS 0 class CBOINCGUIApp; // Forward declaration class CMainDocument; // Forward declaration diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp index 7825cfbfa8..90dde9d848 100644 --- a/clientgui/MainDocument.cpp +++ b/clientgui/MainDocument.cpp @@ -426,7 +426,14 @@ int CMainDocument::OnExit() { } if (m_RPCThread) { + // Use a critical section to prevent a crash during + // manager shutdown due to a rare race condition + m_critsect.Enter(); m_RPCThread->Delete(); + // On some platforms, Delete() takes effect only when thread calls TestDestroy() + m_RPCThread->Resume(); + m_critsect.Leave(); + wxStopWatch ThreadDeleteTimer = wxStopWatch(); // RPC thread sets m_RPCThread to NULL when it exits while (m_RPCThread) { diff --git a/clientgui/MainDocument.h b/clientgui/MainDocument.h index a9783ea4eb..0e312762fd 100644 --- a/clientgui/MainDocument.h +++ b/clientgui/MainDocument.h @@ -181,9 +181,7 @@ public: ASYNC_RPC_REQUEST* GetCurrentRPCRequest() { return ¤t_rpc_request; }; void TestAsyncRPC(); // TEMPORARY -- CAF RPCThread* m_RPCThread; -#if USE_CRITICAL_SECTIONS_FOR_ASYNC_RPCS wxCriticalSection m_critsect; -#endif private: ASYNC_RPC_REQUEST current_rpc_request;