From eb66934f8aeca169e02b4548b34a60886eb43e44 Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Wed, 17 May 2006 07:44:54 +0000 Subject: [PATCH] *** empty log message *** svn path=/trunk/boinc/; revision=10153 --- api/boinc_api.C | 5 ++ checkin_notes | 12 ++++ lib/boinc_win.h | 20 ++---- lib/diagnostics.C | 81 +++++++++++++++++++--- lib/diagnostics.h | 1 + lib/diagnostics_win.C | 154 ++++++++++++++++++++---------------------- 6 files changed, 167 insertions(+), 106 deletions(-) diff --git a/api/boinc_api.C b/api/boinc_api.C index 0fb2e55a15..cf6d880c00 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -437,6 +437,11 @@ void boinc_exit(int status) { // fflush(NULL); + // Cleanup the diagnostics allocations and stuff. Dump any memory + // leaks if it is a debug build. + // + boinc_finish_diag(); + // various platforms have various issues with shutting down // a process while an unspecified number of threads are still // executing or triggering endless exit()/atexit() loops. Use diff --git a/checkin_notes b/checkin_notes index cde00978e8..4c2a090528 100755 --- a/checkin_notes +++ b/checkin_notes @@ -4773,3 +4773,15 @@ David 16 May 2006 win_build/ boinc_ss.vcproj libboinc.vcproj + +Rom 16 May 2006 + - Manually perform memory leak detection since we now terminate the + process before the memory leak detection stuff kicks in. + - Cleanup used diagnostic resources when boinc_exit() is called. + + api/ + boinc_api.C + lib/ + boinc_win.h + diagnostics.C, .h + diagnostics_win.C diff --git a/lib/boinc_win.h b/lib/boinc_win.h index 49f51f650d..32e5126f06 100644 --- a/lib/boinc_win.h +++ b/lib/boinc_win.h @@ -104,36 +104,23 @@ #include #include +#include #if !defined(__CYGWIN32__) #include #endif -#include -#if !defined(__MINGW32__) && !defined(__CYGWIN32__) -#include -#endif #if !defined(__CYGWIN32__) #include #else - #ifndef _TCHAR_DEFINED typedef char TCHAR, *PTCHAR; typedef unsigned char TBYTE , *PTBYTE ; #define _TCHAR_DEFINED #endif /* !_TCHAR_DEFINED */ - typedef LPSTR LPTCH, PTCH; typedef LPSTR PTSTR, LPTSTR, PUTSTR, LPUTSTR; typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR; #define __TEXT(quote) quote - -#endif - -#if !defined(__MINGW32__) && !defined(__CYGWIN32__) -#include -#endif -#if !defined(__MINGW32__) && !defined(__CYGWIN32__) -#include #endif // All projects should be using std::min and std::max instead of the Windows @@ -150,6 +137,11 @@ typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR; #include #include +#if !defined(__MINGW32__) && !defined(__CYGWIN32__) +#include +#include +#endif + #ifdef __cplusplus #include #include diff --git a/lib/diagnostics.C b/lib/diagnostics.C index ecf94a77af..44ef3fb332 100644 --- a/lib/diagnostics.C +++ b/lib/diagnostics.C @@ -73,7 +73,10 @@ static int aborted_via_gui; #ifdef _WIN32 -int __cdecl boinc_message_reporting(int reportType, char *szMsg, int *retVal); +int __cdecl boinc_message_reporting(int reportType, char *szMsg, int *retVal); +_CrtMemState start_snapshot; +_CrtMemState finish_snapshot; +_CrtMemState difference_snapshot; #endif @@ -88,7 +91,7 @@ int boinc_init_diagnostics(int _flags) { // Used to cleanup the diagnostics environment. // int boinc_finish_diag() { - return BOINC_SUCCESS; + return diagnostics_finish(); } @@ -191,14 +194,6 @@ int diagnostics_init( #if defined(_WIN32) - // Initialize the thread list structure - // The data for this structure should be set by - // boinc_init or boinc_init_graphics. - diagnostics_init_thread_list(); - - diagnostics_init_unhandled_exception_monitor(); - diagnostics_init_message_monitor(); - #if defined(_DEBUG) _CrtSetReportHook(boinc_message_reporting); @@ -215,7 +210,23 @@ int diagnostics_init( } } + if (flags & BOINC_DIAG_BOINCAPPLICATION) { + if (flags & BOINC_DIAG_MEMORYLEAKCHECKENABLED) { + _CrtMemCheckpoint(&start_snapshot); + } + } + #endif // defined(_DEBUG) + + // Initialize the thread list structure + // The data for this structure should be set by + // boinc_init or boinc_init_graphics. + diagnostics_init_thread_list(); + + diagnostics_init_unhandled_exception_monitor(); + + diagnostics_init_message_monitor(); + #endif // defined(_WIN32) @@ -265,6 +276,56 @@ int diagnostics_init( } +// Cleanup the diagnostic framework before dumping any memory leaks. +// +int diagnostics_finish() { + +#if defined(_WIN32) + + // Shutdown the message monitor thread and handles + diagnostics_finish_message_monitor(); + + // Shutdown the unhandled exception filter thread and handles + diagnostics_finish_unhandled_exception_monitor(); + + // Cleanup internal thread list structures and free up any + // used memory. + diagnostics_finish_thread_list(); + +#ifdef _DEBUG + + // Only perform the memory leak dump if it is a boinc application + // and not the BOINC Manager, BOINC Core Client, or BOINC + // Screen saver since they'll check on close. + if (flags & BOINC_DIAG_BOINCAPPLICATION) { + if (flags & BOINC_DIAG_MEMORYLEAKCHECKENABLED) { + _CrtMemCheckpoint(&finish_snapshot); + if (_CrtMemDifference(&difference_snapshot, &start_snapshot, &finish_snapshot)) { + + fprintf( stderr, "\n\n"); + fprintf( stderr, "**********\n"); + fprintf( stderr, "**********\n"); + fprintf( stderr, "\n"); + fprintf( stderr, "Memory Leaks Detected!!!\n"); + fprintf( stderr, "\n"); + fprintf( stderr, "Memory Statistics:\n"); + _CrtMemDumpStatistics(&difference_snapshot); + fprintf( stderr, "\n"); + _CrtMemDumpAllObjectsSince(&difference_snapshot); + fprintf( stderr, "\n"); + } + } + } + +#endif // defined(_DEBUG) +#endif // defined(_WIN32) + + // Set initalization flag to false. + diagnostics_initialized = false; + + return BOINC_SUCCESS; +} + // has the diagnostics library been initialized? // int diagnostics_is_initialized(){ diff --git a/lib/diagnostics.h b/lib/diagnostics.h index 3c78ad99ad..4c5cfa7b3c 100644 --- a/lib/diagnostics.h +++ b/lib/diagnostics.h @@ -74,6 +74,7 @@ extern int boinc_finish_diag(); extern int diagnostics_init( int flags, const char* stdout_prefix, const char* stderr_prefix ); +extern int diagnostics_finish(); extern int diagnostics_is_initialized(); extern int diagnostics_is_flag_set( int flags ); diff --git a/lib/diagnostics_win.C b/lib/diagnostics_win.C index d17e61f4d9..49e155df16 100644 --- a/lib/diagnostics_win.C +++ b/lib/diagnostics_win.C @@ -106,7 +106,7 @@ BOOL diagnostics_get_registry_value(LPCTSTR lpName, LPDWORD lpdwType, LPDWORD lp // crash. This is platform specific in nature since it // depends on the OS datatypes. typedef struct _BOINC_THREADLISTENTRY { - std::string name; + char name[256]; DWORD thread_id; HANDLE thread_handle; BOOL graphics_thread; @@ -128,7 +128,7 @@ static HANDLE hThreadListSync; // Initialize the thread list entry. int diagnostics_init_thread_entry(PBOINC_THREADLISTENTRY entry) { - entry->name.clear(); + strncpy(entry->name, "", sizeof(entry->name)); entry->thread_id = 0; entry->thread_handle = 0; entry->crash_suspend_exempt = FALSE; @@ -147,22 +147,19 @@ int diagnostics_init_thread_entry(PBOINC_THREADLISTENTRY entry) { // Initialize the thread list, which means empty it if anything is // in it. int diagnostics_init_thread_list() { - unsigned int i; - PBOINC_THREADLISTENTRY pThreadEntry = NULL; - std::vector::iterator thread_iter; + size_t i; + size_t size; // Create a Mutex that can be used to syncronize data access // to the global thread list. hThreadListSync = CreateMutex(NULL, TRUE, NULL); - for (i=0; i::iterator thread_iter; + size_t i; + size_t size; // Wait for the ThreadListSync mutex before writing updates WaitForSingleObject(hThreadListSync, INFINITE); - for (i=0; iname = ""; pThreadEntry->thread_id = pThread->ClientId.UniqueThread; pThreadEntry->thread_handle = hThread; pThreadEntry->crash_kernel_time = (FLOAT)pThread->KernelTime.QuadPart; @@ -430,7 +414,6 @@ int diagnostics_update_thread_list_NT() { // Release resources if (hThreadListSync) ReleaseMutex(hThreadListSync); - if (hKernel32) CloseHandle(hKernel32); if (pBuffer) HeapFree(GetProcessHeap(), NULL, pBuffer); return 0; @@ -452,13 +435,13 @@ int diagnostics_update_thread_list_XP() { UINT uiSystemIndex = 0; UINT uiInternalIndex = 0; UINT uiInternalCount = 0; - HMODULE hKernel32; + HMODULE hKernel32Lib; tOT pOT = NULL; // Dynamically link to the proper function pointers. - hKernel32 = LoadLibrary("kernel32.dll"); - pOT = (tOT) GetProcAddress( hKernel32, "OpenThread" ); + hKernel32Lib = GetModuleHandle("kernel32.dll"); + pOT = (tOT) GetProcAddress( hKernel32Lib, "OpenThread" ); // Get a snapshot of the process and thread information. diagnostics_get_process_information(&pBuffer, &cbBuffer); @@ -496,7 +479,6 @@ int diagnostics_update_thread_list_XP() { pThreadEntry = new BOINC_THREADLISTENTRY; diagnostics_init_thread_entry(pThreadEntry); - pThreadEntry->name = ""; pThreadEntry->thread_id = pThread->ClientId.UniqueThread; pThreadEntry->thread_handle = hThread; pThreadEntry->crash_kernel_time = (FLOAT)pThread->KernelTime.QuadPart; @@ -520,7 +502,6 @@ int diagnostics_update_thread_list_XP() { // Release resources if (hThreadListSync) ReleaseMutex(hThreadListSync); - if (hKernel32) CloseHandle(hKernel32); if (pBuffer) HeapFree(GetProcessHeap(), NULL, pBuffer); return 0; @@ -579,6 +560,31 @@ int diagnostics_update_thread_list() { // Set the current threads name to make it easy to know what the // thread is supposed to be doing. +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero +} THREADNAME_INFO; + +void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info ); + } + __except(EXCEPTION_CONTINUE_EXECUTION) + { + } +} + int diagnostics_set_thread_name( char* name ) { HANDLE hThread; PBOINC_THREADLISTENTRY pThreadEntry = NULL; @@ -591,7 +597,7 @@ int diagnostics_set_thread_name( char* name ) { // If we already know about the thread, just set its name. Otherwise // create a new entry and then set the name to the new entry. if (pThreadEntry) { - pThreadEntry->name = name; + strncpy(pThreadEntry->name, name, sizeof(pThreadEntry->name)); } else { DuplicateHandle( GetCurrentProcess(), @@ -605,7 +611,7 @@ int diagnostics_set_thread_name( char* name ) { pThreadEntry = new BOINC_THREADLISTENTRY; diagnostics_init_thread_entry(pThreadEntry); - pThreadEntry->name = name; + strncpy(pThreadEntry->name, name, sizeof(pThreadEntry->name)); pThreadEntry->thread_id = GetCurrentThreadId(); pThreadEntry->thread_handle = hThread; diagnostics_threads.push_back(pThreadEntry); @@ -614,6 +620,9 @@ int diagnostics_set_thread_name( char* name ) { // Release the Mutex ReleaseMutex(hThreadListSync); + // Set the thread name in the debugger + SetThreadName(pThreadEntry->thread_id, pThreadEntry->name); + return 0; } @@ -787,8 +796,6 @@ int diagnostics_init_message_monitor() { DWORD dwType; DWORD dwSize; DWORD dwCaptureMessages; - PBOINC_MESSAGEMONITORENTRY pMessageEntry = NULL; - std::vector::iterator message_iter; HMODULE hKernel32Lib; tIDP pIDP = NULL; @@ -806,13 +813,10 @@ int diagnostics_init_message_monitor() { // Clear out any previous messages. for (i=0; i::iterator message_iter; // Begin the cleanup process by means of shutting down the // message monitoring thread. @@ -910,13 +910,10 @@ int diagnostics_finish_message_monitor() { // Clear out any previous messages. for (i=0; i::iterator message_iter; HANDLE hEvents[2]; // Set our friendly name @@ -1074,12 +1068,8 @@ DWORD WINAPI diagnostics_message_monitor(LPVOID lpParameter) { // Trim back the number of messages in memory if (diagnostics_monitor_messages.size() > 50) { - pMessageEntry = diagnostics_monitor_messages[0]; - - message_iter = diagnostics_monitor_messages.begin(); - diagnostics_monitor_messages.erase(message_iter); - - delete pMessageEntry; + delete diagnostics_monitor_messages[0]; + diagnostics_monitor_messages.erase(diagnostics_monitor_messages.begin()); } // Release the Mutex @@ -1301,7 +1291,7 @@ int diagnostics_dump_thread_information(PBOINC_THREADLISTENTRY pThreadEntry) { "User Time: %f, " "Wait Time: %f\n" "\n", - pThreadEntry->name.c_str(), + pThreadEntry->name, pThreadEntry->thread_id, strThreadStatus.c_str(), strThreadWaitReason.c_str(), @@ -1614,7 +1604,7 @@ DWORD WINAPI diagnostics_unhandled_exception_monitor(LPVOID lpParameter) { // Notify the calling thread that the message monitoring thread is // finished. - SetEvent(hMessageQuitFinishedEvent); + SetEvent(hExceptionQuitFinishedEvent); return 0; }