}
//---------------------------------------------------------------------------
-// %%Function: ExternalShutdownHelper
-//
-// Parameters:
-// int exitCode :: process exit code
-// ShutdownCompleteAction sca :: indicates whether ::ExitProcess() is
-// called or if the function returns.
-//
-// Returns:
-// Nothing
-//
-// Description:
-// This is a helper shared by CorExitProcess and ShutdownRuntimeWithoutExiting
-// which causes the runtime to shutdown after the appropriate checks.
-// ---------------------------------------------------------------------------
-static void ExternalShutdownHelper(int exitCode, ShutdownCompleteAction sca)
-{
- CONTRACTL {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- ENTRY_POINT;
- } CONTRACTL_END;
-
- CONTRACT_VIOLATION(GCViolation | ModeViolation);
-
- if (g_fEEShutDown || !g_fEEStarted)
- return;
-
- if (!CanRunManagedCode())
- {
- return;
- }
-
- // The exit code for the process is communicated in one of two ways. If the
- // entrypoint returns an 'int' we take that. Otherwise we take a latched
- // process exit code. This can be modified by the app via System.SetExitCode().
- SetLatchedExitCode(exitCode);
-
-
- ForceEEShutdown(sca);
-
- // @TODO: If we cannot run ManagedCode, BEGIN_EXTERNAL_ENTRYPOINT will skip
- // the shutdown. We could call ::ExitProcess in that failure case, but that
- // would violate our hosting agreement. We are supposed to go through EEPolicy::
- // HandleExitProcess(). Is this legal if !CanRunManagedCode()?
-
-}
-
-//---------------------------------------------------------------------------
-// %%Function: void STDMETHODCALLTYPE CorExitProcess(int exitCode)
-//
-// Parameters:
-// int exitCode :: process exit code
-//
-// Returns:
-// Nothing
-//
-// Description:
-// COM Objects shutdown stuff should be done here
-// ---------------------------------------------------------------------------
-extern "C" void STDMETHODCALLTYPE CorExitProcess(int exitCode)
-{
- WRAPPER_NO_CONTRACT;
-
- ExternalShutdownHelper(exitCode, SCA_ExitProcessWhenShutdownComplete);
-}
-
-//---------------------------------------------------------------------------
-// %%Function: ShutdownRuntimeWithoutExiting
-//
-// Parameters:
-// int exitCode :: process exit code
-//
-// Returns:
-// Nothing
-//
-// Description:
-// This is a helper used only by the v4+ Shim to shutdown this runtime and
-// and return when the work has completed. It is exposed to the Shim via
-// GetCLRFunction.
-// ---------------------------------------------------------------------------
-void ShutdownRuntimeWithoutExiting(int exitCode)
-{
- WRAPPER_NO_CONTRACT;
-
- ExternalShutdownHelper(exitCode, SCA_ReturnWhenShutdownComplete);
-}
-
-//---------------------------------------------------------------------------
// %%Function: IsRuntimeStarted
//
// Parameters:
//
// Description: Indicates if the runtime is active or not. "Active" implies
// that the runtime has started and is in a position to run
-// managed code. If either of these conditions are false, the
-// function return FALSE.
-//
-// Why couldnt we add !g_fEEStarted check in CanRunManagedCode?
-//
-//
-// ExecuteDLL in ceemain.cpp could start the runtime
-// (due to DLL_PROCESS_ATTACH) after invoking CanRunManagedCode.
-// If the function were to be modified, then this scenario could fail.
-// Hence, I have built over CanRunManagedCode in IsRuntimeActive.
-
+// managed code.
// ---------------------------------------------------------------------------
BOOL IsRuntimeActive()
{
- // If the runtime has started AND we can run managed code,
- // then runtime is considered "active".
- BOOL fCanRunManagedCode = CanRunManagedCode();
- return (g_fEEStarted && fCanRunManagedCode);
-}
-
-// ---------------------------------------------------------------------------
-// %%Function: CanRunManagedCode()
-//
-// Parameters:
-// none
-//
-// Returns:
-// true or false
-//
-// Description: Indicates if one is currently allowed to run managed code.
-// ---------------------------------------------------------------------------
-NOINLINE BOOL CanRunManagedCodeRare(LoaderLockCheck::kind checkKind, HINSTANCE hInst /*= 0*/)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- } CONTRACTL_END;
-
- // If we are shutting down the runtime, then we cannot run code.
- if (g_fForbidEnterEE)
- return FALSE;
-
- // If pre-loaded objects are not present, then no way.
- if (g_pPreallocatedOutOfMemoryException == NULL)
- return FALSE;
-
- // If we are finaling live objects or processing ExitProcess event,
- // we can not allow managed method to run unless the current thread
- // is the finalizer thread
- if ((g_fEEShutDown & ShutDown_Finalize2) && !FinalizerThread::IsCurrentThreadFinalizer())
- return FALSE;
-
- return TRUE;
-}
-
-#include <optsmallperfcritical.h>
-BOOL CanRunManagedCode(LoaderLockCheck::kind checkKind, HINSTANCE hInst /*= 0*/)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- } CONTRACTL_END;
-
- // Special-case the common success cases
- // (Try not to make any calls here so that we don't have to spill our incoming arg regs)
- if (!g_fForbidEnterEE
- && (g_pPreallocatedOutOfMemoryException != NULL)
- && !(g_fEEShutDown & ShutDown_Finalize2)
- && ((checkKind == LoaderLockCheck::None)))
- {
- return TRUE;
- }
-
- // Then call a helper for everything else.
- return CanRunManagedCodeRare(checkKind, hInst);
+ return (g_fEEStarted);
}
-#include <optdefault.h>
//*****************************************************************************
BOOL ExecuteDLL_ReturnOrThrow(HRESULT hr, BOOL fFromThunk)
// outside unmanaged code. If you want to connect internal pieces
// of CLR code, use EX_TRY instead.
//===================================================================================
-#define BEGIN_EXTERNAL_ENTRYPOINT(phresult) \
- { \
- HRESULT *__phr = (phresult); \
- *__phr = S_OK; \
- _ASSERTE(GetThread() == NULL || \
- !GetThread()->PreemptiveGCDisabled()); \
- if (!CanRunManagedCode()) \
- { \
- *__phr = E_PROCESS_SHUTDOWN_REENTRY; \
- } \
- else \
- { \
- MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \
- if (CURRENT_THREAD == NULL) \
- { \
- CURRENT_THREAD = SetupThreadNoThrow(__phr); \
- } \
- if (CURRENT_THREAD != NULL) \
- { \
- EX_TRY_THREAD(CURRENT_THREAD); \
- { \
-
-#define END_EXTERNAL_ENTRYPOINT \
- } \
- EX_CATCH_HRESULT(*__phr); \
- } \
- } \
- } \
+#define BEGIN_EXTERNAL_ENTRYPOINT(phresult) \
+ { \
+ HRESULT *__phr = (phresult); \
+ *__phr = S_OK; \
+ _ASSERTE(GetThread() == NULL || \
+ !GetThread()->PreemptiveGCDisabled()); \
+ MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \
+ if (CURRENT_THREAD == NULL) \
+ { \
+ CURRENT_THREAD = SetupThreadNoThrow(__phr); \
+ } \
+ if (CURRENT_THREAD != NULL) \
+ { \
+ EX_TRY_THREAD(CURRENT_THREAD); \
+ { \
+
+#define END_EXTERNAL_ENTRYPOINT \
+ } \
+ EX_CATCH_HRESULT(*__phr); \
+ } \
+ } \
// This macro should be used at the entry points (e.g. COM interop boundaries)
// where CE's are not expected to get swallowed.
#define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(fCond) \
- } \
- EX_CATCH \
- { \
- *__phr = GET_EXCEPTION()->GetHR(); \
- } \
- EX_END_CATCH(RethrowCorruptingExceptionsEx(fCond)); \
- } \
- } \
- } \
+ } \
+ EX_CATCH \
+ { \
+ *__phr = GET_EXCEPTION()->GetHR(); \
+ } \
+ EX_END_CATCH(RethrowCorruptingExceptionsEx(fCond)); \
+ } \
+ } \
// This macro should be used at the entry points (e.g. COM interop boundaries)
// where CE's are not expected to get swallowed.
OBJECTREF pThrowable = NULL;
- if (!CanRunManagedCode())
+ Thread* pThread = SetupThreadNoThrow();
+ if (pThread == NULL)
{
- hr = E_PROCESS_SHUTDOWN_REENTRY;
+ hr = E_OUTOFMEMORY;
}
else
{
- Thread* pThread = SetupThreadNoThrow();
- if (pThread == NULL)
- {
- hr = E_OUTOFMEMORY;
- }
- else
- {
- // Transition to cooperative GC mode before we start setting up the stub.
- GCX_COOP();
+ // Transition to cooperative GC mode before we start setting up the stub.
+ GCX_COOP();
- // The PreStub allocates memory for the frame, but doesn't link it
- // into the chain or fully initialize it. Do so now.
- pPFrame->Init();
- pPFrame->Push();
+ // The PreStub allocates memory for the frame, but doesn't link it
+ // into the chain or fully initialize it. Do so now.
+ pPFrame->Init();
+ pPFrame->Push();
- ComCallWrapper *pWrap = NULL;
+ ComCallWrapper *pWrap = NULL;
- GCPROTECT_BEGIN(pThrowable)
+ GCPROTECT_BEGIN(pThrowable)
+ {
+ // We need a try/catch around the code to enter the domain since entering
+ // an AppDomain can throw an exception.
+ EX_TRY
{
- // We need a try/catch around the code to enter the domain since entering
- // an AppDomain can throw an exception.
- EX_TRY
- {
- // check for invalid wrappers in the debug build
- // in the retail all bets are off
- pWrap = ComCallWrapper::GetWrapperFromIP(pUnk);
- _ASSERTE(pWrap->IsWrapperActive() || pWrap->IsAggregated());
-
- // Make sure we're not trying to call on the class interface of a class with ComVisible(false) members
- // in its hierarchy.
- if ((pCMD->IsFieldCall()) || (NULL == pCMD->GetInterfaceMethodDesc() && !pCMD->GetMethodDesc()->IsInterface()))
- {
- // If we have a fieldcall or a null interface MD, we could be dealing with the IClassX interface.
- ComMethodTable* pComMT = ComMethodTable::ComMethodTableFromIP(pUnk);
- pComMT->CheckParentComVisibility(FALSE);
- }
-
- {
- OBJECTREF pADThrowable = NULL;
+ // check for invalid wrappers in the debug build
+ // in the retail all bets are off
+ pWrap = ComCallWrapper::GetWrapperFromIP(pUnk);
+ _ASSERTE(pWrap->IsWrapperActive() || pWrap->IsAggregated());
+
+ // Make sure we're not trying to call on the class interface of a class with ComVisible(false) members
+ // in its hierarchy.
+ if ((pCMD->IsFieldCall()) || (NULL == pCMD->GetInterfaceMethodDesc() && !pCMD->GetMethodDesc()->IsInterface()))
+ {
+ // If we have a fieldcall or a null interface MD, we could be dealing with the IClassX interface.
+ ComMethodTable* pComMT = ComMethodTable::ComMethodTableFromIP(pUnk);
+ pComMT->CheckParentComVisibility(FALSE);
+ }
- BOOL fExceptionThrown = FALSE;
+ {
+ OBJECTREF pADThrowable = NULL;
- GCPROTECT_BEGIN(pADThrowable);
+ BOOL fExceptionThrown = FALSE;
+
+ GCPROTECT_BEGIN(pADThrowable);
+ {
+ if (pCMD->IsMethodCall())
{
- if (pCMD->IsMethodCall())
+ // We need to ensure all valuetypes are loaded in
+ // the target domain so that GC can happen later
+
+ EX_TRY
{
- // We need to ensure all valuetypes are loaded in
- // the target domain so that GC can happen later
-
- EX_TRY
- {
- MethodDesc* pTargetMD = pCMD->GetMethodDesc();
- MetaSig::EnsureSigValueTypesLoaded(pTargetMD);
-
- if (pCMD->IsWinRTCtor() || pCMD->IsWinRTStatic() || pCMD->IsWinRTRedirectedMethod())
- {
- // Activation, static method invocation, and call through a redirected interface may be the first
- // managed code that runs in the module. Fully load it here so we don't have to call EnsureInstanceActive
- // on every activation/static call.
- pTargetMD->GetMethodTable()->EnsureInstanceActive();
- }
- }
- EX_CATCH
+ MethodDesc* pTargetMD = pCMD->GetMethodDesc();
+ MetaSig::EnsureSigValueTypesLoaded(pTargetMD);
+
+ if (pCMD->IsWinRTCtor() || pCMD->IsWinRTStatic() || pCMD->IsWinRTRedirectedMethod())
{
- pADThrowable = GET_THROWABLE();
+ // Activation, static method invocation, and call through a redirected interface may be the first
+ // managed code that runs in the module. Fully load it here so we don't have to call EnsureInstanceActive
+ // on every activation/static call.
+ pTargetMD->GetMethodTable()->EnsureInstanceActive();
}
- EX_END_CATCH(RethrowTerminalExceptions);
}
+ EX_CATCH
+ {
+ pADThrowable = GET_THROWABLE();
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+ }
+
+ if (pADThrowable != NULL)
+ {
+ // Transform the exception into an HRESULT. This also sets up
+ // an IErrorInfo on the current thread for the exception.
+ hr = SetupErrorInfo(pADThrowable, pCMD);
+ pADThrowable = NULL;
+ fExceptionThrown = TRUE;
+ }
+ }
+ GCPROTECT_END();
+
+ if(!fExceptionThrown)
+ {
+ GCPROTECT_BEGIN(pADThrowable);
+ {
+ // We need a try/catch around the call to the worker since we need
+ // to transform any exceptions into HRESULTs. We want to do this
+ // inside the AppDomain of the CCW.
+ EX_TRY
+ {
+ GCX_PREEMP();
+ pStub = ComCall::GetComCallMethodStub(pCMD);
+ }
+ EX_CATCH
+ {
+ fNonTransientExceptionThrown = !GET_EXCEPTION()->IsTransient();
+ pADThrowable = GET_THROWABLE();
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
if (pADThrowable != NULL)
{
// an IErrorInfo on the current thread for the exception.
hr = SetupErrorInfo(pADThrowable, pCMD);
pADThrowable = NULL;
- fExceptionThrown = TRUE;
}
}
GCPROTECT_END();
-
- if(!fExceptionThrown)
- {
- GCPROTECT_BEGIN(pADThrowable);
- {
- // We need a try/catch around the call to the worker since we need
- // to transform any exceptions into HRESULTs. We want to do this
- // inside the AppDomain of the CCW.
- EX_TRY
- {
- GCX_PREEMP();
- pStub = ComCall::GetComCallMethodStub(pCMD);
- }
- EX_CATCH
- {
- fNonTransientExceptionThrown = !GET_EXCEPTION()->IsTransient();
- pADThrowable = GET_THROWABLE();
- }
- EX_END_CATCH(RethrowTerminalExceptions);
-
- if (pADThrowable != NULL)
- {
- // Transform the exception into an HRESULT. This also sets up
- // an IErrorInfo on the current thread for the exception.
- hr = SetupErrorInfo(pADThrowable, pCMD);
- pADThrowable = NULL;
- }
- }
- GCPROTECT_END();
- }
}
}
- EX_CATCH
- {
- pThrowable = GET_THROWABLE();
-
- // If an exception was thrown while transitionning back to the original
- // AppDomain then can't use the stub and must report an error.
- pStub = NULL;
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- if (pThrowable != NULL)
- {
- // Transform the exception into an HRESULT. This also sets up
- // an IErrorInfo on the current thread for the exception.
- hr = SetupErrorInfo(pThrowable, pCMD);
- pThrowable = NULL;
- }
}
- GCPROTECT_END();
+ EX_CATCH
+ {
+ pThrowable = GET_THROWABLE();
- // Unlink the PrestubMethodFrame.
- pPFrame->Pop();
+ // If an exception was thrown while transitionning back to the original
+ // AppDomain then can't use the stub and must report an error.
+ pStub = NULL;
+ }
+ EX_END_CATCH(SwallowAllExceptions);
- if (pStub)
+ if (pThrowable != NULL)
{
- // Now, replace the prestub with the new stub.
- static_assert((COMMETHOD_CALL_PRESTUB_SIZE - COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET) % DATA_ALIGNMENT == 0,
- "The call target in COM prestub must be aligned so we can guarantee atomicity of updates");
+ // Transform the exception into an HRESULT. This also sets up
+ // an IErrorInfo on the current thread for the exception.
+ hr = SetupErrorInfo(pThrowable, pCMD);
+ pThrowable = NULL;
+ }
+ }
+ GCPROTECT_END();
+
+ // Unlink the PrestubMethodFrame.
+ pPFrame->Pop();
+
+ if (pStub)
+ {
+ // Now, replace the prestub with the new stub.
+ static_assert((COMMETHOD_CALL_PRESTUB_SIZE - COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET) % DATA_ALIGNMENT == 0,
+ "The call target in COM prestub must be aligned so we can guarantee atomicity of updates");
+
+ UINT_PTR* ppofs = (UINT_PTR*) (((BYTE*)pCMD) - COMMETHOD_CALL_PRESTUB_SIZE + COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET);
- UINT_PTR* ppofs = (UINT_PTR*) (((BYTE*)pCMD) - COMMETHOD_CALL_PRESTUB_SIZE + COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET);
-
- *ppofs = ((UINT_PTR)pStub
#ifdef _TARGET_X86_
- - (size_t)pCMD
+ *ppofs = ((UINT_PTR)pStub - (size_t)pCMD);
+#else
+ *ppofs = ((UINT_PTR)pStub);
#endif
- );
- // Return the address of the prepad. The prepad will regenerate the hidden parameter and due
- // to the update above will execute the new stub code the second time around.
- retAddr = (PCODE)(((BYTE*)pCMD - COMMETHOD_CALL_PRESTUB_SIZE)ARM_ONLY(+THUMB_CODE));
+ // Return the address of the prepad. The prepad will regenerate the hidden parameter and due
+ // to the update above will execute the new stub code the second time around.
+ retAddr = (PCODE)(((BYTE*)pCMD - COMMETHOD_CALL_PRESTUB_SIZE)ARM_ONLY(+THUMB_CODE));
- goto Exit;
- }
+ goto Exit;
}
}
}
CONTRACTL_END;
- SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode();
+ SetupForComCallHR();
// we can safely assume that the CCW is still alive since this is an AddRef
StackSString ssMessage;
}
CONTRACTL_END;
- if (!CanRunManagedCode())
- return;
-
m_pWrap->Cleanup();
}
public:
// dangerous mode. If we call managed code, we will potentially be active in
// the GC heap, even as GC's are occuring!
- // Check for ShutDown scenario. This happens only when we have initiated shutdown
- // and someone is trying to call in after the CLR is suspended. In that case, we
- // must either raise an unmanaged exception or return an HRESULT, depending on the
- // expectations of our caller.
- if (!CanRunManagedCode())
+ // We must do the following in this order, because otherwise we would be constructing
+ // the exception for the abort without synchronizing with the GC. Also, we have no
+ // CLR SEH set up, despite the fact that we may throw a ThreadAbortException.
+ pThread->RareDisablePreemptiveGC();
+ EX_TRY
{
- hr = E_PROCESS_SHUTDOWN_REENTRY;
+ pThread->HandleThreadAbort();
}
- else
+ EX_CATCH
{
- // We must do the following in this order, because otherwise we would be constructing
- // the exception for the abort without synchronizing with the GC. Also, we have no
- // CLR SEH set up, despite the fact that we may throw a ThreadAbortException.
- pThread->RareDisablePreemptiveGC();
- EX_TRY
- {
- pThread->HandleThreadAbort();
- }
- EX_CATCH
- {
- hr = GET_EXCEPTION()->GetHR();
- }
- EX_END_CATCH(SwallowAllExceptions);
+ hr = GET_EXCEPTION()->GetHR();
}
+ EX_END_CATCH(SwallowAllExceptions);
// should always be in coop mode here
_ASSERTE(pThread->PreemptiveGCDisabled());
CONTRACTL_END;
// No point going further if the runtime is not running...
- // We use CanRunManagedCode() instead of IsRuntimeActive() because this allows us
- // to specify test using the form that does not trigger a GC.
- if (!(g_fEEStarted && CanRunManagedCode(LoaderLockCheck::None)))
+ if (!IsRuntimeActive())
{
return HOST_E_CLRNOTAVAILABLE;
}
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
- // Do not add a CONTRACT here. We haven't set up SEH. We rely
- // on HandleThreadAbort and COMPlusThrowBoot dealing with this situation properly.
+ // Do not add a CONTRACT here. We haven't set up SEH.
// WARNING!!!!
// when we start executing here, we are actually in cooperative mode. But we
// dangerous mode. If we call managed code, we will potentially be active in
// the GC heap, even as GC's are occuring!
- // Check for ShutDown scenario. This happens only when we have initiated shutdown
- // and someone is trying to call in after the CLR is suspended. In that case, we
- // must either raise an unmanaged exception or return an HRESULT, depending on the
- // expectations of our caller.
- if (!CanRunManagedCode())
- {
- // DO NOT IMPROVE THIS EXCEPTION! It cannot be a managed exception. It
- // cannot be a real exception object because we cannot execute any managed
- // code here.
- pThread->m_fPreemptiveGCDisabled = 0;
- COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY);
- }
-
// We must do the following in this order, because otherwise we would be constructing
// the exception for the abort without synchronizing with the GC. Also, we have no
// CLR SEH set up, despite the fact that we may throw a ThreadAbortException.
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_MODE_PREEMPTIVE;
- if (!CanRunManagedCode())
- COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY);
-
Thread * pThread = GetThreadNULLOk();
if (pThread == NULL)
pThread = CreateThreadBlockThrow();
VOID SetManagedUnhandledExceptionBit(
BOOL useLastThrownObject);
-
-void COMPlusThrowBoot(HRESULT hr)
-{
- STATIC_CONTRACT_THROWS;
-
- _ASSERTE(g_fEEShutDown >= ShutDown_Finalize2 || !"This should not be called unless we are in the last phase of shutdown!");
- ULONG_PTR arg = hr;
- RaiseException(BOOTUP_EXCEPTION_COMPLUS, EXCEPTION_NONCONTINUABLE, 1, &arg);
-}
-
-
//-------------------------------------------------------------------------------
// This simply tests to see if the exception object is a subclass of
// the descriminating class specified in the exception clause.
PrintToStdErrA(" StackOverflowException.\n");
}
}
- else if (!CanRunManagedCode(LoaderLockCheck::None))
- {
- // Well, if we can't enter the runtime, we very well can't get the exception message.
- dump = FALSE;
- }
else if (SentEvent || IsAsyncThreadException(&throwable))
{
// We don't print anything on async exceptions, like ThreadAbort.
#endif
GCPROTECT_BEGIN(throwable);
- //BOOL IsStackOverflow = (throwable->GetMethodTable() == g_pStackOverflowExceptionClass);
// Notify the AppDomain that we have taken an unhandled exception. Can't notify of stack overflow -- guard
// page is not yet reset.
// Send up the unhandled exception appdomain event.
- //
- // If we can't run managed code, we can't deliver the event. Nor do we attempt to delieve the event in stack
- // overflow or OOM conditions.
- if (/*!IsStackOverflow &&*/
- pThread->DetermineIfGuardPagePresent() &&
- CanRunManagedCode(LoaderLockCheck::None))
+ if (pThread->DetermineIfGuardPagePresent())
{
-
// x86 only
#if !defined(WIN64EXCEPTIONS)
// If the Thread object's exception state's exception pointers
// This is a workaround designed to allow the use of the StubLinker object at bootup
// time where the EE isn't sufficient awake to create COM+ exception objects.
// Instead, COMPlusThrow(rexcep) does a simple RaiseException using this code.
-// Or use COMPlusThrowBoot() to explicitly do so.
//==========================================================================
#define BOOTUP_EXCEPTION_COMPLUS 0xC0020001
-void COMPlusThrowBoot(HRESULT hr);
-
-
//==========================================================================
// Used by the classloader to record a managed exception object to explain
// why a classload got botched.
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
- // Do not add a CONTRACT here. We haven't set up SEH. We rely
- // on HandleThreadAbort and COMPlusThrowBoot dealing with this situation properly.
+ // Do not add a CONTRACT here. We haven't set up SEH.
// WARNING!!!!
// when we start executing here, we are actually in cooperative mode. But we
// dangerous mode. If we call managed code, we will potentially be active in
// the GC heap, even as GC's are occuring!
- // Check for ShutDown scenario. This happens only when we have initiated shutdown
- // and someone is trying to call in after the CLR is suspended. In that case, we
- // must either raise an unmanaged exception or return an HRESULT, depending on the
- // expectations of our caller.
- if (!CanRunManagedCode())
- {
- // DO NOT IMPROVE THIS EXCEPTION! It cannot be a managed exception. It
- // cannot be a real exception object because we cannot execute any managed
- // code here.
- pThread->m_fPreemptiveGCDisabled = 0;
- COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY);
- }
-
// We must do the following in this order, because otherwise we would be constructing
// the exception for the abort without synchronizing with the GC. Also, we have no
// CLR SEH set up, despite the fact that we may throw a ThreadAbortException.
// RuntimeExceptionKind.h
//
-//
-
-
#ifndef __runtimeexceptionkind_h__
#define __runtimeexceptionkind_h__
kLastException
};
-
-// I would have preferred to define a unique HRESULT in our own facility, but we
-// weren't supposed to create new HRESULTs so close to ship. And now it's set
-// in stone.
-#define E_PROCESS_SHUTDOWN_REENTRY HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED)
-
-
#endif // __runtimeexceptionkind_h__
HRESULT __stdcall Unknown_QueryInterface_IErrorInfo(IUnknown* pUnk, REFIID riid, void** ppv)
{
- // Special version of SetupForComCallHR that doesn't call
- // CanRunManagedCode() to avoid firing LoaderLock MDA
- SetupForComCallHRNoCheckCanRunManagedCode();
+ SetupForComCallHR();
WRAPPER_NO_CONTRACT;
- HRESULT hr = S_OK;
- if (!CanRunManagedCode(LoaderLockCheck::ForCorrectness))
- {
- // if we cannot run managed code, do a very simple QI which responds only to IUnknown and IErrorInfo
- hr = Unknown_QueryInterface_IErrorInfo_Simple(pUnk, riid, ppv);
-
- if (hr == E_NOINTERFACE)
- {
- hr = HOST_E_CLRNOTAVAILABLE;
- }
- }
-
// otherwise do a regular QI
return Unknown_QueryInterface(pUnk, riid, ppv);
}
// ---------------------------------------------------------------------------
ULONG __stdcall Unknown_ReleaseSpecial_IErrorInfo(IUnknown* pUnk)
{
- // Special version of SetupForComCallDWORD that doesn't call
- // CanRunManagedCode() to avoid firing LoaderLock MDA
- // No managed code will be executed in this function
- SetupForComCallDWORDNoCheckCanRunManagedCode();
+ SetupForComCallDWORD();
WRAPPER_NO_CONTRACT;
- // <TODO>Address this violation in context of bug 27409</TODO>
CONTRACT_VIOLATION(GCViolation);
- if (!CanRunManagedCode(LoaderLockCheck::None))
- {
- // CCW cleanup doesn't run managed code but may trigger operations such as
- // switching the thread to cooperative mode which is not safe during shutdown.
- return 0;
- }
- else
- {
- // Don't switch domains since we need to allow release calls to go through
- // even after the AD has been unlaoded. Furthermore release doesn't require
- // us to transition into the domain to work properly.
- return Unknown_ReleaseSpecial_IErrorInfo_Internal(pUnk);
- }
+ // Don't switch domains since we need to allow release calls to go through
+ // even after the AD has been unlaoded. Furthermore release doesn't require
+ // us to transition into the domain to work properly.
+ return Unknown_ReleaseSpecial_IErrorInfo_Internal(pUnk);
}
{
HRESULT hrRetVal = S_OK;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- BeginSetupForComCallHRWithEscapingCorruptingExceptions();
-#else // !FEATURE_CORRUPTING_EXCEPTIONS
SetupForComCallHR();
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
CONTRACTL
{
InvokeArgs args = {pDisp, dispidMember, &riid, lcid, wFlags, pdispparams,
pvarResult, pexcepinfo, puArgErr, &hrRetVal};
- Dispatch_Invoke_CallBack(&args);
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- EndSetupForComCallHRWithEscapingCorruptingExceptions();
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ Dispatch_Invoke_CallBack(&args);
return hrRetVal;
}
ULONG __stdcall ICCW_AddRefFromJupiter_Wrapper(IUnknown *pUnk)
{
- // We do not need to hook with host here
- SetupForComCallDWORDNoHostNotif();
+ SetupForComCallDWORD();
WRAPPER_NO_CONTRACT;
ULONG __stdcall ICCW_ReleaseFromJupiter_Wrapper(IUnknown *pUnk)
{
- // We do not need to hook with host here
- SetupForComCallDWORDNoHostNotif();
+ SetupForComCallDWORD();
WRAPPER_NO_CONTRACT;
HRESULT __stdcall ICCW_Peg_Wrapper(IUnknown *pUnk)
{
- // We do not need to hook with host here and we cannot do CanRunManagedCode check
- // as we are most likely in the middle of a GC
- SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode();
-
+ SetupForComCallHR();
WRAPPER_NO_CONTRACT;
return ICCW_Peg(pUnk);
HRESULT __stdcall ICCW_Unpeg_Wrapper(IUnknown *pUnk)
{
- // We do not need to hook with host here and we cannot do CanRunManagedCode check
- // as we are most likely in the middle of a GC
- SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode();
-
+ SetupForComCallHR();
WRAPPER_NO_CONTRACT;
return ICCW_Unpeg(pUnk);
Thread* pThread = NULL;
BEGIN_ENTRYPOINT_THROWS;
- if (!CanRunManagedCode())
- {
- // CLR is shutting down - someone's DllMain detach event may be calling back into managed code.
- // It is misleading to use our COM+ exception code, since this is not a managed exception.
- ULONG_PTR arg = E_PROCESS_SHUTDOWN_REENTRY;
- RaiseException(EXCEPTION_EXX, 0, 1, &arg);
- }
-
HRESULT hr = S_OK;
pThread = SetupThreadNoThrow(&hr);
if (pThread == NULL)
// since fundamental parts of the system (such as the GC) rely on non alertable
// waits not running any managed code. Also if we are past the point in shutdown were we
// are allowed to run managed code then we can't forward the call to the sync context.
- if (!ignoreSyncCtx && alertable && CanRunManagedCode(LoaderLockCheck::None)
+ if (!ignoreSyncCtx
+ && alertable
&& !HasThreadStateNC(Thread::TSNC_BlockedForShutdown))
{
GCX_COOP();
LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes);
BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem);
-void ShutdownRuntimeWithoutExiting(int exitCode);
BOOL IsRuntimeStarted(DWORD *pdwStartupFlags);
void *GetCLRFunction(LPCSTR FunctionName)
{
func = (void*)EEHeapFreeInProcessHeap;
}
- else if (strcmp(FunctionName, "ShutdownRuntimeWithoutExiting") == 0)
- {
- func = (void*)ShutdownRuntimeWithoutExiting;
- }
else if (strcmp(FunctionName, "IsRuntimeStarted") == 0)
{
func = (void*)IsRuntimeStarted;
return OOMRetVal; \
} \
-
-#define InternalSetupForComCall(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \
-SetupThreadForComCall(OOMRetVal); \
-if (CheckCanRunManagedCode && !CanRunManagedCode()) \
- return CannotEnterRetVal;
-
-#define SetupForComCallHRNoHostNotif() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true)
-#define SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false)
-#define SetupForComCallDWORDNoHostNotif() InternalSetupForComCall(-1, -1, -1, true)
-
-#define SetupForComCallHR() \
-InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true)
-
-#define SetupForComCallHRNoCheckCanRunManagedCode() \
-InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false)
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-
-// Since Corrupting exceptions can escape COM interop boundaries,
-// these macros will be used to setup the initial SO-Intolerant transition.
-#define InternalSetupForComCallWithEscapingCorruptingExceptions(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \
-if (CheckCanRunManagedCode && !CanRunManagedCode()) \
- return CannotEnterRetVal; \
-SetupThreadForComCall(OOMRetVal); \
-
-#define BeginSetupForComCallHRWithEscapingCorruptingExceptions() \
-HRESULT __hr = S_OK; \
-InternalSetupForComCallWithEscapingCorruptingExceptions(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true) \
- \
-if (SUCCEEDED(__hr)) \
-{ \
-
-#define EndSetupForComCallHRWithEscapingCorruptingExceptions() \
-} \
- \
-if (FAILED(__hr)) \
-{ \
- return __hr; \
-} \
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
-#define SetupForComCallDWORD() \
-InternalSetupForComCall(-1, -1, -1, true)
-
-// Special version of SetupForComCallDWORD that doesn't call
-// CanRunManagedCode() to avoid firing LoaderLock MDA
-#define SetupForComCallDWORDNoCheckCanRunManagedCode() \
-InternalSetupForComCall(-1, -1, -1, false)
+#define SetupForComCallHR() SetupThreadForComCall(E_OUTOFMEMORY)
+#define SetupForComCallDWORD() SetupThreadForComCall(ERROR_OUTOFMEMORY)
// A holder for NATIVE_LIBRARY_HANDLE.
FORCEINLINE void VoidFreeNativeLibrary(NATIVE_LIBRARY_HANDLE h)
BOOL IsRuntimeActive();
//
-// Can we run managed code?
-//
-struct LoaderLockCheck
-{
- enum kind
- {
- ForMDA,
- ForCorrectness,
- None,
- };
-};
-BOOL CanRunManagedCode(LoaderLockCheck::kind checkKind, HINSTANCE hInst = 0);
-inline BOOL CanRunManagedCode(HINSTANCE hInst = 0)
-{
- return CanRunManagedCode(LoaderLockCheck::ForMDA, hInst);
-}
-
-//
// Global state variable indicating if the EE is in its init phase.
//
EXTERN bool g_fEEInit;