<Comment> An unknown error occurred in the Diagnpostics IPC Server. </Comment>
</HRESULT>
+<HRESULT NumericValue="0x80131388">
+ <SymbolicName>CORPROF_E_SUSPENSION_IN_PROGRESS</SymbolicName>
+ <Comment> The runtime cannot be suspened since a suspension is already in progress. </Comment>
+</HRESULT>
+
<HRESULT NumericValue="0x80131401">
<SymbolicName>SECURITY_E_INCOMPATIBLE_SHARE</SymbolicName>
<Message>"Loading this assembly would produce a different grant set from other instances."</Message>
[in] ULONG cFunctions,
[in, size_is(cFunctions)] ModuleID moduleIds[],
[in, size_is(cFunctions)] mdMethodDef methodIds[]);
+
+ // Suspend the runtime without performing a GC.
+ HRESULT SuspendRuntime();
+
+ // Restart the runtime from a previous suspension.
+ HRESULT ResumeRuntime();
}
/*
BOOL fConcurrentGCDisabledForAttach;
Volatile<BOOL> fProfControlBlockInitialized;
+
+ Volatile<BOOL> fProfilerRequestedRuntimeSuspend;
void Init();
void ResetPerSessionStatus();
ResetPerSessionStatus();
fProfControlBlockInitialized = TRUE;
+
+ fProfilerRequestedRuntimeSuspend = FALSE;
}
// Reset those variables that is only for the current attach session
#define CORDIAGIPC_E_UNKNOWN_COMMAND EMAKEHR(0x1385)
#define CORDIAGIPC_E_UNKNOWN_MAGIC EMAKEHR(0x1386)
#define CORDIAGIPC_E_UNKNOWN_ERROR EMAKEHR(0x1387)
+#define CORPROF_E_SUSPENSION_IN_PROGRESS EMAKEHR(0x1388)
#define SECURITY_E_INCOMPATIBLE_SHARE EMAKEHR(0x1401)
#define SECURITY_E_UNVERIFIABLE EMAKEHR(0x1402)
#define SECURITY_E_INCOMPATIBLE_EVIDENCE EMAKEHR(0x1403)
/* [size_is][in] */ ModuleID moduleIds[ ],
/* [size_is][in] */ mdMethodDef methodIds[ ]) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SuspendRuntime( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ResumeRuntime( void) = 0;
+
};
/* [size_is][in] */ ModuleID moduleIds[ ],
/* [size_is][in] */ mdMethodDef methodIds[ ]);
+ HRESULT ( STDMETHODCALLTYPE *SuspendRuntime )(
+ ICorProfilerInfo10 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ResumeRuntime )(
+ ICorProfilerInfo10 * This);
+
END_INTERFACE
} ICorProfilerInfo10Vtbl;
#define ICorProfilerInfo10_RequestReJITWithInliners(This,dwRejitFlags,cFunctions,moduleIds,methodIds) \
( (This)->lpVtbl -> RequestReJITWithInliners(This,dwRejitFlags,cFunctions,moduleIds,methodIds) )
+#define ICorProfilerInfo10_SuspendRuntime(This) \
+ ( (This)->lpVtbl -> SuspendRuntime(This) )
+
+#define ICorProfilerInfo10_ResumeRuntime(This) \
+ ( (This)->lpVtbl -> ResumeRuntime(This) )
+
#endif /* COBJMACROS */
}
CONTRACTL_END;
- ThreadStoreLockHolder tsLock;
+ // If a profiler has requested that the runtime suspend to do stack snapshots, it
+ // will be holding the ThreadStore lock already
+ ThreadStoreLockHolder tsLock(!g_profControlBlock.fProfilerRequestedRuntimeSuspend);
Thread * pThread = NULL;
*m_elements.Append() = (ThreadID) pThread;
}
+ _ASSERTE(ThreadStore::HoldingThreadStore() || g_profControlBlock.fProfilerRequestedRuntimeSuspend);
return S_OK;
}
return S_OK;
}
+HRESULT ProfToEEInterfaceImpl::SuspendRuntime()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ CAN_TAKE_LOCK;
+ EE_THREAD_NOT_REQUIRED;
+ }
+ CONTRACTL_END;
+
+ PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
+ kP2EEAllowableAfterAttach | kP2EETriggers,
+ (LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: SuspendRuntime\n"));
+
+ if (!g_fEEStarted)
+ {
+ return CORPROF_E_RUNTIME_UNINITIALIZED;
+ }
+
+ if (ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
+ {
+ return CORPROF_E_SUSPENSION_IN_PROGRESS;
+ }
+
+ g_profControlBlock.fProfilerRequestedRuntimeSuspend = TRUE;
+ ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_FOR_PROFILER);
+ return S_OK;
+}
+
+HRESULT ProfToEEInterfaceImpl::ResumeRuntime()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ CAN_TAKE_LOCK;
+ }
+ CONTRACTL_END;
+
+ PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
+ kP2EEAllowableAfterAttach | kP2EETriggers,
+ (LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: ResumeRuntime\n"));
+
+ if (!g_fEEStarted)
+ {
+ return CORPROF_E_RUNTIME_UNINITIALIZED;
+ }
+
+ if (!g_profControlBlock.fProfilerRequestedRuntimeSuspend)
+ {
+ return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
+ }
+
+ ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);
+ g_profControlBlock.fProfilerRequestedRuntimeSuspend = FALSE;
+ return S_OK;
+}
+
/*
* GetStringLayout
*
BYTE * pbContext,
ULONG32 contextSize)
{
-
-#if !defined(FEATURE_HIJACK)
-
- // DoStackSnapshot needs Thread::Suspend/ResumeThread functionality.
- // On platforms w/o support for these APIs return E_NOTIMPL.
- return E_NOTIMPL;
-
-#else // !defined(FEATURE_HIJACK)
-
CONTRACTL
{
// Yay! (Note: NOTHROW is vital. The throw at minimum allocates
HostCallPreference hostCallPreference;
// First, check "1) Target thread to walk == current thread OR Target thread is suspended"
- if (pThreadToSnapshot != pCurrentThread)
+ if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
{
#ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
hr = E_NOTIMPL;
// inlined P/Invoke. In this case, the InlinedCallFrame will be used to help start off our
// stackwalk at the top of the stack.
//
- if (pThreadToSnapshot != pCurrentThread)
+ if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
{
#ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
hr = E_NOTIMPL;
}
return hr;
-
-#endif // !defined(FEATURE_HIJACK)
}
ModuleID moduleIds[],
mdMethodDef methodIds[]);
+ COM_METHOD SuspendRuntime();
+
+ COM_METHOD ResumeRuntime();
+
// end ICorProfilerInfo10
protected:
SUSPEND_FOR_SHUTDOWN = 4,
SUSPEND_FOR_DEBUGGER = 5,
SUSPEND_FOR_GC_PREP = 6,
- SUSPEND_FOR_DEBUGGER_SWEEP = 7 // This must only be used in Thread::SysSweepThreadsForDebug
+ SUSPEND_FOR_DEBUGGER_SWEEP = 7, // This must only be used in Thread::SysSweepThreadsForDebug
+ SUSPEND_FOR_PROFILER = 8
} SUSPEND_REASON;
private: