void TwoWayPipe::GetPipeName(char *name, DWORD id, const char *suffix)
{
- UINT64 disambiguationKey;
- BOOL ret = GetProcessIdDisambiguationKey(id, &disambiguationKey);
+ BOOL ret = GetProcessIdDisambiguationKey(id, &m_disambiguationKey);
// If GetProcessIdDisambiguationKey failed for some reason, it should set the value
// to 0. We expect that anyone else making the pipe name will also fail and thus will
// also try to use 0 as the value.
- _ASSERTE(ret == TRUE || disambiguationKey == 0);
+ _ASSERTE(ret == TRUE || m_disambiguationKey == 0);
- int chars = _snprintf(name, MaxPipeNameLength, PipeNameFormat, id, disambiguationKey, suffix);
+ int chars = _snprintf(name, MaxPipeNameLength, PipeNameFormat, id, m_disambiguationKey, suffix);
_ASSERTE(chars > 0 && chars < MaxPipeNameLength);
}
m_state = NotInitialized;
return true;
}
+
+// Used by debugger side (RS) to cleanup the target (LS) named pipes
+// and semaphores when the debugger detects the debuggee process exited.
+void TwoWayPipe::CleanupTargetProcess()
+{
+ unlink(m_inPipeName);
+ unlink(m_outPipeName);
+ PAL_CleanupTargetProcess(m_id, m_disambiguationKey);
+}
// Terminate the debuggee process.
virtual BOOL TerminateProcess(UINT32 exitCode);
+#ifdef FEATURE_PAL
+ virtual void CleanupTargetProcess()
+ {
+ m_pTransport->CleanupTargetProcess();
+ }
+#endif
+
private:
// Return TRUE if the transport is up and runnning
BOOL IsTransportRunning()
{
return S_FALSE;
}
+
+#ifdef FEATURE_PAL
+ // Used by debugger side (RS) to cleanup the target (LS) named pipes
+ // and semaphores when the debugger detects the debuggee process exited.
+ virtual void CleanupTargetProcess()
+ {
+ }
+#endif
};
//
PUBLIC_CALLBACK_IN_THIS_SCOPE0_NO_LOCK(GetProcess());
pCordb->m_managedCallback->ExitProcess(GetProcess());
}
+
// This CordbProcess object now has no reservations against a client calling ICorDebug::Terminate.
// That call may race against the CordbProcess::Neuter below, but since we already neutered the children,
// that neuter call will not do anything interesting that will conflict with Terminate.
-
LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: returned from ExitProcess callback\n"));
-
{
RSLockHolder ch(GetProcess()->GetStopGoLock());
// and dispatch it inband w/the other callbacks.
if (!fDetach)
{
+#ifdef FEATURE_PAL
+ // Cleanup the transport pipe and semaphore files that might be left by the target (LS) process.
+ m_pNativePipeline->CleanupTargetProcess();
+#endif
ExitProcessWorkItem * pItem = new (nothrow) ExitProcessWorkItem(m_pProcess);
if (pItem != NULL)
{
// may be delivered once the session is established.
#ifdef RIGHT_SIDE_COMPILE
HRESULT Init(DWORD pid, HANDLE hProcessExited);
-#else // RIGHT_SIDE_COMPILE
+#else
HRESULT Init(DebuggerIPCControlBlock * pDCB, AppDomainEnumerationIPCBlock * pADB);
#endif // RIGHT_SIDE_COMPILE
// Init() may be called again to start over from the beginning).
void Shutdown();
+#ifdef RIGHT_SIDE_COMPILE
+ // Used by debugger side (RS) to cleanup the target (LS) named pipes
+ // and semaphores when the debugger detects the debuggee process exited.
+ void CleanupTargetProcess();
+#else
// 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();
+#endif // RIGHT_SIDE_COMPILE
LONG AddRef()
{
return m_state;
}
+ // Used by debugger side (RS) to cleanup the target (LS) named pipes
+ // and semaphores when the debugger detects the debuggee process exited.
+ void CleanupTargetProcess();
+
private:
State m_state;
static const int MaxPipeNameLength = 64;
- static void GetPipeName(char *name, DWORD id, const char *suffix);
+ void GetPipeName(char *name, DWORD id, const char *suffix);
- int m_id; //id that was passed to CreateServer() or Connect()
- int m_inboundPipe, m_outboundPipe; //two one sided pipes used for communication
- char m_inPipeName[MaxPipeNameLength]; //filename of the inbound pipe
- char m_outPipeName[MaxPipeNameLength]; //filename of the outbound pipe
+ int m_id; // id that was passed to CreateServer() or Connect()
+ int m_inboundPipe, m_outboundPipe; // two one sided pipes used for communication
+ UINT64 m_disambiguationKey; // key to make the names more unique
+ char m_inPipeName[MaxPipeNameLength]; // filename of the inbound pipe
+ char m_outPipeName[MaxPipeNameLength]; // filename of the outbound pipe
#else
// Connects to a one sided pipe previously created by CreateOneWayPipe.
Release();
}
+#ifndef RIGHT_SIDE_COMPILE
+
// 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.
m_pipe.Disconnect();
}
-#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 easily. It's
// mainly paranoia to increase the protection of your system when the proxy isn't started.
// AV on a deallocated handle, which might happen if we simply called Shutdown()).
m_eState = SS_Closed;
}
-#endif // !RIGHT_SIDE_COMPILE
-#ifdef RIGHT_SIDE_COMPILE
+#else // RIGHT_SIDE_COMPILE
+
+// Used by debugger side (RS) to cleanup the target (LS) named pipes
+// and semaphores when the debugger detects the debuggee process exited.
+void DbgTransportSession::CleanupTargetProcess()
+{
+ m_pipe.CleanupTargetProcess();
+}
+
// On the RS it may be useful to wait and see if the session can reach the SS_Open state. If the target
// runtime has terminated for some reason then we'll never reach the open state. So the method below gives the
// RS a way to try and establish a connection for a reasonable amount of time and to time out otherwise. They
PAL_NotifyRuntimeStarted();
PALIMPORT
+VOID
+PALAPI
+PAL_CleanupTargetProcess(
+ IN int pid,
+ IN UINT64 disambiguationKey);
+
+PALIMPORT
void
PALAPI
PAL_InitializeDebug(
{
PAL_ERROR pe = NO_ERROR;
- // Enumerate all the modules in the process and invoke the callback
- // for the coreclr module if found.
- DWORD count;
- ProcessModules *listHead = CreateProcessModules(m_processId, &count);
- if (listHead == NULL)
+ if (!m_canceled)
{
- TRACE("CreateProcessModules failed for pid %d\n", m_processId);
- pe = ERROR_INVALID_PARAMETER;
- goto exit;
- }
+ // Enumerate all the modules in the process and invoke the callback
+ // for the coreclr module if found.
+ DWORD count;
+ ProcessModules *listHead = CreateProcessModules(m_processId, &count);
+ if (listHead == NULL)
+ {
+ TRACE("CreateProcessModules failed for pid %d\n", m_processId);
+ pe = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
- for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
- {
- if (IsCoreClrModule(entry->Name))
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
{
- PAL_CPP_TRY
+ if (IsCoreClrModule(entry->Name))
{
- TRACE("InvokeStartupCallback executing callback %p %s\n", entry->BaseAddress, entry->Name);
- m_callback(entry->Name, entry->BaseAddress, m_parameter);
- }
- PAL_CPP_CATCH_ALL
- {
- }
- PAL_CPP_ENDTRY
+ PAL_CPP_TRY
+ {
+ TRACE("InvokeStartupCallback executing callback %p %s\n", entry->BaseAddress, entry->Name);
+ m_callback(entry->Name, entry->BaseAddress, m_parameter);
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ }
+ PAL_CPP_ENDTRY
- // Currently only the first coreclr module in a process is supported
- break;
+ // Currently only the first coreclr module in a process is supported
+ break;
+ }
}
- }
- exit:
- if (listHead != NULL)
- {
- DestroyProcessModules(listHead);
+ exit:
+ if (listHead != NULL)
+ {
+ DestroyProcessModules(listHead);
+ }
}
return pe;
// Wait until the coreclr runtime (debuggee) starts up
if (sem_wait(m_startupSem) == 0)
{
- if (!m_canceled)
+ // The continue semaphore should exists now and is needed to wake up the runtimes below
+ continueSem = sem_open(continueSemName, O_RDWR);
+ if (continueSem != SEM_FAILED)
{
- // The continue semaphore should exists now and is needed to wake up the runtimes below
- continueSem = sem_open(continueSemName, O_RDWR);
- if (continueSem != SEM_FAILED)
- {
- TRACE("StartupHelperThread continue sem exists after wait - invoking callback\n");
- pe = InvokeStartupCallback();
- }
- else
- {
- TRACE("sem_open(continue) failed: errno is %d (%s)\n", errno, strerror(errno));
- pe = GetSemError();
- }
+ TRACE("StartupHelperThread continue sem exists after wait - invoking callback\n");
+ pe = InvokeStartupCallback();
+ }
+ else
+ {
+ TRACE("sem_open(continue) failed: errno is %d (%s)\n", errno, strerror(errno));
+ pe = GetSemError();
}
}
else
}
/*++
+ PAL_CleanupTargetProcess
+
+ Cleanup the target process's name continue semaphore
+ on the debugger side when the debugger detects the
+ process termination.
+
+Parameters:
+ pid - process id
+ disambiguationKey - key to make process id unique
+
+Return value:
+ None
+--*/
+VOID
+PALAPI
+PAL_CleanupTargetProcess(
+ IN int pid,
+ IN UINT64 disambiguationKey)
+{
+ char continueSemName[NAME_MAX - 4];
+
+ sprintf_s(continueSemName,
+ sizeof(continueSemName),
+ RuntimeContinueSemaphoreName,
+ pid,
+ disambiguationKey);
+
+ sem_unlink(continueSemName);
+}
+
+/*++
Function:
GetProcessIdDisambiguationKey
FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
-#if defined(DEBUGGING_SUPPORTED) && defined(FEATURE_PAL)
- // Terminate the debugging services in the first phase for PAL based platforms
- // because EEDllMain's DLL_PROCESS_DETACH is NOT going to be called.
- TerminateDebugger();
-#endif // DEBUGGING_SUPPORTED && FEATURE_PAL
-
if (g_fProcessDetach)
{
ThreadStore::TrapReturningThreads(TRUE);