Browse Source

Merge pull request #255 from Hoikas/keyleaks

Key Leaks/Debug Logging
Branan Purvine-Riley 12 years ago
parent
commit
215ec07ed2
  1. 111
      Sources/Plasma/Apps/plClient/winmain.cpp
  2. 14
      Sources/Plasma/CoreLib/hsStream.cpp
  3. 2
      Sources/Plasma/NucleusLib/inc/plgDispatch.h
  4. 12
      Sources/Plasma/NucleusLib/pnDispatch/plDispatch.cpp
  5. 8
      Sources/Plasma/NucleusLib/pnDispatch/plDispatch.h
  6. 63
      Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp
  7. 1
      Sources/Plasma/PubUtilLib/plResMgr/plResManager.h
  8. 3
      Sources/Tools/MaxMain/plPluginResManager.cpp

111
Sources/Plasma/Apps/plClient/winmain.cpp

@ -305,11 +305,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
bool active = (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE); bool active = (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE);
bool minimized = (HIWORD(wParam) != 0); bool minimized = (HIWORD(wParam) != 0);
DebugMsgF("Got WM_ACTIVATE, active=%s, minimized=%s, clicked=%s",
active ? "true" : "false",
minimized ? "true" : "false",
(LOWORD(wParam) == WA_CLICKACTIVE) ? "true" : "false");
if (gClient && !minimized && !gClient->GetDone()) if (gClient && !minimized && !gClient->GetDone())
{ {
gClient->WindowActivate(active); gClient->WindowActivate(active);
@ -324,7 +319,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
// Let go of the mouse if the window is being moved. // Let go of the mouse if the window is being moved.
case WM_ENTERSIZEMOVE: case WM_ENTERSIZEMOVE:
DebugMsgF("Got WM_ENTERSIZEMOVE%s", gClient ? "" : ", no client, ignoring");
gDragging = true; gDragging = true;
if( gClient ) if( gClient )
gClient->WindowActivate(false); gClient->WindowActivate(false);
@ -332,7 +326,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
// Redo the mouse capture if the window gets moved // Redo the mouse capture if the window gets moved
case WM_EXITSIZEMOVE: case WM_EXITSIZEMOVE:
DebugMsgF("Got WM_EXITSIZEMOVE%s", gClient ? "" : ", no client, ignoring");
gDragging = false; gDragging = false;
if( gClient ) if( gClient )
gClient->WindowActivate(true); gClient->WindowActivate(true);
@ -342,12 +335,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
// and his cool program that bumps windows out from under the taskbar) // and his cool program that bumps windows out from under the taskbar)
case WM_MOVE: case WM_MOVE:
if (!gDragging && gClient && gClient->GetInputManager()) if (!gDragging && gClient && gClient->GetInputManager())
{
gClient->GetInputManager()->Activate(true); gClient->GetInputManager()->Activate(true);
DebugMsgF("Got WM_MOVE");
}
else
DebugMsgF("Got WM_MOVE, but ignoring");
break; break;
/// Resize the window /// Resize the window
@ -358,7 +346,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
// size, not when the window is minimized or restored) // size, not when the window is minimized or restored)
case WM_SIZING: case WM_SIZING:
{ {
DebugMsgF("Got WM_SIZING");
RECT r; RECT r;
::GetClientRect(hWnd, &r); ::GetClientRect(hWnd, &r);
gClient->GetPipeline()->Resize(r.right - r.left, r.bottom - r.top); gClient->GetPipeline()->Resize(r.right - r.left, r.bottom - r.top);
@ -369,14 +356,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
// Let go of the mouse if the window is being minimized // Let go of the mouse if the window is being minimized
if (wParam == SIZE_MINIMIZED) if (wParam == SIZE_MINIMIZED)
{ {
DebugMsgF("Got WM_SIZE, SIZE_MINIMIZED%s", gClient ? "" : ", but no client, ignoring");
if (gClient) if (gClient)
gClient->WindowActivate(false); gClient->WindowActivate(false);
} }
// Redo the mouse capture if the window gets restored // Redo the mouse capture if the window gets restored
else if (wParam == SIZE_RESTORED) else if (wParam == SIZE_RESTORED)
{ {
DebugMsgF("Got WM_SIZE, SIZE_RESTORED%s", gClient ? "" : ", but no client, ignoring");
if (gClient) if (gClient)
gClient->WindowActivate(true); gClient->WindowActivate(true);
} }
@ -653,32 +638,40 @@ BOOL WinInit(HINSTANCE hInst, int nCmdShow)
// //
// For error logging // For error logging
// //
static FILE* gDebugFile=NULL; static plStatusLog* s_DebugLog = nullptr;
void DebugMessageProc(const char* msg) static void _DebugMessageProc(const char* msg)
{ {
OutputDebugString(msg); #if defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
OutputDebugString("\n"); s_DebugLog->AddLine(msg, plStatusLog::kRed);
if (gDebugFile != NULL) #endif // defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
{
fprintf(gDebugFile, "%s\n", msg);
fflush(gDebugFile);
}
} }
void DebugMsgF(const char* format, ...) static void _StatusMessageProc(const char* msg)
{ {
#ifndef PLASMA_EXTERNAL_RELEASE #if defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
s_DebugLog->AddLine(msg);
#endif // defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
}
static void DebugMsgF(const char* format, ...)
{
#if defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
va_list args; va_list args;
va_start(args, format); va_start(args, format);
s_DebugLog->AddLineV(plStatusLog::kYellow, format, args);
char buf[256];
int numWritten = _vsnprintf(buf, sizeof(buf), format, args);
hsAssert(numWritten > 0, "Buffer too small");
va_end(args); va_end(args);
#endif // defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
}
DebugMessageProc(buf); static void DebugInit()
#endif {
#if defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
plStatusLogMgr& mgr = plStatusLogMgr::GetInstance();
s_DebugLog = mgr.CreateStatusLog(30, "plasmadbg.log", plStatusLog::kFilledBackground |
plStatusLog::kDeleteForMe | plStatusLog::kAlignToTop | plStatusLog::kTimestamp);
hsSetDebugMessageProc(_DebugMessageProc);
hsSetStatusMessageProc(_StatusMessageProc);
#endif // defined(HS_DEBUGGING) || !defined(PLASMA_EXTERNAL_RELEASE)
} }
static void AuthFailedStrings (ENetError authError, static void AuthFailedStrings (ENetError authError,
@ -1203,6 +1196,7 @@ LONG WINAPI plCustomUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *Except
#include "pfConsoleCore/pfConsoleEngine.h" #include "pfConsoleCore/pfConsoleEngine.h"
PF_CONSOLE_LINK_ALL() PF_CONSOLE_LINK_ALL()
#include "plResMgr/plVersion.h"
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{ {
PF_CONSOLE_INIT_ALL() PF_CONSOLE_INIT_ALL()
@ -1398,22 +1392,8 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
// //
// Set up to log errors by using hsDebugMessage // Set up to log errors by using hsDebugMessage
// //
gDebugFile = NULL; DebugInit();
if ( !plStatusLog::fLoggingOff ) DebugMsgF("Plasma 2.0.%i.%i - %s", PLASMA2_MAJOR_VERSION, PLASMA2_MINOR_VERSION, plProduct::ProductString().c_str());
{
wchar_t fileAndPath[MAX_PATH];
PathGetLogDirectory(fileAndPath, arrsize(fileAndPath));
PathAddFilename(fileAndPath, fileAndPath, L"plasmalog.txt", arrsize(fileAndPath));
gDebugFile = _wfopen(fileAndPath, L"wt");
hsAssert(gDebugFile != NULL, "Error creating debug file plasmalog.txt");
hsSetDebugMessageProc(DebugMessageProc);
if (gDebugFile != NULL)
{
fputs(plProduct::ProductString().c_str(), gDebugFile);
fputs("\n", gDebugFile);
fflush(gDebugFile);
}
}
for (;;) { for (;;) {
// Create Window // Create Window
@ -1485,32 +1465,17 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
break; break;
} }
#ifndef _DEBUG //
try // Cleanup
{ //
#endif if (gClient)
//
// Cleanup
//
if (gClient)
{
gClient->Shutdown(); // shuts down PhysX for us
gClient = nil;
}
hsAssert(hsgResMgr::ResMgr()->RefCnt()==1, "resMgr has too many refs, expect mem leaks");
hsgResMgr::Shutdown(); // deletes fResMgr
DeInitNetClientComm();
#ifndef _DEBUG
} catch (...)
{ {
// just catch all the crashes on exit... just to keep GameTap from complaining gClient->Shutdown(); // shuts down PhysX for us
if (gDebugFile) gClient = nil;
fprintf(gDebugFile, "Crashed on shutdown.\n");
} }
#endif hsAssert(hsgResMgr::ResMgr()->RefCnt()==1, "resMgr has too many refs, expect mem leaks");
hsgResMgr::Shutdown(); // deletes fResMgr
if (gDebugFile) DeInitNetClientComm();
fclose(gDebugFile);
// Uninstall our unhandled exception filter, if we installed one // Uninstall our unhandled exception filter, if we installed one
#ifndef HS_DEBUGGING #ifndef HS_DEBUGGING

14
Sources/Plasma/CoreLib/hsStream.cpp

@ -714,17 +714,13 @@ uint32_t hsUNIXStream::Read(uint32_t bytes, void* buffer)
{ {
if (!fRef || !bytes) if (!fRef || !bytes)
return 0; return 0;
int numItems = ::fread(buffer, 1 /*size*/, bytes /*count*/, fRef); size_t numItems = ::fread(buffer, 1 /*size*/, bytes /*count*/, fRef);
fBytesRead += numItems; fBytesRead += numItems;
fPosition += numItems; fPosition += numItems;
if ((unsigned)numItems < bytes) { if (numItems < bytes)
if (feof(fRef)) { {
// EOF ocurred if (!feof(fRef))
char str[128]; {
sprintf(str, "Hit EOF on UNIX Read, only read %d out of requested %d bytes\n", numItems, bytes);
hsDebugMessage(str, 0);
}
else {
hsDebugMessage("Error on UNIX Read", ferror(fRef)); hsDebugMessage("Error on UNIX Read", ferror(fRef));
} }
} }

2
Sources/Plasma/NucleusLib/inc/plgDispatch.h

@ -68,6 +68,8 @@ public:
virtual void MsgQueueOnOff(bool) = 0; // Turn on or off Queued Messages, if off, uses MsgSend Immediately (for plugins) virtual void MsgQueueOnOff(bool) = 0; // Turn on or off Queued Messages, if off, uses MsgSend Immediately (for plugins)
virtual bool SetMsgBuffering(bool on) = 0; // On starts deferring msg delivery until buffering is set to off again. virtual bool SetMsgBuffering(bool on) = 0; // On starts deferring msg delivery until buffering is set to off again.
virtual void BeginShutdown() = 0;
}; };
class plgDispatch class plgDispatch

12
Sources/Plasma/NucleusLib/pnDispatch/plDispatch.cpp

@ -103,12 +103,16 @@ plDispatch::plDispatch()
plDispatch::~plDispatch() plDispatch::~plDispatch()
{ {
int i; hsAssert(fRegisteredExactTypes.GetCount() == 0, "registered type after Dispatch shutdown");
for( i = 0; i < fRegisteredExactTypes.GetCount(); i++ )
delete fRegisteredExactTypes[i];
ITrashUndelivered(); ITrashUndelivered();
}
void plDispatch::BeginShutdown()
{
for (int i = 0; i < fRegisteredExactTypes.Count(); ++i)
delete fRegisteredExactTypes[i];
fRegisteredExactTypes.Reset();
ITrashUndelivered();
} }
void plDispatch::ITrashUndelivered() void plDispatch::ITrashUndelivered()

8
Sources/Plasma/NucleusLib/pnDispatch/plDispatch.h

@ -131,6 +131,8 @@ public:
virtual bool SetMsgBuffering(bool on); // On starts deferring msg delivery until buffering is set to off again. virtual bool SetMsgBuffering(bool on); // On starts deferring msg delivery until buffering is set to off again.
virtual void BeginShutdown();
static void SetMsgRecieveCallback(MsgRecieveCallback callback) { fMsgRecieveCallback = callback; } static void SetMsgRecieveCallback(MsgRecieveCallback callback) { fMsgRecieveCallback = callback; }
}; };
@ -146,8 +148,10 @@ public:
virtual bool MsgSend(plMessage* msg) { return true; } virtual bool MsgSend(plMessage* msg) { return true; }
virtual void MsgQueue(plMessage* msg) {} virtual void MsgQueue(plMessage* msg) {}
virtual void MsgQueueProcess() {} virtual void MsgQueueProcess() {}
virtual void BeginShutdown() {}
}; };

63
Sources/Plasma/PubUtilLib/plResMgr/plResManager.cpp

@ -96,7 +96,6 @@ static void ILog(uint8_t level, const char* format, ...)
plResManager::plResManager(): plResManager::plResManager():
fInited(false), fInited(false),
fPageOutHint(0),
fDispatch(nil), fDispatch(nil),
fReadingObject( false ), fReadingObject( false ),
fCurCloneID(0), fCurCloneID(0),
@ -205,10 +204,11 @@ void plResManager::IShutdown()
// TimerCallbackMgr is a fixed-keyed object, so needs to shut down before the registry // TimerCallbackMgr is a fixed-keyed object, so needs to shut down before the registry
plgTimerCallbackMgr::Shutdown(); plgTimerCallbackMgr::Shutdown();
// Destroy the dispatch. Note that we do this before the registry so that any lingering messages // Formerly, we destroyed the Dispatcher here to clean up keys for leak reporting.
// can free up keys properly // However, if there are *real* leaked keys, then they will want to unload after this step.
hsRefCnt_SafeUnRef(fDispatch); // To unload, plKeyImp needs to dispatcher. SO, we're going to pitch everything currently in the
fDispatch = nil; // Dispatcher and kill it later
fDispatch->BeginShutdown();
// Just before we shut down the registry, page out any keys that still exist. // Just before we shut down the registry, page out any keys that still exist.
// (They shouldn't... they're baaaaaad.) // (They shouldn't... they're baaaaaad.)
@ -224,9 +224,12 @@ void plResManager::IShutdown()
fLoadedPages.clear(); fLoadedPages.clear();
IUnlockPages(); IUnlockPages();
fLastFoundPage = nil; fLastFoundPage = nil;
// Now, kill off the Dispatcher
hsRefCnt_SafeUnRef(fDispatch);
fDispatch = nullptr;
kResMgrLog(1, ILog(1, " ...Shutdown successful!")); kResMgrLog(1, ILog(1, " ...Shutdown successful!"));
fInited = false; fInited = false;
@ -488,47 +491,21 @@ public:
} }
}; };
#if HS_BUILD_FOR_UNIX
static void sLeakReportRedirectFn( const char message[] )
{
hsUNIXStream stream;
stream.Open( "resMgrMemLeaks.txt", "at" );
stream.WriteString( message );
stream.Close();
}
static bool sFirstTime = true;
#endif
// Just the scene nodes (and objects referenced by the node... and so on) // Just the scene nodes (and objects referenced by the node... and so on)
void plResManager::IPageOutSceneNodes(bool forceAll) void plResManager::IPageOutSceneNodes(bool forceAll)
{ {
plSynchEnabler ps(false); // disable dirty tracking while paging out plSynchEnabler ps(false); // disable dirty tracking while paging out
#if HS_BUILD_FOR_UNIX
if (sFirstTime)
{
hsUNIXStream stream;
stream.Open("resMgrMemLeaks.txt", "wt");
stream.Close();
sFirstTime = false;
}
hsDebugMessageProc oldProc = hsSetStatusMessageProc(sLeakReportRedirectFn);
#endif
if (forceAll) if (forceAll)
{ {
hsStatusMessage( "--- plResManager Object Leak Report (BEGIN) ---" ); hsStatusMessage( "--- plResManager Object Leak Report (BEGIN) ---" );
plPageOutIterator iter(this, uint16_t(-1)); plPageOutIterator iter(this, static_cast<uint16_t>(-1));
hsStatusMessage( "--- plResManager Object Leak Report (END) ---" ); hsStatusMessage( "--- plResManager Object Leak Report (END) ---" );
} }
else else
{ {
plPageOutIterator iter(this, fPageOutHint); plPageOutIterator iter(this, 0);
} }
#if HS_BUILD_FOR_UNIX
hsSetStatusMessageProc( oldProc );
#endif
} }
//// FindKey ///////////////////////////////////////////////////////////////// //// FindKey /////////////////////////////////////////////////////////////////
@ -1578,7 +1555,7 @@ static void sIReportLeak(plKeyImp* key, plRegistryPageNode* page)
if (!alreadyDone) if (!alreadyDone)
{ {
// Print out page header // Print out page header
hsStatusMessageF(" Leaks in page %s>%s[%08x]:\n", lastPage->GetPageInfo().GetAge().c_str(), lastPage->GetPageInfo().GetPage().c_str(), lastPage->GetPageInfo().GetLocation().GetSequenceNumber()); hsStatusMessageF("\tLeaks in page %s>%s[%08x]:\n", lastPage->GetPageInfo().GetAge().c_str(), lastPage->GetPageInfo().GetPage().c_str(), lastPage->GetPageInfo().GetLocation().GetSequenceNumber());
alreadyDone = true; alreadyDone = true;
} }
@ -1586,14 +1563,14 @@ static void sIReportLeak(plKeyImp* key, plRegistryPageNode* page)
if (refsLeft == 0) if (refsLeft == 0)
return; return;
char tempStr2[128]; plStringStream ss;
if (key->ObjectIsLoaded() == nil) ss << "\t\t" << plFactory::GetNameOfClass(key->GetUoid().GetClassType()) << ": ";
sprintf(tempStr2, "(key only, %d refs left)", refsLeft); ss << key->GetUoid().StringIze() << " ";
if (key->ObjectIsLoaded())
ss << "- " << key->GetDataLen() << " bytes - " << refsLeft << " refs left";
else else
sprintf(tempStr2, "- %d bytes - %d refs left", key->GetDataLen(), refsLeft); ss << "(key only, " << refsLeft << " refs left)";
hsStatusMessage(ss.GetString().c_str());
hsStatusMessageF(" %s: %s %s\n", plFactory::GetNameOfClass(key->GetUoid().GetClassType()),
key->GetUoid().StringIze().c_str(), tempStr2);
} }
//// UnloadPageObjects /////////////////////////////////////////////////////// //// UnloadPageObjects ///////////////////////////////////////////////////////
@ -1624,7 +1601,7 @@ void plResManager::UnloadPageObjects(plRegistryPageNode* pageNode, uint16_t clas
plUnloadObjectsIterator iterator; plUnloadObjectsIterator iterator;
if (classIndexHint != uint16_t(-1)) if (classIndexHint != static_cast<uint16_t>(-1))
pageNode->IterateKeys(&iterator, classIndexHint); pageNode->IterateKeys(&iterator, classIndexHint);
else else
pageNode->IterateKeys(&iterator); pageNode->IterateKeys(&iterator);

1
Sources/Plasma/PubUtilLib/plResMgr/plResManager.h

@ -209,7 +209,6 @@ protected:
plRegistryPageNode* CreatePage(const plLocation& location, const char* age, const char* page); plRegistryPageNode* CreatePage(const plLocation& location, const char* age, const char* page);
bool fInited; bool fInited;
uint16_t fPageOutHint;
// True if we're reading in an object. We only read one object at a time // True if we're reading in an object. We only read one object at a time
bool fReadingObject; bool fReadingObject;

3
Sources/Tools/MaxMain/plPluginResManager.cpp

@ -60,9 +60,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
plKey plPluginResManager::NameToLoc(const plString& age, const plString& page, int32_t sequenceNumber, bool itinerant) plKey plPluginResManager::NameToLoc(const plString& age, const plString& page, int32_t sequenceNumber, bool itinerant)
{ {
// Hack for now--always prefer paging out sceneNodes first
fPageOutHint = plSceneNode::Index();
// Get or create our page // Get or create our page
plRegistryPageNode* pageNode = INameToPage(age, page, sequenceNumber, itinerant); plRegistryPageNode* pageNode = INameToPage(age, page, sequenceNumber, itinerant);
hsAssert(pageNode != nil, "No page returned from INameToPage(), shouldn't be possible"); hsAssert(pageNode != nil, "No page returned from INameToPage(), shouldn't be possible");

Loading…
Cancel
Save