summaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2015-12-15 16:42:20 -0800
committerMike McLaughlin <mikem@microsoft.com>2016-01-14 19:00:52 -0800
commitdac4a490f66ef501fb8d7b246ed3c21a8bcfa485 (patch)
treee94702f122dd5eecad9a3a6a2795538bddb47f09 /src/debug
parentf06fa2ea19a57631d7bac1fad232888a2c039a9b (diff)
downloadcoreclr-dac4a490f66ef501fb8d7b246ed3c21a8bcfa485.tar.gz
coreclr-dac4a490f66ef501fb8d7b246ed3c21a8bcfa485.tar.bz2
coreclr-dac4a490f66ef501fb8d7b246ed3c21a8bcfa485.zip
Add debugger launch to dbgshim for xplat.
Add the RegisterForRuntimeStartup/UnregisterForRuntimeStartup to dbghim. Executes the callback when the coreclr runtime starts in the specified process. The callback is passed the proper ICorDebug instance for the version of the runtime or an error if something fails. This API works for launch and attach (and even the attach scenario if the runtime hasn't been loaded yet) equally on both xplat and Windows. The callback is always called on a separate thread. This API returns immediately. The callback is invoke when the coreclr runtime module is loaded during early initialization. The runtime is blocked during initialization until the callback returns. HRESULT RegisterForRuntimeStartup( __in DWORD dwProcessId, __in PSTARTUP_CALLBACK pfnCallback, __in PVOID parameter, __out PVOID *ppUnregisterToken) HRESULT UnregisterForRuntimeStartup( __in PVOID pUnregisterToken) Most of the work is done for xplat in the PAL_RegisterForRuntimeStartup and PAL_UnregisterForRuntimeStartup. On Windows, the APIs are implemented on top of the old dbgshim ones. Added reference counting to DbgTransportSession so the cleanup can be done after the transport worker and the main code is finished. Fix a hang in OSX initializing multiple PALs in the debugging test dbg, dbgshim and mscordaccore by not calling FILEInitStdHandles() from PAL_InitializeDLL. Fixed a minor EnumerateCLRs bug in an error path. A ThrowHR instead of returning the HRESULT. Better pipe file/dbg transport cleanup. Now also call the dbg transport connection abort for an unhandled native exception. Added PROCAbort to replace most calls to abort(). The shutdown handler is called in PROCAbort(). Cleanup debugger transport pipes on CTRL-C termination. Cleanup process code; remove now useless CProcSharedData. Added "PROCESS" PAL trace type.
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/di/dbgtransportmanager.cpp3
-rw-r--r--src/debug/ee/debugger.cpp282
-rw-r--r--src/debug/ee/debugger.h2
-rw-r--r--src/debug/inc/dbgtransportsession.h29
-rw-r--r--src/debug/inc/debug-pal.h16
-rw-r--r--src/debug/shared/dbgtransportsession.cpp69
6 files changed, 215 insertions, 186 deletions
diff --git a/src/debug/di/dbgtransportmanager.cpp b/src/debug/di/dbgtransportmanager.cpp
index e9b619de18..c5f60f3a02 100644
--- a/src/debug/di/dbgtransportmanager.cpp
+++ b/src/debug/di/dbgtransportmanager.cpp
@@ -74,6 +74,7 @@ HRESULT DbgTransportTarget::GetTransportForProcess(DWORD dwPID
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
if (hProcess == NULL)
{
+ transport->Shutdown();
return HRESULT_FROM_GetLastError();
}
@@ -160,7 +161,6 @@ void DbgTransportTarget::ReleaseTransport(DbgTransportSession *pTransport)
_ASSERTE(!"Trying to release transport that doesn't belong to this DbgTransportTarget");
pTransport->Shutdown();
- delete pTransport;
}
HRESULT DbgTransportTarget::CreateProcess(LPCWSTR lpApplicationName,
@@ -211,7 +211,6 @@ DbgTransportTarget::ProcessEntry::~ProcessEntry()
m_hProcess = NULL;
m_transport->Shutdown();
- delete m_transport;
m_transport = NULL;
}
diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp
index 12a7473e8e..6279ed0499 100644
--- a/src/debug/ee/debugger.cpp
+++ b/src/debug/ee/debugger.cpp
@@ -904,7 +904,6 @@ HRESULT ValidateObject(Object *objPtr)
#ifdef FEATURE_DBGIPC_TRANSPORT_VM
-__attribute__((destructor))
void
ShutdownTransport()
{
@@ -914,6 +913,15 @@ ShutdownTransport()
g_pDbgTransport = NULL;
}
}
+
+void
+AbortTransport()
+{
+ if (g_pDbgTransport != NULL)
+ {
+ g_pDbgTransport->AbortConnection();
+ }
+}
#endif // FEATURE_DBGIPC_TRANSPORT_VM
@@ -1742,21 +1750,16 @@ void Debugger::RaiseStartupNotification()
// that it's flushed from any CPU cache into memory.
InterlockedIncrement(&m_fLeftSideInitialized);
+#ifndef FEATURE_DBGIPC_TRANSPORT_VM
// If we are remote debugging, don't send the event now if a debugger is not attached. No one will be
// listening, and we will fail. However, we still want to initialize the variable above.
- BOOL fRaiseStartupNotification = TRUE;
-#if defined(FEATURE_DBGIPC_TRANSPORT_VM)
- fRaiseStartupNotification = (CORDebuggerAttached() ? TRUE : FALSE);
-#endif
- if (fRaiseStartupNotification)
- {
- DebuggerIPCEvent startupEvent;
- InitIPCEvent(&startupEvent, DB_IPCE_LEFTSIDE_STARTUP, NULL, VMPTR_AppDomain::NullPtr());
-
- SendRawEvent(&startupEvent);
+ DebuggerIPCEvent startupEvent;
+ InitIPCEvent(&startupEvent, DB_IPCE_LEFTSIDE_STARTUP, NULL, VMPTR_AppDomain::NullPtr());
+
+ SendRawEvent(&startupEvent);
- // RS will set flags from OOP while we're stopped at the event if it wants to attach.
- }
+ // RS will set flags from OOP while we're stopped at the event if it wants to attach.
+#endif // FEATURE_DBGIPC_TRANSPORT_VM
}
@@ -1884,7 +1887,8 @@ void Debugger::SendCreateProcess(DebuggerLockHolder * pDbgLockHolder)
pDbgLockHolder->Acquire();
}
-#ifdef FEATURE_CORECLR
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_PAL)
+
HANDLE g_hContinueStartupEvent = NULL;
CLR_ENGINE_METRICS g_CLREngineMetrics = {
@@ -1895,9 +1899,6 @@ CLR_ENGINE_METRICS g_CLREngineMetrics = {
bool IsTelestoDebugPackInstalled()
{
-#ifdef FEATURE_PAL
- return false;
-#else
RegKeyHolder hKey;
if (ERROR_SUCCESS != WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &hKey))
return false;
@@ -1916,10 +1917,8 @@ bool IsTelestoDebugPackInstalled()
// RegCloseKey called by holder
return debugPackInstalled;
-#endif // FEATURE_PAL
}
-
#define StartupNotifyEventNamePrefix W("TelestoStartupEvent_")
const int cchEventNameBufferSize = sizeof(StartupNotifyEventNamePrefix)/sizeof(WCHAR) + 8; // + hex DWORD (8). NULL terminator is included in sizeof(StartupNotifyEventNamePrefix)
HANDLE OpenStartupNotificationEvent()
@@ -1957,7 +1956,8 @@ void NotifyDebuggerOfTelestoStartup()
CloseHandle(g_hContinueStartupEvent);
g_hContinueStartupEvent = NULL;
}
-#endif // FEATURE_CORECLR
+
+#endif // FEATURE_CORECLR && !FEATURE_PAL
//---------------------------------------------------------------------------------------
//
@@ -1996,10 +1996,8 @@ HRESULT Debugger::Startup(void)
// Iff the debug pack is installed, then go through the telesto debugging pipeline.
LOG((LF_CORDB, LL_INFO10, "Debugging service is enabled because debug pack is installed or Watson support is enabled)\n"));
-#if !defined(FEATURE_DBGIPC_TRANSPORT_VM)
// This may block while an attach occurs.
NotifyDebuggerOfTelestoStartup();
-#endif
}
else
{
@@ -2013,164 +2011,162 @@ HRESULT Debugger::Startup(void)
}
#endif // FEATURE_CORECLR && !FEATURE_PAL
- DebuggerLockHolder dbgLockHolder(this);
+ {
+ DebuggerLockHolder dbgLockHolder(this);
- // Stubs in Stacktraces are always enabled.
- g_EnableSIS = true;
+ // Stubs in Stacktraces are always enabled.
+ g_EnableSIS = true;
- // We can get extra Interop-debugging test coverage by having some auxillary unmanaged
- // threads running and throwing debug events. Keep these stress procs separate so that
- // we can focus on certain problem areas.
-#ifdef _DEBUG
+ // We can get extra Interop-debugging test coverage by having some auxillary unmanaged
+ // threads running and throwing debug events. Keep these stress procs separate so that
+ // we can focus on certain problem areas.
+ #ifdef _DEBUG
- g_DbgShouldntUseDebugger = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgNoDebugger) != 0;
+ g_DbgShouldntUseDebugger = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgNoDebugger) != 0;
- // Creates random thread procs.
- DWORD dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreads);
- DWORD dwId;
- DWORD i;
+ // Creates random thread procs.
+ DWORD dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreads);
+ DWORD dwId;
+ DWORD i;
- if (dwRegVal > 0)
- {
- for(i = 0; i < dwRegVal; i++)
+ if (dwRegVal > 0)
{
- int iProc = GetRandomInt(NumItems(g_pStressProcs));
- LPTHREAD_START_ROUTINE pStartRoutine = g_pStressProcs[iProc];
- ::CreateThread(NULL, 0, pStartRoutine, NULL, 0, &dwId);
- LOG((LF_CORDB, LL_INFO1000, "Created random thread (%d) with tid=0x%x\n", i, dwId));
+ for (i = 0; i < dwRegVal; i++)
+ {
+ int iProc = GetRandomInt(NumItems(g_pStressProcs));
+ LPTHREAD_START_ROUTINE pStartRoutine = g_pStressProcs[iProc];
+ ::CreateThread(NULL, 0, pStartRoutine, NULL, 0, &dwId);
+ LOG((LF_CORDB, LL_INFO1000, "Created random thread (%d) with tid=0x%x\n", i, dwId));
+ }
}
- }
- dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsIB);
- if (dwRegVal > 0)
- {
- for(i = 0; i < dwRegVal; i++)
+ dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsIB);
+ if (dwRegVal > 0)
{
- ::CreateThread(NULL, 0, DbgInteropStressProc, NULL, 0, &dwId);
- LOG((LF_CORDB, LL_INFO1000, "Created extra thread (%d) with tid=0x%x\n", i, dwId));
+ for (i = 0; i < dwRegVal; i++)
+ {
+ ::CreateThread(NULL, 0, DbgInteropStressProc, NULL, 0, &dwId);
+ LOG((LF_CORDB, LL_INFO1000, "Created extra thread (%d) with tid=0x%x\n", i, dwId));
+ }
}
- }
- dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsCantStop);
- if (dwRegVal > 0)
- {
- for(i = 0; i < dwRegVal; i++)
+ dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsCantStop);
+ if (dwRegVal > 0)
{
- ::CreateThread(NULL, 0, DbgInteropCantStopStressProc, NULL, 0, &dwId);
- LOG((LF_CORDB, LL_INFO1000, "Created extra thread 'can't-stop' (%d) with tid=0x%x\n", i, dwId));
+ for (i = 0; i < dwRegVal; i++)
+ {
+ ::CreateThread(NULL, 0, DbgInteropCantStopStressProc, NULL, 0, &dwId);
+ LOG((LF_CORDB, LL_INFO1000, "Created extra thread 'can't-stop' (%d) with tid=0x%x\n", i, dwId));
+ }
}
- }
- dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsOOB);
- if (dwRegVal > 0)
- {
- for(i = 0; i < dwRegVal; i++)
+ dwRegVal = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgExtraThreadsOOB);
+ if (dwRegVal > 0)
{
- ::CreateThread(NULL, 0, DbgInteropOOBStressProc, NULL, 0, &dwId);
- LOG((LF_CORDB, LL_INFO1000, "Created extra thread OOB (%d) with tid=0x%x\n", i, dwId));
+ for (i = 0; i < dwRegVal; i++)
+ {
+ ::CreateThread(NULL, 0, DbgInteropOOBStressProc, NULL, 0, &dwId);
+ LOG((LF_CORDB, LL_INFO1000, "Created extra thread OOB (%d) with tid=0x%x\n", i, dwId));
+ }
}
- }
-#endif
+ #endif
-#ifdef FEATURE_PAL
- PAL_InitializeDebug();
-#endif // FEATURE_PAL
+ #ifdef FEATURE_PAL
+ PAL_InitializeDebug();
+ #endif // FEATURE_PAL
- // Lazily initialize the interop-safe heap
+ // Lazily initialize the interop-safe heap
- // Must be done before the RC thread is initialized.
- // @dbgtodo - In V2, LS was lazily initialized; but was eagerly pre-initialized if launched by debugger.
- // (This was for perf reasons). But we don't want Launch vs. Attach checks in the LS, so we now always
- // init. As we move more to OOP, this init will become cheaper.
- {
- LazyInit();
- DebuggerController::Initialize();
- }
+ // Must be done before the RC thread is initialized.
+ // @dbgtodo - In V2, LS was lazily initialized; but was eagerly pre-initialized if launched by debugger.
+ // (This was for perf reasons). But we don't want Launch vs. Attach checks in the LS, so we now always
+ // init. As we move more to OOP, this init will become cheaper.
+ {
+ LazyInit();
+ DebuggerController::Initialize();
+ }
- InitializeHijackFunctionAddress();
+ InitializeHijackFunctionAddress();
- // Create the runtime controller thread, a.k.a, the debug helper thread.
- // Don't use the interop-safe heap b/c we don't want to lazily create it.
- m_pRCThread = new DebuggerRCThread(this);
-
- _ASSERTE(m_pRCThread != NULL); // throws on oom
- TRACE_ALLOC(m_pRCThread);
+ // Create the runtime controller thread, a.k.a, the debug helper thread.
+ // Don't use the interop-safe heap b/c we don't want to lazily create it.
+ m_pRCThread = new DebuggerRCThread(this);
+ _ASSERTE(m_pRCThread != NULL); // throws on oom
+ TRACE_ALLOC(m_pRCThread);
- hr = m_pRCThread->Init();
-
- _ASSERTE(SUCCEEDED(hr)); // throws on error
+ hr = m_pRCThread->Init();
+ _ASSERTE(SUCCEEDED(hr)); // throws on error
-#if defined(FEATURE_DBGIPC_TRANSPORT_VM)
- // Create transport session and initialize it.
- g_pDbgTransport = new DbgTransportSession();
- hr = g_pDbgTransport->Init(m_pRCThread->GetDCB(), m_pAppDomainCB);
- if (FAILED(hr))
- ThrowHR(hr);
+ #if defined(FEATURE_DBGIPC_TRANSPORT_VM)
+ // Create transport session and initialize it.
+ g_pDbgTransport = new DbgTransportSession();
+ hr = g_pDbgTransport->Init(m_pRCThread->GetDCB(), m_pAppDomainCB);
+ if (FAILED(hr))
+ {
+ ShutdownTransport();
+ ThrowHR(hr);
+ }
-#ifdef FEATURE_PAL
- PAL_SetShutdownCallback(ShutdownTransport);
-#endif // FEATURE_PAL
+ #ifdef FEATURE_PAL
+ PAL_SetShutdownCallback(AbortTransport);
+ #endif // FEATURE_PAL
+ #endif // FEATURE_DBGIPC_TRANSPORT_VM
- bool waitForAttach = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_DbgWaitForDebuggerAttach) != 0;
- if (waitForAttach)
- {
- // Mark this process as launched by the debugger and the debugger as attached.
- g_CORDebuggerControlFlags |= DBCF_GENERATE_DEBUG_CODE;
- MarkDebuggerAttachedInternal();
+ RaiseStartupNotification();
- LazyInit();
- DebuggerController::Initialize();
- }
-#endif // FEATURE_DBGIPC_TRANSPORT_VM
+ // Also initialize the AppDomainEnumerationIPCBlock
+ #if !defined(FEATURE_IPCMAN) || defined(FEATURE_DBGIPC_TRANSPORT_VM)
+ m_pAppDomainCB = new (nothrow) AppDomainEnumerationIPCBlock();
+ #else
+ m_pAppDomainCB = g_pIPCManagerInterface->GetAppDomainBlock();
+ #endif
- RaiseStartupNotification();
-
- // Also initialize the AppDomainEnumerationIPCBlock
-#if !defined(FEATURE_IPCMAN) || defined(FEATURE_DBGIPC_TRANSPORT_VM)
- m_pAppDomainCB = new (nothrow) AppDomainEnumerationIPCBlock();
-#else
- m_pAppDomainCB = g_pIPCManagerInterface->GetAppDomainBlock();
-#endif
+ if (m_pAppDomainCB == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO100, "D::S: Failed to get AppDomain IPC block from IPCManager.\n"));
+ ThrowHR(E_FAIL);
+ }
- if (m_pAppDomainCB == NULL)
- {
- LOG((LF_CORDB, LL_INFO100, "D::S: Failed to get AppDomain IPC block from IPCManager.\n"));
- ThrowHR(E_FAIL);
- }
+ hr = InitAppDomainIPC();
+ _ASSERTE(SUCCEEDED(hr)); // throws on error.
- hr = InitAppDomainIPC();
- _ASSERTE(SUCCEEDED(hr)); // throws on error.
+ // See if we need to spin up the helper thread now, rather than later.
+ DebuggerIPCControlBlock* pIPCControlBlock = m_pRCThread->GetDCB();
+ (void)pIPCControlBlock; //prevent "unused variable" error from GCC
- // See if we need to spin up the helper thread now, rather than later.
- DebuggerIPCControlBlock* pIPCControlBlock = m_pRCThread->GetDCB();
- (void)pIPCControlBlock; //prevent "unused variable" error from GCC
+ _ASSERTE(pIPCControlBlock != NULL);
+ _ASSERTE(!pIPCControlBlock->m_rightSideShouldCreateHelperThread);
+ {
+ // Create the win32 thread for the helper and let it run free.
+ hr = m_pRCThread->Start();
- _ASSERTE(pIPCControlBlock != NULL);
+ // convert failure to exception as with old contract
+ if (FAILED(hr))
+ {
+ ThrowHR(hr);
+ }
- _ASSERTE(!pIPCControlBlock->m_rightSideShouldCreateHelperThread);
- {
- // Create the win32 thread for the helper and let it run free.
- hr = m_pRCThread->Start();
+ LOG((LF_CORDB, LL_EVERYTHING, "Start was successful\n"));
+ }
- // convert failure to exception as with old contract
- if (FAILED(hr))
+ #ifdef TEST_DATA_CONSISTENCY
+ // if we have set the environment variable TestDataConsistency, run the data consistency test.
+ // See code:DataTest::TestDataSafety for more information
+ if ((g_pConfig != NULL) && (g_pConfig->TestDataConsistency() == true))
{
- ThrowHR(hr);
+ DataTest dt;
+ dt.TestDataSafety();
}
-
- LOG((LF_CORDB, LL_EVERYTHING, "Start was successful\n"));
+ #endif
}
-#ifdef TEST_DATA_CONSISTENCY
- // if we have set the environment variable TestDataConsistency, run the data consistency test.
- // See code:DataTest::TestDataSafety for more information
- if((g_pConfig != NULL) && (g_pConfig->TestDataConsistency() == true))
- {
- DataTest dt;
- dt.TestDataSafety();
- }
-#endif
+#ifdef FEATURE_PAL
+ // Signal the debugger (via dbgshim) and wait until it is ready for us to
+ // continue. This needs to be outside the lock and after the transport is
+ // initialized.
+ PAL_NotifyRuntimeStarted();
+#endif // FEATURE_PAL
// We don't bother changing this process's permission.
// A managed debugger will have the SE_DEBUG permission which will allow it to open our process handle,
@@ -2584,11 +2580,9 @@ void Debugger::StopDebugger(void)
m_pRCThread->AsyncStop();
}
-
// Also clean up the AppDomain stuff since this is cross-process.
TerminateAppDomainIPC ();
-
//
// Tell the VM to clear out all references to the debugger before we start cleaning up,
// so that nothing will reference (accidentally) through the partially cleaned up debugger.
diff --git a/src/debug/ee/debugger.h b/src/debug/ee/debugger.h
index 5e4ff53562..d14c83c87a 100644
--- a/src/debug/ee/debugger.h
+++ b/src/debug/ee/debugger.h
@@ -111,7 +111,9 @@ typedef DPTR(struct DebuggerIPCControlBlock) PTR_DebuggerIPCControlBlock;
GPTR_DECL(Debugger, g_pDebugger);
GPTR_DECL(EEDebugInterface, g_pEEInterface);
+#ifndef FEATURE_PAL
GVAL_DECL(HANDLE, g_hContinueStartupEvent);
+#endif
extern DebuggerRCThread *g_pRCThread;
//---------------------------------------------------------------------------------------
diff --git a/src/debug/inc/dbgtransportsession.h b/src/debug/inc/dbgtransportsession.h
index 3b38b87bb7..0c0b37e67d 100644
--- a/src/debug/inc/dbgtransportsession.h
+++ b/src/debug/inc/dbgtransportsession.h
@@ -306,10 +306,12 @@ enum IPCEventType
class DbgTransportSession
{
public:
-
// No real work done in the constructor. Use Init() instead.
DbgTransportSession();
+ // Cleanup what is allocated/created in Init()
+ ~DbgTransportSession();
+
// Allocates initial resources (including starting the transport thread). The session will start in the
// SS_Opening state. That is, the RS will immediately start trying to Connect() a connection while the
// LS will perform an Accept() to wait for a connection request. The RS needs an IP address and port
@@ -330,6 +332,28 @@ public:
// Init() may be called again to start over from the beginning).
void Shutdown();
+ // Cleans up the named pipe connection so no tmp files are left behind. Does only
+ // the minimum and must be safe to call at any time. Called during PAL ExitProcess,
+ // TerminateProcess and for unhandled native exceptions and asserts.
+ void AbortConnection();
+
+ LONG AddRef()
+ {
+ LONG ref = InterlockedIncrement(&m_ref);
+ return ref;
+ }
+
+ LONG Release()
+ {
+ _ASSERTE(m_ref > 0);
+ LONG ref = InterlockedDecrement(&m_ref);
+ if (ref == 0)
+ {
+ delete this;
+ }
+ return ref;
+ }
+
#ifndef RIGHT_SIDE_COMPILE
// API used only by the LS to drive the transport into a state where it won't accept connections. This is
// used when no proxy is detected at startup but it's too late to shutdown all of the debugging system
@@ -614,6 +638,9 @@ private:
#endif // _DEBUG
+ // Reference count
+ LONG m_ref;
+
// Some flags used to record how far we got in Init() (used for cleanup in Shutdown()).
bool m_fInitStateLock;
#ifndef RIGHT_SIDE_COMPILE
diff --git a/src/debug/inc/debug-pal.h b/src/debug/inc/debug-pal.h
deleted file mode 100644
index 90cf0c822e..0000000000
--- a/src/debug/inc/debug-pal.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-
-#ifndef Debug_PAL_H
-#define Debug_PAL_H
-
-#if defined(FEATURE_PAL)
-// This function looks for a dynamic module (libraryName) loaded into the process specified (pId)
-// and returns its load address. NULL is module is not loaded.
-void *GetDynamicLibraryAddressInProcess(DWORD pid, const char *libraryName);
-#endif
-
-#endif //Debug_PAL_H \ No newline at end of file
diff --git a/src/debug/shared/dbgtransportsession.cpp b/src/debug/shared/dbgtransportsession.cpp
index 01f4acbc66..5aa9f28e15 100644
--- a/src/debug/shared/dbgtransportsession.cpp
+++ b/src/debug/shared/dbgtransportsession.cpp
@@ -36,9 +36,37 @@ DbgTransportSession *g_pDbgTransport = NULL;
// No real work done in the constructor. Use Init() instead.
DbgTransportSession::DbgTransportSession()
{
+ m_ref = 1;
m_eState = SS_Closed;
}
+DbgTransportSession::~DbgTransportSession()
+{
+ DbgTransportLog(LC_Proxy, "DbgTransportSession::~DbgTransportSession() called");
+
+ // No other threads are now using session resources. We're free to deallocate them as we wish (if they
+ // were allocated in the first place).
+ if (m_hTransportThread)
+ CloseHandle(m_hTransportThread);
+ if (m_rghEventReadyEvent[IPCET_OldStyle])
+ CloseHandle(m_rghEventReadyEvent[IPCET_OldStyle]);
+ if (m_rghEventReadyEvent[IPCET_DebugEvent])
+ CloseHandle(m_rghEventReadyEvent[IPCET_DebugEvent]);
+ if (m_pEventBuffers)
+ delete [] m_pEventBuffers;
+
+#ifdef RIGHT_SIDE_COMPILE
+ if (m_hSessionOpenEvent)
+ CloseHandle(m_hSessionOpenEvent);
+
+ if (m_hProcessExited)
+ CloseHandle(m_hProcessExited);
+#endif // RIGHT_SIDE_COMPILE
+
+ if (m_fInitStateLock)
+ m_sStateLock.Destroy();
+}
+
// Allocates initial resources (including starting the transport thread). The session will start in the
// SS_Opening state. That is, the RS will immediately start trying to Connect() a connection while the LS will
// perform an accept()/Accept() to wait for a connection request. The RS needs an IP address and port number
@@ -59,6 +87,7 @@ HRESULT DbgTransportSession::Init(DebuggerIPCControlBlock *pDCB, AppDomainEnumer
// Because of the above memset the embeded classes/structs need to be reinitialized especially
// the two way pipe; it expects the in/out handles to be -1 instead of 0.
+ m_ref = 1;
m_pipe = TwoWayPipe();
m_sStateLock = DbgTransportLock();
@@ -124,9 +153,13 @@ HRESULT DbgTransportSession::Init(DebuggerIPCControlBlock *pDCB, AppDomainEnumer
// Start the transport thread which handles forming and re-forming connections, driving the session
// state to SS_Open and receiving and initially processing all incoming traffic.
+ AddRef();
m_hTransportThread = CreateThread(NULL, 0, TransportWorkerStatic, this, 0, NULL);
if (m_hTransportThread == NULL)
+ {
+ Release();
return E_OUTOFMEMORY;
+ }
return S_OK;
}
@@ -178,30 +211,16 @@ void DbgTransportSession::Shutdown()
#endif // RIGHT_SIDE_COMPILE
}
- // No other threads are now using session resources. We're free to deallocate them as we wish (if they
- // were allocated in the first place).
- if (m_hTransportThread)
- CloseHandle(m_hTransportThread);
- if (m_rghEventReadyEvent[IPCET_OldStyle])
- CloseHandle(m_rghEventReadyEvent[IPCET_OldStyle]);
- if (m_rghEventReadyEvent[IPCET_DebugEvent])
- CloseHandle(m_rghEventReadyEvent[IPCET_DebugEvent]);
- if (m_pEventBuffers)
- delete [] m_pEventBuffers;
-
-#ifdef RIGHT_SIDE_COMPILE
- if (m_hSessionOpenEvent)
- CloseHandle(m_hSessionOpenEvent);
-
- if (m_hProcessExited)
- {
- CloseHandle(m_hProcessExited);
- }
-#endif // RIGHT_SIDE_COMPILE
-
- if (m_fInitStateLock)
- m_sStateLock.Destroy();
+ // The transport instance is no longer valid
+ Release();
+}
+// Cleans up the named pipe connection so no tmp files are left behind. Does only
+// the minimum and must be safe to call at any time. Called during PAL ExitProcess,
+// TerminateProcess and for unhandled native exceptions and asserts.
+void DbgTransportSession::AbortConnection()
+{
+ m_pipe.Disconnect();
}
#ifndef RIGHT_SIDE_COMPILE
@@ -2125,6 +2144,10 @@ void DbgTransportSession::TransportWorker()
}
}
} // Leave m_sStateLock
+
+ // Now release all the resources allocated for the transport now that the
+ // worker thread isn't using them anymore.
+ Release();
}
// Given a fully initialized debugger event structure, return the size of the structure in bytes (this is not