From 54891e0650e69f08832f75a40dc102efc6115d38 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Fri, 10 Feb 2017 17:12:53 -0800 Subject: Remove always defined FEATURE_CORECLR --- src/vm/corhost.cpp | 5999 +++++++++++----------------------------------------- 1 file changed, 1276 insertions(+), 4723 deletions(-) (limited to 'src/vm/corhost.cpp') diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp index e00482168d..c71c2f9879 100644 --- a/src/vm/corhost.cpp +++ b/src/vm/corhost.cpp @@ -89,5043 +89,1822 @@ extern BOOL g_fEEHostedStartup; INT64 g_PauseTime; // Total time in millisecond the CLR has been paused Volatile g_IsPaused; // True if the runtime is paused (FAS) CLREventStatic g_ClrResumeEvent; // Event that is fired at FAS Resuming -#ifndef FEATURE_CORECLR -CLREventStatic g_PauseCompletedEvent; // Set when Pause has completed its work on another thread. -#endif -#if defined(FEATURE_CORECLR) extern BYTE g_rbTestKeyBuffer[]; -#endif - -#if !defined(FEATURE_CORECLR) -//****************************************************************************** -// TODO: ICorThreadpool: Move this into a separate file CorThreadpool.cpp -// after the move to VBL -//****************************************************************************** - -HRESULT STDMETHODCALLTYPE CorThreadpool::CorRegisterWaitForSingleObject(PHANDLE phNewWaitObject, - HANDLE hWaitObject, - WAITORTIMERCALLBACK Callback, - PVOID Context, - ULONG timeout, - BOOL executeOnlyOnce, - BOOL* pResult) -{ - CONTRACTL - { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; - } - CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; +//*************************************************************************** - BEGIN_ENTRYPOINT_NOTHROW; +ULONG CorRuntimeHostBase::m_Version = 0; - ULONG flag = executeOnlyOnce ? WAIT_SINGLE_EXECUTION : 0; - *pResult = FALSE; - EX_TRY - { - *pResult = ThreadpoolMgr::RegisterWaitForSingleObject(phNewWaitObject, - hWaitObject, - Callback, - Context, - timeout, - flag); +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +static CCLRDebugManager s_CLRDebugManager; +#endif // FEATURE_INCLUDE_ALL_INTERFACES - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); +#if defined(FEATURE_INCLUDE_ALL_INTERFACES) || defined(FEATURE_WINDOWSPHONE) +CCLRErrorReportingManager g_CLRErrorReportingManager; +#endif // defined(FEATURE_INCLUDE_ALL_INTERFACES) || defined(FEATURE_WINDOWSPHONE) - END_ENTRYPOINT_NOTHROW; +#ifdef FEATURE_IPCMAN +static CCLRSecurityAttributeManager s_CLRSecurityAttributeManager; +#endif // FEATURE_IPCMAN - return hr; -} +#endif // !DAC +typedef DPTR(CONNID) PTR_CONNID; -HRESULT STDMETHODCALLTYPE CorThreadpool::CorBindIoCompletionCallback(HANDLE fileHandle, - LPOVERLAPPED_COMPLETION_ROUTINE callback) +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +// Hash table to keep track for SQL fiber support +class ConnectionNameTable : CHashTableAndData { - CONTRACTL + friend class CCLRDebugManager; +public: + + // Key to match is connection ID. + // Returns true if the given HASHENTRY has the same key as the requested key. + BOOL Cmp(SIZE_T requestedKey, const HASHENTRY * pEntry) { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; + SUPPORTS_DAC; + LIMITED_METHOD_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + + CONNID keyRequested = (CONNID)requestedKey; + CONNID keySearch = dac_cast(pEntry)->m_dwConnectionId; + return keyRequested != keySearch; } - CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; + // Hash function + ULONG Hash(CONNID dwConnectionId) + { + SUPPORTS_DAC; + LIMITED_METHOD_CONTRACT; + + return (ULONG)(dwConnectionId); + } - BOOL ret = FALSE; - DWORD errCode = 0; +#ifndef DACCESS_COMPILE + // constructor + ConnectionNameTable( + ULONG iBuckets) : // # of chains we are hashing into. + CHashTableAndData(iBuckets) + {LIMITED_METHOD_CONTRACT;} - EX_TRY + // destructor + ~ConnectionNameTable() { - ret = ThreadpoolMgr::BindIoCompletionCallback(fileHandle,callback,0, errCode); - hr = (ret ? S_OK : HRESULT_FROM_WIN32(errCode)); + CONTRACTL + { + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + NOTHROW; + } + CONTRACTL_END; + HASHFIND hashFind; + ConnectionNameHashEntry *pNameEntry; + + pNameEntry = (ConnectionNameHashEntry *)FindFirstEntry(&hashFind); + while (pNameEntry != NULL) + { + if (pNameEntry->m_pwzName) + { + delete pNameEntry->m_pwzName; + pNameEntry->m_pwzName = NULL; + } + + if (pNameEntry->m_CLRTaskCount != 0) + { + _ASSERTE(pNameEntry->m_ppCLRTaskArray != NULL); + for (UINT i = 0; i < pNameEntry->m_CLRTaskCount; i++) + { + pNameEntry->m_ppCLRTaskArray[i]->Release(); + } + delete [] pNameEntry->m_ppCLRTaskArray; + pNameEntry->m_ppCLRTaskArray = NULL; + pNameEntry->m_CLRTaskCount = 0; + } + pNameEntry = (ConnectionNameHashEntry *)FindNextEntry(&hashFind); + } } - EX_CATCH + + // Add a new connection into hash table. + // This function does not throw but return NULL when memory allocation fails. + ConnectionNameHashEntry *AddConnection( + CONNID dwConnectionId, + __in_z WCHAR *pwzName) // We should review this in the future. This API is + // public and callable by a host. This SAL annotation + // is the best we can do now. { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); + CONTRACTL + { + GC_NOTRIGGER; + NOTHROW; + } + CONTRACTL_END; - END_ENTRYPOINT_NOTHROW; + ULONG iHash = Hash(dwConnectionId); - return hr; -} + size_t len = wcslen(pwzName) + 1; + WCHAR *pConnName = new (nothrow) WCHAR[len]; + if (pConnName == NULL) + return NULL; + ConnectionNameHashEntry *pRecord = (ConnectionNameHashEntry *)Add(iHash); + if (pRecord) + { + pRecord->m_dwConnectionId = dwConnectionId; + pRecord->m_pwzName = pConnName; + wcsncpy_s(pRecord->m_pwzName, len, pwzName, len); + pRecord->m_CLRTaskCount = 0; + pRecord->m_ppCLRTaskArray = NULL; + } + else + { + if (pConnName) + delete [] pConnName; + } -HRESULT STDMETHODCALLTYPE CorThreadpool::CorUnregisterWait(HANDLE hWaitObject, - HANDLE CompletionEvent, - BOOL* pResult) -{ - CONTRACTL - { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; + return pRecord; } - CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - - BEGIN_ENTRYPOINT_NOTHROW; - - *pResult = FALSE; - EX_TRY + // Delete a hash entry given a connection id + void DeleteConnection(CONNID dwConnectionId) { + CONTRACTL + { + GC_NOTRIGGER; + NOTHROW; + } + CONTRACTL_END; + + ULONG iHash; + iHash = Hash(dwConnectionId); + ConnectionNameHashEntry * pRecord = + reinterpret_cast(Find(iHash, (SIZE_T)dwConnectionId)); + if (pRecord == NULL) + { + return; + } - *pResult = ThreadpoolMgr::UnregisterWaitEx(hWaitObject,CompletionEvent); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); + _ASSERTE(pRecord->m_CLRTaskCount == 0 && pRecord->m_ppCLRTaskArray == NULL); + if (pRecord->m_pwzName) + { + delete pRecord->m_pwzName; + pRecord->m_pwzName = NULL; + } + Delete(iHash, (HASHENTRY *)pRecord); } - EX_CATCH + + // return NULL if the given connection id cannot be found. + ConnectionNameHashEntry *FindConnection(CONNID dwConnectionId) { - hr = GET_EXCEPTION()->GetHR(); + CONTRACTL + { + GC_NOTRIGGER; + NOTHROW; + } + CONTRACTL_END; + + ULONG iHash; + iHash = Hash(dwConnectionId); + return reinterpret_cast(Find(iHash, (SIZE_T)dwConnectionId)); } - EX_END_CATCH(SwallowAllExceptions); +#endif // !DAC +}; +#endif //FEATURE_INCLUDE_ALL_INTERFACES - END_ENTRYPOINT_NOTHROW; - return hr; +// Keep track connection id and name +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +SPTR_IMPL(ConnectionNameTable, CCLRDebugManager, m_pConnectionNameHash); +CrstStatic CCLRDebugManager::m_lockConnectionNameTable; +#endif // FEATURE_INCLUDE_ALL_INTERFACES -} +#ifndef DACCESS_COMPILE -HRESULT STDMETHODCALLTYPE CorThreadpool::CorQueueUserWorkItem(LPTHREAD_START_ROUTINE Function, - PVOID Context,BOOL executeOnlyOnce, - BOOL* pResult ) -{ - CONTRACTL - { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; - } - CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; - *pResult = FALSE; - EX_TRY - { - *pResult = ThreadpoolMgr::QueueUserWorkItem(Function,Context,QUEUE_ONLY); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - END_ENTRYPOINT_NOTHROW; - return hr; -} +// *** ICorRuntimeHost methods *** -HRESULT STDMETHODCALLTYPE CorThreadpool::CorCallOrQueueUserWorkItem(LPTHREAD_START_ROUTINE Function, - PVOID Context, - BOOL* pResult ) +extern BOOL g_fWeOwnProcess; + +CorHost2::CorHost2() { - CONTRACTL - { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; - } - CONTRACTL_END; + LIMITED_METHOD_CONTRACT; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; - *pResult = FALSE; - EX_TRY - { - *pResult = ThreadpoolMgr::QueueUserWorkItem(Function,Context,CALL_OR_QUEUE); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - END_ENTRYPOINT_NOTHROW; - return hr; + m_fStarted = FALSE; + m_fFirstToLoadCLR = FALSE; + m_fAppDomainCreated = FALSE; } +static DangerousNonHostedSpinLock lockOnlyOneToInvokeStart; -HRESULT STDMETHODCALLTYPE CorThreadpool::CorCreateTimer(PHANDLE phNewTimer, - WAITORTIMERCALLBACK Callback, - PVOID Parameter, - DWORD DueTime, - DWORD Period, - BOOL* pResult) +STDMETHODIMP CorHost2::Start() { CONTRACTL { - DISABLED(NOTHROW); + NOTHROW; GC_TRIGGERS; - MODE_ANY; ENTRY_POINT; - } - CONTRACTL_END; + }CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; + HRESULT hr; - *pResult = FALSE; - EX_TRY + BEGIN_ENTRYPOINT_NOTHROW; + + // Ensure that only one thread at a time gets in here + DangerousNonHostedSpinLockHolder lockHolder(&lockOnlyOneToInvokeStart); + + // To provide the complete semantic of Start/Stop in context of a given host, we check m_fStarted and let + // them invoke the Start only if they have not already. Likewise, they can invoke the Stop method + // only if they have invoked Start prior to that. + // + // This prevents a host from invoking Stop twice and hitting the refCount to zero, when another + // host is using the CLR, as CLR instance sharing across hosts is a scenario for CoreCLR. + + if (g_fEEStarted) { - *pResult = ThreadpoolMgr::CreateTimerQueueTimer(phNewTimer,Callback,Parameter,DueTime,Period,0); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); + hr = S_OK; + // CoreCLR is already running - but was Start already invoked by this host? + if (m_fStarted) + { + // This host had already invoked the Start method - return them an error + hr = HOST_E_INVALIDOPERATION; + } + else + { + // Increment the global (and dynamic) refCount... + FastInterlockIncrement(&m_RefCount); + + // And set our flag that this host has invoked the Start... + m_fStarted = TRUE; + } } - EX_CATCH + else { - hr = GET_EXCEPTION()->GetHR(); + // Using managed C++ libraries, its possible that when the runtime is already running, + // MC++ will use CorBindToRuntimeEx to make callbacks into specific appdomain of its + // choice. Now, CorBindToRuntimeEx results in CorHost2::CreateObject being invoked + // that will set runtime hosted flag "g_fHostConfig |= CLRHOSTED". + // + // For the case when managed code started without CLR hosting and MC++ does a + // CorBindToRuntimeEx, setting the CLR hosted flag is incorrect. + // + // Thus, before we attempt to start the runtime, we save the status of it being + // already running or not. Next, if we are able to successfully start the runtime + // and ONLY if it was not started earlier will we set the hosted flag below. + if (!g_fEEStarted) + { + g_fHostConfig |= CLRHOSTED; + } + + hr = CorRuntimeHostBase::Start(); + if (SUCCEEDED(hr)) + { + // Set our flag that this host invoked the Start method. + m_fStarted = TRUE; + + // And they also loaded the CoreCLR DLL in the memory (for this version). + // This is a special flag as the host that has got this flag set will be allowed + // to repeatedly invoke Stop method (without corresponding Start method invocations). + // This is to support scenarios like that of Office where they need to bring down + // the CLR at any cost. + // + // So, if you want to do that, just make sure you are the first host to load the + // specific version of CLR in memory AND start it. + m_fFirstToLoadCLR = TRUE; + if (FastInterlockIncrement(&m_RefCount) != 1) + { + } + else + { + if (g_fWeOwnProcess) + { + // Runtime is started by a managed exe. Bump the ref-count, so that + // matching Start/Stop does not stop runtime. + FastInterlockIncrement(&m_RefCount); + } + } + } } - EX_END_CATCH(SwallowAllExceptions); END_ENTRYPOINT_NOTHROW; return hr; } - -HRESULT STDMETHODCALLTYPE CorThreadpool::CorDeleteTimer(HANDLE Timer, HANDLE CompletionEvent, BOOL* pResult) +// Starts the runtime. This is equivalent to CoInitializeEE(); +HRESULT CorRuntimeHostBase::Start() { CONTRACTL { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; + NOTHROW; + DISABLED(GC_TRIGGERS); ENTRY_POINT; } CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; + HRESULT hr = S_OK; - *pResult = FALSE; - EX_TRY - { - *pResult = ThreadpoolMgr::DeleteTimerQueueTimer(Timer,CompletionEvent); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); - } - EX_CATCH + BEGIN_ENTRYPOINT_NOTHROW; { - hr = GET_EXCEPTION()->GetHR(); + m_Started = TRUE; +#ifdef FEATURE_EVENT_TRACE + g_fEEHostedStartup = TRUE; +#endif // FEATURE_EVENT_TRACE + hr = InitializeEE(COINITEE_DEFAULT); } - EX_END_CATCH(SwallowAllExceptions); - END_ENTRYPOINT_NOTHROW; + return hr; } -HRESULT STDMETHODCALLTYPE CorThreadpool::CorChangeTimer(HANDLE Timer, - ULONG DueTime, - ULONG Period, - BOOL* pResult) + +HRESULT CorHost2::Stop() { CONTRACTL { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; + NOTHROW; + ENTRY_POINT; // We're bringing the EE down, so no point in probing + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} } CONTRACTL_END; - - HRESULT hr = E_UNEXPECTED; + if (!g_fEEStarted) + { + return E_UNEXPECTED; + } + HRESULT hr=S_OK; BEGIN_ENTRYPOINT_NOTHROW; - *pResult = FALSE; - EX_TRY + // Is this host eligible to invoke the Stop method? + if ((!m_fStarted) && (!m_fFirstToLoadCLR)) { - //CONTRACT_VIOLATION(ThrowsViolation); - *pResult = ThreadpoolMgr::ChangeTimerQueueTimer(Timer,DueTime,Period); - hr = (*pResult ? S_OK : HRESULT_FROM_GetLastError()); + // Well - since this host never invoked Start, it is not eligible to invoke Stop. + // Semantically, for such a host, CLR is not available in the process. The only + // exception to this condition is the host that first loaded this version of the + // CLR and invoked Start method. For details, refer to comments in CorHost2::Start implementation. + hr = HOST_E_CLRNOTAVAILABLE; } - EX_CATCH + else { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); + while (TRUE) + { + LONG refCount = m_RefCount; + if (refCount == 0) + { + hr = HOST_E_CLRNOTAVAILABLE; + break; + } + else + if (FastInterlockCompareExchange(&m_RefCount, refCount - 1, refCount) == refCount) + { + // Indicate that we have got a Stop for a corresponding Start call from the + // Host. Semantically, CoreCLR has stopped for them. + m_fStarted = FALSE; + if (refCount > 1) + { + hr=S_FALSE; + break; + } + else + { + break; + } + } + } + } END_ENTRYPOINT_NOTHROW; + + return hr; } -HRESULT STDMETHODCALLTYPE CorThreadpool::CorSetMaxThreads(DWORD MaxWorkerThreads, - DWORD MaxIOCompletionThreads) +HRESULT CorHost2::GetCurrentAppDomainId(DWORD *pdwAppDomainId) { CONTRACTL { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; + NOTHROW; + GC_NOTRIGGER; ENTRY_POINT; } CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; + // 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)) + || !m_fStarted + ) + { + return HOST_E_CLRNOTAVAILABLE; + } + + HRESULT hr = S_OK; + BEGIN_ENTRYPOINT_NOTHROW; - BOOL result = FALSE; - EX_TRY + if(pdwAppDomainId == NULL) { - result = ThreadpoolMgr::SetMaxThreads(MaxWorkerThreads, MaxIOCompletionThreads); - hr = (result ? S_OK : E_FAIL); + hr = E_POINTER; } - EX_CATCH + else { - hr = GET_EXCEPTION()->GetHR(); + Thread *pThread = GetThread(); + if (!pThread) + { + hr = E_UNEXPECTED; + } + else + { + *pdwAppDomainId = SystemDomain::GetCurrentDomain()->GetId().m_dwId; + } } - EX_END_CATCH(SwallowAllExceptions); END_ENTRYPOINT_NOTHROW; + return hr; } -HRESULT STDMETHODCALLTYPE CorThreadpool::CorGetMaxThreads(DWORD *MaxWorkerThreads, - DWORD *MaxIOCompletionThreads) +HRESULT CorHost2::ExecuteApplication(LPCWSTR pwzAppFullName, + DWORD dwManifestPaths, + LPCWSTR *ppwzManifestPaths, + DWORD dwActivationData, + LPCWSTR *ppwzActivationData, + int *pReturnValue) +{ + return E_NOTIMPL; +} + +/* + * This method processes the arguments sent to the host which are then used + * to invoke the main method. + * Note - + * [0] - points to the assemblyName that has been sent by the host. + * The rest are the arguments sent to the assembly. + * Also note, this might not always return the exact same identity as the cmdLine + * used to invoke the method. + * + * For example :- + * ActualCmdLine - Foo arg1 arg2. + * (Host1) - Full_path_to_Foo arg1 arg2 +*/ +void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) { CONTRACTL { - DISABLED(NOTHROW); + THROWS; GC_TRIGGERS; - MODE_ANY; - ENTRY_POINT; + MODE_COOPERATIVE; } CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; + struct _gc + { + PTRARRAYREF cmdLineArgs; + } gc; - BOOL result = FALSE; - EX_TRY + ZeroMemory(&gc, sizeof(gc)); + GCPROTECT_BEGIN(gc); + + gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); + OBJECTREF orAssemblyPath = StringObject::NewString(pwzAssemblyPath); + gc.cmdLineArgs->SetAt(0, orAssemblyPath); + + for (int i = 0; i < argc; ++i) { - result = ThreadpoolMgr::GetMaxThreads(MaxWorkerThreads, MaxIOCompletionThreads); - hr = (result ? S_OK : E_FAIL); + OBJECTREF argument = StringObject::NewString(argv[i]); + gc.cmdLineArgs->SetAt(i + 1, argument); } - EX_CATCH + + MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS); + + ARG_SLOT args[] = { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); + ObjToArgSlot(gc.cmdLineArgs), + }; + setCmdLineArgs.Call(args); - END_ENTRYPOINT_NOTHROW; - return hr; + GCPROTECT_END(); } -HRESULT STDMETHODCALLTYPE CorThreadpool::CorGetAvailableThreads(DWORD *AvailableWorkerThreads, - DWORD *AvailableIOCompletionThreads) +HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, + LPCWSTR pwzAssemblyPath, + int argc, + LPCWSTR* argv, + DWORD *pReturnValue) { CONTRACTL { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; + THROWS; // Throws...as we do not want it to swallow the managed exception ENTRY_POINT; } CONTRACTL_END; - HRESULT hr = E_UNEXPECTED; - BEGIN_ENTRYPOINT_NOTHROW; + // This is currently supported in default domain only + if (dwAppDomainId != DefaultADID) + return HOST_E_INVALIDOPERATION; - BOOL result = FALSE; - EX_TRY - { - result = ThreadpoolMgr::GetAvailableThreads(AvailableWorkerThreads, AvailableIOCompletionThreads); - hr = (result ? S_OK : E_FAIL); - } - EX_CATCH + // No point going further if the runtime is not running... + if (!IsRuntimeActive() || !m_fStarted) { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - - END_ENTRYPOINT_NOTHROW; - - return hr; -} -#endif // !defined(FEATURE_CORECLR) -//*************************************************************************** - -ULONG CorRuntimeHostBase::m_Version = 0; - -#ifdef FEATURE_INCLUDE_ALL_INTERFACES -static CCLRDebugManager s_CLRDebugManager; -#endif // FEATURE_INCLUDE_ALL_INTERFACES - -#if defined(FEATURE_INCLUDE_ALL_INTERFACES) || defined(FEATURE_WINDOWSPHONE) -CCLRErrorReportingManager g_CLRErrorReportingManager; -#endif // defined(FEATURE_INCLUDE_ALL_INTERFACES) || defined(FEATURE_WINDOWSPHONE) - -#ifdef FEATURE_IPCMAN -static CCLRSecurityAttributeManager s_CLRSecurityAttributeManager; -#endif // FEATURE_IPCMAN - -#endif // !DAC - -typedef DPTR(CONNID) PTR_CONNID; - -#ifdef FEATURE_INCLUDE_ALL_INTERFACES -// Hash table to keep track for SQL fiber support -class ConnectionNameTable : CHashTableAndData -{ - friend class CCLRDebugManager; -public: + return HOST_E_CLRNOTAVAILABLE; + } + + if(!pwzAssemblyPath) + return E_POINTER; - // Key to match is connection ID. - // Returns true if the given HASHENTRY has the same key as the requested key. - BOOL Cmp(SIZE_T requestedKey, const HASHENTRY * pEntry) + if(argc < 0) { - SUPPORTS_DAC; - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - - CONNID keyRequested = (CONNID)requestedKey; - CONNID keySearch = dac_cast(pEntry)->m_dwConnectionId; - return keyRequested != keySearch; + return E_INVALIDARG; } - // Hash function - ULONG Hash(CONNID dwConnectionId) + if(argc > 0 && argv == NULL) { - SUPPORTS_DAC; - LIMITED_METHOD_CONTRACT; - - return (ULONG)(dwConnectionId); + return E_INVALIDARG; } -#ifndef DACCESS_COMPILE - // constructor - ConnectionNameTable( - ULONG iBuckets) : // # of chains we are hashing into. - CHashTableAndData(iBuckets) - {LIMITED_METHOD_CONTRACT;} + HRESULT hr = S_OK; - // destructor - ~ConnectionNameTable() - { - CONTRACTL - { - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - NOTHROW; - } - CONTRACTL_END; - HASHFIND hashFind; - ConnectionNameHashEntry *pNameEntry; + AppDomain *pCurDomain = SystemDomain::GetCurrentDomain(); - pNameEntry = (ConnectionNameHashEntry *)FindFirstEntry(&hashFind); - while (pNameEntry != NULL) + Thread *pThread = GetThread(); + if (pThread == NULL) + { + pThread = SetupThreadNoThrow(&hr); + if (pThread == NULL) { - if (pNameEntry->m_pwzName) - { - delete pNameEntry->m_pwzName; - pNameEntry->m_pwzName = NULL; - } - - if (pNameEntry->m_CLRTaskCount != 0) - { - _ASSERTE(pNameEntry->m_ppCLRTaskArray != NULL); - for (UINT i = 0; i < pNameEntry->m_CLRTaskCount; i++) - { - pNameEntry->m_ppCLRTaskArray[i]->Release(); - } - delete [] pNameEntry->m_ppCLRTaskArray; - pNameEntry->m_ppCLRTaskArray = NULL; - pNameEntry->m_CLRTaskCount = 0; - } - pNameEntry = (ConnectionNameHashEntry *)FindNextEntry(&hashFind); + goto ErrExit; } } - // Add a new connection into hash table. - // This function does not throw but return NULL when memory allocation fails. - ConnectionNameHashEntry *AddConnection( - CONNID dwConnectionId, - __in_z WCHAR *pwzName) // We should review this in the future. This API is - // public and callable by a host. This SAL annotation - // is the best we can do now. + if(pCurDomain->GetId().m_dwId != DefaultADID) { - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; + return HOST_E_INVALIDOPERATION; + } - ULONG iHash = Hash(dwConnectionId); + INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; + INSTALL_UNWIND_AND_CONTINUE_HANDLER; - size_t len = wcslen(pwzName) + 1; - WCHAR *pConnName = new (nothrow) WCHAR[len]; - if (pConnName == NULL) - return NULL; + _ASSERTE (!pThread->PreemptiveGCDisabled()); - ConnectionNameHashEntry *pRecord = (ConnectionNameHashEntry *)Add(iHash); - if (pRecord) - { - pRecord->m_dwConnectionId = dwConnectionId; - pRecord->m_pwzName = pConnName; - wcsncpy_s(pRecord->m_pwzName, len, pwzName, len); - pRecord->m_CLRTaskCount = 0; - pRecord->m_ppCLRTaskArray = NULL; - } - else - { - if (pConnName) - delete [] pConnName; - } + Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); - return pRecord; - } +#if defined(FEATURE_MULTICOREJIT) + pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain); +#endif // defined(FEATURE_MULTICOREJIT) - // Delete a hash entry given a connection id - void DeleteConnection(CONNID dwConnectionId) { - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; + GCX_COOP(); - ULONG iHash; - iHash = Hash(dwConnectionId); - ConnectionNameHashEntry * pRecord = - reinterpret_cast(Find(iHash, (SIZE_T)dwConnectionId)); - if (pRecord == NULL) - { - return; - } + // Here we call the managed method that gets the cmdLineArgs array. + SetCommandLineArgs(pwzAssemblyPath, argc, argv); - _ASSERTE(pRecord->m_CLRTaskCount == 0 && pRecord->m_ppCLRTaskArray == NULL); - if (pRecord->m_pwzName) + PTRARRAYREF arguments = NULL; + GCPROTECT_BEGIN(arguments); + + arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass); + for (int i = 0; i < argc; ++i) { - delete pRecord->m_pwzName; - pRecord->m_pwzName = NULL; + STRINGREF argument = StringObject::NewString(argv[i]); + arguments->SetAt(i, argument); } - Delete(iHash, (HASHENTRY *)pRecord); - } - // return NULL if the given connection id cannot be found. - ConnectionNameHashEntry *FindConnection(CONNID dwConnectionId) - { - CONTRACTL + DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */); + if (pReturnValue) { - GC_NOTRIGGER; - NOTHROW; + *pReturnValue = retval; } - CONTRACTL_END; - - ULONG iHash; - iHash = Hash(dwConnectionId); - return reinterpret_cast(Find(iHash, (SIZE_T)dwConnectionId)); - } -#endif // !DAC -}; -#endif //FEATURE_INCLUDE_ALL_INTERFACES - -// Keep track connection id and name -#ifdef FEATURE_INCLUDE_ALL_INTERFACES -SPTR_IMPL(ConnectionNameTable, CCLRDebugManager, m_pConnectionNameHash); -CrstStatic CCLRDebugManager::m_lockConnectionNameTable; -#endif // FEATURE_INCLUDE_ALL_INTERFACES + GCPROTECT_END(); -#ifndef DACCESS_COMPILE + } + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; -#if !defined(FEATURE_CORECLR) // simple hosting -//***************************************************************************** -// ICorRuntimeHost -//***************************************************************************** -extern BOOL g_singleVersionHosting; +ErrExit: -// *** ICorRuntimeHost methods *** -// Returns an object for configuring the runtime prior to -// it starting. If the runtime has been initialized this -// routine returns an error. See ICorConfiguration. -HRESULT CorHost::GetConfiguration(ICorConfiguration** pConfiguration) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - HRESULT hr=E_FAIL; - BEGIN_ENTRYPOINT_NOTHROW; - if (CorHost::GetHostVersion() != 1) - { - hr=HOST_E_INVALIDOPERATION; - } - else - if (!pConfiguration) - hr= E_POINTER; - else - if (!m_Started) - { - *pConfiguration = (ICorConfiguration *) this; - AddRef(); - hr=S_OK; - } - END_ENTRYPOINT_NOTHROW; - // Cannot obtain configuration after the runtime is started return hr; } -STDMETHODIMP CorHost::Start(void) +HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath, + LPCWSTR pwzTypeName, + LPCWSTR pwzMethodName, + LPCWSTR pwzArgument, + DWORD *pReturnValue) { CONTRACTL { NOTHROW; - GC_TRIGGERS; ENTRY_POINT; } CONTRACTL_END; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = CorRuntimeHostBase::Start(); - - END_ENTRYPOINT_NOTHROW; - - if (hr == S_FALSE) + // No point going further if the runtime is not running... + if (!IsRuntimeActive() + || !m_fStarted + ) { - // This is to keep v1 behavior. - hr = S_OK; - } - return(hr); + return HOST_E_CLRNOTAVAILABLE; + } + + + // Ensure that code is not loaded in the Default AppDomain + return HOST_E_INVALIDOPERATION; } -#endif // !defined(FEATURE_CORECLR) - -// *** ICorRuntimeHost methods *** -#ifndef FEATURE_CORECLR -// Returns an object for configuring the runtime prior to -// it starting. If the runtime has been initialized this -// routine returns an error. See ICorConfiguration. -HRESULT CorHost2::GetConfiguration(ICorConfiguration** pConfiguration) +HRESULT ExecuteInAppDomainHelper(FExecuteInAppDomainCallback pCallback, + void * cookie) { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - if (!pConfiguration) - return E_POINTER; - HRESULT hr=E_FAIL; - BEGIN_ENTRYPOINT_NOTHROW; - if (!m_Started) - { - *pConfiguration = (ICorConfiguration *) this; - AddRef(); - hr=S_OK; - } - END_ENTRYPOINT_NOTHROW; - // Cannot obtain configuration after the runtime is started - return hr; -} -#endif // FEATURE_CORECLR + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_SO_INTOLERANT; -extern BOOL g_fWeOwnProcess; + HRESULT hr = S_OK; -CorHost2::CorHost2() -{ - LIMITED_METHOD_CONTRACT; + BEGIN_SO_TOLERANT_CODE(GetThread()); + hr = pCallback(cookie); + END_SO_TOLERANT_CODE; -#ifdef FEATURE_CORECLR - m_fStarted = FALSE; - m_fFirstToLoadCLR = FALSE; - m_fAppDomainCreated = FALSE; -#endif // FEATURE_CORECLR + return hr; } -static DangerousNonHostedSpinLock lockOnlyOneToInvokeStart; - -STDMETHODIMP CorHost2::Start() +HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId, + FExecuteInAppDomainCallback pCallback, + void * cookie) { - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - ENTRY_POINT; - }CONTRACTL_END; - - HRESULT hr; - - BEGIN_ENTRYPOINT_NOTHROW; - -#ifdef FEATURE_CORECLR - // Ensure that only one thread at a time gets in here - DangerousNonHostedSpinLockHolder lockHolder(&lockOnlyOneToInvokeStart); - - // To provide the complete semantic of Start/Stop in context of a given host, we check m_fStarted and let - // them invoke the Start only if they have not already. Likewise, they can invoke the Stop method - // only if they have invoked Start prior to that. - // - // This prevents a host from invoking Stop twice and hitting the refCount to zero, when another - // host is using the CLR, as CLR instance sharing across hosts is a scenario for CoreCLR. - if (g_fEEStarted) + // No point going further if the runtime is not running... + if (!IsRuntimeActive() + || !m_fStarted + ) { - hr = S_OK; - // CoreCLR is already running - but was Start already invoked by this host? - if (m_fStarted) - { - // This host had already invoked the Start method - return them an error - hr = HOST_E_INVALIDOPERATION; - } - else - { - // Increment the global (and dynamic) refCount... - FastInterlockIncrement(&m_RefCount); + return HOST_E_CLRNOTAVAILABLE; + } - // And set our flag that this host has invoked the Start... - m_fStarted = TRUE; - } - } - else -#endif // FEATURE_CORECLR + if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) { - // Using managed C++ libraries, its possible that when the runtime is already running, - // MC++ will use CorBindToRuntimeEx to make callbacks into specific appdomain of its - // choice. Now, CorBindToRuntimeEx results in CorHost2::CreateObject being invoked - // that will set runtime hosted flag "g_fHostConfig |= CLRHOSTED". - // - // For the case when managed code started without CLR hosting and MC++ does a - // CorBindToRuntimeEx, setting the CLR hosted flag is incorrect. - // - // Thus, before we attempt to start the runtime, we save the status of it being - // already running or not. Next, if we are able to successfully start the runtime - // and ONLY if it was not started earlier will we set the hosted flag below. - if (!g_fEEStarted) - { - g_fHostConfig |= CLRHOSTED; - } - - hr = CorRuntimeHostBase::Start(); - if (SUCCEEDED(hr)) - { -#ifdef FEATURE_CORECLR - // Set our flag that this host invoked the Start method. - m_fStarted = TRUE; - - // And they also loaded the CoreCLR DLL in the memory (for this version). - // This is a special flag as the host that has got this flag set will be allowed - // to repeatedly invoke Stop method (without corresponding Start method invocations). - // This is to support scenarios like that of Office where they need to bring down - // the CLR at any cost. - // - // So, if you want to do that, just make sure you are the first host to load the - // specific version of CLR in memory AND start it. - m_fFirstToLoadCLR = TRUE; -#endif // FEATURE_CORECLR - if (FastInterlockIncrement(&m_RefCount) != 1) - { - } - else - { - if (g_fWeOwnProcess) - { - // Runtime is started by a managed exe. Bump the ref-count, so that - // matching Start/Stop does not stop runtime. - FastInterlockIncrement(&m_RefCount); - } - } - } + // Ensure that code is not loaded in the Default AppDomain + if (dwAppDomainId == DefaultADID) + return HOST_E_INVALIDOPERATION; } - END_ENTRYPOINT_NOTHROW; - return hr; -} + // Moved this here since no point validating the pointer + // if the basic checks [above] fail + if( pCallback == NULL) + return E_POINTER; -// Starts the runtime. This is equivalent to CoInitializeEE(); -HRESULT CorRuntimeHostBase::Start() -{ CONTRACTL { NOTHROW; - DISABLED(GC_TRIGGERS); - ENTRY_POINT; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } CONTRACTL_END; HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; + BEGIN_EXTERNAL_ENTRYPOINT(&hr); + GCX_COOP_THREAD_EXISTS(GET_THREAD()); + ENTER_DOMAIN_ID(ADID(dwAppDomainId)) { - m_Started = TRUE; -#ifdef FEATURE_EVENT_TRACE - g_fEEHostedStartup = TRUE; -#endif // FEATURE_EVENT_TRACE - hr = InitializeEE(COINITEE_DEFAULT); + // We are calling an unmanaged function pointer, either an unmanaged function, or a marshaled out delegate. + // The thread should be in preemptive mode, and SO_Tolerant. + GCX_PREEMP(); + hr=ExecuteInAppDomainHelper (pCallback, cookie); } + END_DOMAIN_TRANSITION; + END_EXTERNAL_ENTRYPOINT; END_ENTRYPOINT_NOTHROW; return hr; } -#if !defined(FEATURE_CORECLR) // simple hosting -HRESULT CorHost::Stop() +#define EMPTY_STRING_TO_NULL(s) {if(s && s[0] == 0) {s=NULL;};} + +HRESULT CorHost2::_CreateAppDomain( + LPCWSTR wszFriendlyName, + DWORD dwFlags, + LPCWSTR wszAppDomainManagerAssemblyName, + LPCWSTR wszAppDomainManagerTypeName, + int nProperties, + LPCWSTR* pPropertyNames, + LPCWSTR* pPropertyValues, + DWORD* pAppDomainID) { CONTRACTL { NOTHROW; - ENTRY_POINT; if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } CONTRACTL_END; - // This must remain this way (that is doing nothing) for backwards compat reasons. - return S_OK; -} -#endif // !defined(FEATURE_CORECLR) + HRESULT hr=S_OK; -HRESULT CorHost2::Stop() -{ - CONTRACTL - { - NOTHROW; - ENTRY_POINT; // We're bringing the EE down, so no point in probing - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - } - CONTRACTL_END; - if (!g_fEEStarted) + //cannot call the function more than once when single appDomain is allowed + if (m_fAppDomainCreated && (m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) { - return E_UNEXPECTED; + return HOST_E_INVALIDOPERATION; } - HRESULT hr=S_OK; + + //normalize empty strings + EMPTY_STRING_TO_NULL(wszFriendlyName); + EMPTY_STRING_TO_NULL(wszAppDomainManagerAssemblyName); + EMPTY_STRING_TO_NULL(wszAppDomainManagerTypeName); + + if(pAppDomainID==NULL) + return E_POINTER; + + if (!m_fStarted) + return HOST_E_INVALIDOPERATION; + + if(wszFriendlyName == NULL) + return E_INVALIDARG; + + if((wszAppDomainManagerAssemblyName == NULL) != (wszAppDomainManagerTypeName == NULL)) + return E_INVALIDARG; + BEGIN_ENTRYPOINT_NOTHROW; -#ifdef FEATURE_CORECLR - // Is this host eligible to invoke the Stop method? - if ((!m_fStarted) && (!m_fFirstToLoadCLR)) + BEGIN_EXTERNAL_ENTRYPOINT(&hr); + GCX_COOP_THREAD_EXISTS(GET_THREAD()); + + AppDomainCreationHolder pDomain; + + // If StartupFlag specifies single appDomain then return the default domain instead of creating new one + if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) { - // Well - since this host never invoked Start, it is not eligible to invoke Stop. - // Semantically, for such a host, CLR is not available in the process. The only - // exception to this condition is the host that first loaded this version of the - // CLR and invoked Start method. For details, refer to comments in CorHost2::Start implementation. - hr = HOST_E_CLRNOTAVAILABLE; + pDomain.Assign(SystemDomain::System()->DefaultDomain()); } else -#endif // FEATURE_CORECLR - { - while (TRUE) - { - LONG refCount = m_RefCount; - if (refCount == 0) - { - #ifdef FEATURE_CORECLR - hr = HOST_E_CLRNOTAVAILABLE; - #else // !FEATURE_CORECLR - hr= E_UNEXPECTED; - #endif // FEATURE_CORECLR - break; - } - else - if (FastInterlockCompareExchange(&m_RefCount, refCount - 1, refCount) == refCount) - { - #ifdef FEATURE_CORECLR - // Indicate that we have got a Stop for a corresponding Start call from the - // Host. Semantically, CoreCLR has stopped for them. - m_fStarted = FALSE; - #endif // FEATURE_CORECLR - - if (refCount > 1) - { - hr=S_FALSE; - break; - } - else - { - break; - } - } - } - } -#ifndef FEATURE_CORECLR - if (hr==S_OK) { - EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL); - if (action > eExitProcess) - { - g_fFastExitProcess = 1; - } - EEShutDown(FALSE); + AppDomain::CreateUnmanagedObject(pDomain); } -#endif // FEATURE_CORECLR - END_ENTRYPOINT_NOTHROW; -#ifndef FEATURE_CORECLR - if (hr == S_OK) + ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName); + + if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS) { - if (m_HostControl) - { - m_HostControl->Release(); - m_HostControl = NULL; - } + pDomain->SetIgnoreUnhandledExceptions(); } -#endif // FEATURE_CORECLR - - return hr; -} -#if defined(FEATURE_COMINTEROP) && !defined(FEATURE_CORECLR) + if (dwFlags & APPDOMAIN_SECURITY_FORBID_CROSSAD_REVERSE_PINVOKE) + pDomain->SetReversePInvokeCannotEnter(); -// Creates a domain in the runtime. The identity array is -// a pointer to an array TYPE containing IIdentity objects defining -// the security identity. -HRESULT CorRuntimeHostBase::CreateDomain(LPCWSTR pwzFriendlyName, - IUnknown* pIdentityArray, // Optional - IUnknown ** pAppDomain) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_ENTRY_POINT; + if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS) + pDomain->SetForceTrivialWaitOperations(); - return CreateDomainEx(pwzFriendlyName, - NULL, - NULL, - pAppDomain); -} + +#ifdef PROFILING_SUPPORTED + EX_TRY +#endif + { + pDomain->SetAppDomainManagerInfo(wszAppDomainManagerAssemblyName,wszAppDomainManagerTypeName,eInitializeNewDomainFlags_None); + GCX_COOP(); + + struct + { + STRINGREF friendlyName; + PTRARRAYREF propertyNames; + PTRARRAYREF propertyValues; + STRINGREF sandboxName; + OBJECTREF setupInfo; + OBJECTREF adSetup; + } _gc; -// Returns the default domain. -HRESULT CorRuntimeHostBase::GetDefaultDomain(IUnknown ** pAppDomain) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - ENTRY_POINT; - } CONTRACTL_END; + ZeroMemory(&_gc,sizeof(_gc)); - HRESULT hr = E_UNEXPECTED; - if (!g_fEEStarted) - return hr; + GCPROTECT_BEGIN(_gc) + _gc.friendlyName=StringObject::NewString(wszFriendlyName); + + if(nProperties>0) + { + _gc.propertyNames = (PTRARRAYREF) AllocateObjectArray(nProperties, g_pStringClass); + _gc.propertyValues= (PTRARRAYREF) AllocateObjectArray(nProperties, g_pStringClass); + for (int i=0;i< nProperties;i++) + { + STRINGREF obj = StringObject::NewString(pPropertyNames[i]); + _gc.propertyNames->SetAt(i, obj); + + obj = StringObject::NewString(pPropertyValues[i]); + _gc.propertyValues->SetAt(i, obj); + } + } - if( pAppDomain == NULL) - return E_POINTER; + if (dwFlags & APPDOMAIN_SECURITY_SANDBOXED) + { + _gc.sandboxName = StringObject::NewString(W("Internet")); + } + else + { + _gc.sandboxName = StringObject::NewString(W("FullTrust")); + } - BEGIN_ENTRYPOINT_NOTHROW; + MethodDescCallSite prepareDataForSetup(METHOD__APP_DOMAIN__PREPARE_DATA_FOR_SETUP); - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - { - GCX_COOP_THREAD_EXISTS(GET_THREAD()); + ARG_SLOT args[8]; + args[0]=ObjToArgSlot(_gc.friendlyName); + args[1]=ObjToArgSlot(NULL); + args[2]=ObjToArgSlot(NULL); + args[3]=ObjToArgSlot(NULL); + //CoreCLR shouldn't have dependencies on parent app domain. + args[4]=ObjToArgSlot(NULL); + args[5]=ObjToArgSlot(_gc.sandboxName); + args[6]=ObjToArgSlot(_gc.propertyNames); + args[7]=ObjToArgSlot(_gc.propertyValues); - if (SystemDomain::System()) { - AppDomain* pCom = SystemDomain::System()->DefaultDomain(); - if(pCom) - hr = pCom->GetComIPForExposedObject(pAppDomain); - } + _gc.setupInfo=prepareDataForSetup.Call_RetOBJECTREF(args); - } - END_EXTERNAL_ENTRYPOINT; - END_ENTRYPOINT_NOTHROW; + // + // Get the new flag values and set it to the domain + // + PTRARRAYREF handleArrayObj = (PTRARRAYREF) ObjectToOBJECTREF(_gc.setupInfo); + _gc.adSetup = ObjectToOBJECTREF(handleArrayObj->GetAt(1)); - return hr; -} -// Returns the default domain. -HRESULT CorRuntimeHostBase::CurrentDomain(IUnknown ** pAppDomain) -{ - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - ENTRY_POINT; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - } - CONTRACTL_END; + pDomain->DoSetup(&_gc.setupInfo); - HRESULT hr = E_UNEXPECTED; - if (!g_fEEStarted) - return hr; + pDomain->CacheStringsForDAC(); + + GCPROTECT_END(); - if( pAppDomain == NULL) return E_POINTER; + *pAppDomainID=pDomain->GetId().m_dwId; - BEGIN_ENTRYPOINT_NOTHROW; + // If StartupFlag specifies single appDomain then set the flag that appdomain has already been created + if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) + { + m_fAppDomainCreated = TRUE; + } + } +#ifdef PROFILING_SUPPORTED + EX_HOOK + { + // Need the first assembly loaded in to get any data on an app domain. + { + BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + GCX_PREEMP(); + g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR()); + END_PIN_PROFILER(); + } + } + EX_END_HOOK; - BEGIN_EXTERNAL_ENTRYPOINT(&hr); + // Need the first assembly loaded in to get any data on an app domain. { - GCX_COOP_THREAD_EXISTS(GET_THREAD()); + BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + GCX_PREEMP(); + g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, S_OK); + END_PIN_PROFILER(); + } +#endif // PROFILING_SUPPORTED - AppDomain* pCom = ::GetAppDomain(); - if(pCom) - hr = pCom->GetComIPForExposedObject(pAppDomain); + // DoneCreating releases ownership of AppDomain. After this call, there should be no access to pDomain. + pDomain.DoneCreating(); - } END_EXTERNAL_ENTRYPOINT; + END_ENTRYPOINT_NOTHROW; return hr; -}; -#endif // FEATURE_COMINTEROP && !FEATURE_CORECLR +}; -HRESULT CorHost2::GetCurrentAppDomainId(DWORD *pdwAppDomainId) +HRESULT CorHost2::_CreateDelegate( + DWORD appDomainID, + LPCWSTR wszAssemblyName, + LPCWSTR wszClassName, + LPCWSTR wszMethodName, + INT_PTR* fnPtr) { + CONTRACTL { NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } 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)) -#ifdef FEATURE_CORECLR - || !m_fStarted -#endif - ) - { - return HOST_E_CLRNOTAVAILABLE; - } + HRESULT hr=S_OK; + + EMPTY_STRING_TO_NULL(wszAssemblyName); + EMPTY_STRING_TO_NULL(wszClassName); + EMPTY_STRING_TO_NULL(wszMethodName); + + if (fnPtr == NULL) + return E_POINTER; + *fnPtr = NULL; + + if(wszAssemblyName == NULL) + return E_INVALIDARG; - HRESULT hr = S_OK; + if(wszClassName == NULL) + return E_INVALIDARG; - BEGIN_ENTRYPOINT_NOTHROW; + if(wszMethodName == NULL) + return E_INVALIDARG; + + if (!m_fStarted) + return HOST_E_INVALIDOPERATION; - if(pdwAppDomainId == NULL) - { - hr = E_POINTER; - } - else + if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) { - Thread *pThread = GetThread(); - if (!pThread) - { - hr = E_UNEXPECTED; - } - else - { - *pdwAppDomainId = SystemDomain::GetCurrentDomain()->GetId().m_dwId; - } + // Ensure that code is not loaded in the Default AppDomain + if (appDomainID == DefaultADID) + return HOST_E_INVALIDOPERATION; } - END_ENTRYPOINT_NOTHROW; - - return hr; -} + BEGIN_ENTRYPOINT_NOTHROW; -HRESULT CorHost2::ExecuteApplication(LPCWSTR pwzAppFullName, - DWORD dwManifestPaths, - LPCWSTR *ppwzManifestPaths, - DWORD dwActivationData, - LPCWSTR *ppwzActivationData, - int *pReturnValue) -{ -#ifndef FEATURE_CORECLR - // This API should not be called when the EE has already been started. - HRESULT hr = E_UNEXPECTED; - if (g_fEEStarted) - return hr; + BEGIN_EXTERNAL_ENTRYPOINT(&hr); + GCX_COOP_THREAD_EXISTS(GET_THREAD()); - // - // We will let unhandled exceptions in the activated application - // propagate all the way up, so that ClickOnce semi-trusted apps - // can participate in the Dr Watson program, etc... - // + MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName); + MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName); + MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName); - CONTRACTL { - THROWS; - ENTRY_POINT; - } - CONTRACTL_END; + ADID id; + id.m_dwId=appDomainID; - if (!pwzAppFullName) - IfFailGo(E_POINTER); + ENTER_DOMAIN_ID(id) - // Set the information about the application to execute. - CorCommandLine::m_pwszAppFullName = (LPWSTR) pwzAppFullName; - CorCommandLine::m_dwManifestPaths = dwManifestPaths; - CorCommandLine::m_ppwszManifestPaths = (LPWSTR*) ppwzManifestPaths; - CorCommandLine::m_dwActivationData = dwActivationData; - CorCommandLine::m_ppwszActivationData = (LPWSTR*) ppwzActivationData; + GCX_PREEMP(); - // Start up the EE. - IfFailGo(Start()); + AssemblySpec spec; + spec.Init(szAssemblyName); + Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE); - Thread *pThread; - pThread = GetThread(); - if (pThread == NULL) - pThread = SetupThreadNoThrow(&hr); - if (pThread == NULL) - goto ErrExit; + // we have no signature to check so allowing calling partially trusted code + // can result in an exploit + if (!pAsm->GetSecurityDescriptor()->IsFullyTrusted()) + ThrowHR(COR_E_SECURITY); - _ASSERTE (!pThread->PreemptiveGCDisabled()); + TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName); + MethodDesc* pMD=NULL; + + if (!th.IsTypeDesc()) + { + pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique); + if (pMD == NULL) + { + // try again without the FM_Unique flag (error path) + pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default); + if (pMD != NULL) + { + // the method exists but is overloaded + ThrowHR(COR_E_AMBIGUOUSMATCH); + } + } + } - hr = S_OK; + if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables()) + ThrowHR(COR_E_MISSINGMETHOD); - BEGIN_ENTRYPOINT_THROWS_WITH_THREAD(pThread); - ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD) + // the target method must be decorated with AllowReversePInvokeCallsAttribute + if (!COMDelegate::IsMethodAllowedToSinkReversePInvoke(pMD)) + ThrowHR(COR_E_SECURITY); - SystemDomain::ActivateApplication(pReturnValue); + UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD); + *fnPtr = (INT_PTR)pUMEntryThunk->GetCode(); END_DOMAIN_TRANSITION; - END_ENTRYPOINT_THROWS_WITH_THREAD; -ErrExit: + END_EXTERNAL_ENTRYPOINT; + + END_ENTRYPOINT_NOTHROW; + return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif } -#ifdef FEATURE_CORECLR -/* - * This method processes the arguments sent to the host which are then used - * to invoke the main method. - * Note - - * [0] - points to the assemblyName that has been sent by the host. - * The rest are the arguments sent to the assembly. - * Also note, this might not always return the exact same identity as the cmdLine - * used to invoke the method. - * - * For example :- - * ActualCmdLine - Foo arg1 arg2. - * (Host1) - Full_path_to_Foo arg1 arg2 -*/ -void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) +HRESULT CorHost2::CreateAppDomainWithManager( + LPCWSTR wszFriendlyName, + DWORD dwFlags, + LPCWSTR wszAppDomainManagerAssemblyName, + LPCWSTR wszAppDomainManagerTypeName, + int nProperties, + LPCWSTR* pPropertyNames, + LPCWSTR* pPropertyValues, + DWORD* pAppDomainID) { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; + WRAPPER_NO_CONTRACT; - struct _gc - { - PTRARRAYREF cmdLineArgs; - } gc; + return _CreateAppDomain( + wszFriendlyName, + dwFlags, + wszAppDomainManagerAssemblyName, + wszAppDomainManagerTypeName, + nProperties, + pPropertyNames, + pPropertyValues, + pAppDomainID); +} - ZeroMemory(&gc, sizeof(gc)); - GCPROTECT_BEGIN(gc); +HRESULT CorHost2::CreateDelegate( + DWORD appDomainID, + LPCWSTR wszAssemblyName, + LPCWSTR wszClassName, + LPCWSTR wszMethodName, + INT_PTR* fnPtr) +{ + WRAPPER_NO_CONTRACT; - gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); - OBJECTREF orAssemblyPath = StringObject::NewString(pwzAssemblyPath); - gc.cmdLineArgs->SetAt(0, orAssemblyPath); + return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr); +} - for (int i = 0; i < argc; ++i) +HRESULT CorHost2::Authenticate(ULONGLONG authKey) +{ + CONTRACTL { - OBJECTREF argument = StringObject::NewString(argv[i]); - gc.cmdLineArgs->SetAt(i + 1, argument); + NOTHROW; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } + CONTRACTL_END; - MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS); + // Host authentication was used by Silverlight. It is no longer relevant for CoreCLR. + return S_OK; +} - ARG_SLOT args[] = +HRESULT CorHost2::RegisterMacEHPort() +{ + CONTRACTL { - ObjToArgSlot(gc.cmdLineArgs), - }; - setCmdLineArgs.Call(args); + NOTHROW; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. + } + CONTRACTL_END; - GCPROTECT_END(); + return S_OK; } -HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, - LPCWSTR pwzAssemblyPath, - int argc, - LPCWSTR* argv, - DWORD *pReturnValue) +HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag) { CONTRACTL { - THROWS; // Throws...as we do not want it to swallow the managed exception - ENTRY_POINT; + NOTHROW; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } CONTRACTL_END; - // This is currently supported in default domain only - if (dwAppDomainId != DefaultADID) + if (g_fEEStarted) + { return HOST_E_INVALIDOPERATION; + } - // No point going further if the runtime is not running... - if (!IsRuntimeActive() || !m_fStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - if(!pwzAssemblyPath) - return E_POINTER; + m_dwStartupFlags = flag; - if(argc < 0) - { - return E_INVALIDARG; - } + return S_OK; +} - if(argc > 0 && argv == NULL) + + +HRESULT SuspendEEForPause() +{ + CONTRACTL { - return E_INVALIDARG; + NOTHROW; + MODE_PREEMPTIVE; + GC_TRIGGERS; } + CONTRACTL_END; HRESULT hr = S_OK; - AppDomain *pCurDomain = SystemDomain::GetCurrentDomain(); + // In CoreCLR, we always resume from the same thread that paused. So we can simply suspend the EE from this thread, + // knowing we'll restart from the same thread. + ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER); - Thread *pThread = GetThread(); - if (pThread == NULL) + return hr; +} + +HRESULT RestartEEFromPauseAndSetResumeEvent() +{ + CONTRACTL { - pThread = SetupThreadNoThrow(&hr); - if (pThread == NULL) - { - goto ErrExit; - } + NOTHROW; + MODE_PREEMPTIVE; + GC_TRIGGERS; } + CONTRACTL_END; - if(pCurDomain->GetId().m_dwId != DefaultADID) + // see comments in SuspendEEFromPause + ThreadSuspend::RestartEE(FALSE, TRUE); + + _ASSERTE(g_ClrResumeEvent.IsValid()); + g_ClrResumeEvent.Set(); + + return S_OK; +} + + + +CorExecutionManager::CorExecutionManager() + : m_dwFlags(0), m_pauseStartTime(0) +{ + LIMITED_METHOD_CONTRACT; + g_IsPaused = FALSE; + g_PauseTime = 0; +} + +HRESULT CorExecutionManager::Pause(DWORD dwAppDomainId, DWORD dwFlags) +{ + CONTRACTL { - return HOST_E_INVALIDOPERATION; + NOTHROW; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } + CONTRACTL_END; - INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - - _ASSERTE (!pThread->PreemptiveGCDisabled()); + HRESULT hr = S_OK; - Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); -#if defined(FEATURE_MULTICOREJIT) - pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain); -#endif // defined(FEATURE_MULTICOREJIT) + if(g_IsPaused) + return E_FAIL; + EX_TRY { - GCX_COOP(); + if(!g_ClrResumeEvent.IsValid()) + g_ClrResumeEvent.CreateManualEvent(FALSE); + else + g_ClrResumeEvent.Reset(); - // Here we call the managed method that gets the cmdLineArgs array. - SetCommandLineArgs(pwzAssemblyPath, argc, argv); + } + EX_CATCH_HRESULT(hr); + + if (FAILED(hr)) + return hr; + + BEGIN_ENTRYPOINT_NOTHROW; - PTRARRAYREF arguments = NULL; - GCPROTECT_BEGIN(arguments); + m_dwFlags = dwFlags; - arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass); - for (int i = 0; i < argc; ++i) - { - STRINGREF argument = StringObject::NewString(argv[i]); - arguments->SetAt(i, argument); - } - DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */); - if (pReturnValue) - { - *pReturnValue = retval; - } + if (SUCCEEDED(hr)) + { + g_IsPaused = TRUE; - GCPROTECT_END(); + hr = SuspendEEForPause(); + // Even though this is named with TickCount, it returns milliseconds + m_pauseStartTime = (INT64)CLRGetTickCount64(); } - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; - -ErrExit: + END_ENTRYPOINT_NOTHROW; return hr; } -#endif -HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath, - LPCWSTR pwzTypeName, - LPCWSTR pwzMethodName, - LPCWSTR pwzArgument, - DWORD *pReturnValue) + +HRESULT CorExecutionManager::Resume(DWORD dwAppDomainId) { CONTRACTL { NOTHROW; - ENTRY_POINT; + if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} + ENTRY_POINT; // This is called by a host. } CONTRACTL_END; - // No point going further if the runtime is not running... - if (!IsRuntimeActive() -#ifdef FEATURE_CORECLR - || !m_fStarted -#endif - ) - { - return HOST_E_CLRNOTAVAILABLE; - } - - -#ifndef FEATURE_CORECLR - if(! (pwzAssemblyPath && pwzTypeName && pwzMethodName) ) - return E_POINTER; - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; + if(!g_IsPaused) + return E_FAIL; + + // GCThread is the thread that did the Pause. Resume should also happen on that same thread Thread *pThread = GetThread(); - if (pThread == NULL) + if(pThread != ThreadSuspend::GetSuspensionThread()) { - pThread = SetupThreadNoThrow(&hr); - if (pThread == NULL) - { - goto ErrExit; - } + _ASSERTE(!"HOST BUG: The same thread that did Pause should do the Resume"); + return E_FAIL; } - _ASSERTE (!pThread->PreemptiveGCDisabled()); + BEGIN_ENTRYPOINT_NOTHROW; - EX_TRY - { - ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD) + // Even though this is named with TickCount, it returns milliseconds + INT64 currTime = (INT64)CLRGetTickCount64(); + _ASSERTE(currTime >= m_pauseStartTime); + _ASSERTE(m_pauseStartTime != 0); - INSTALL_UNWIND_AND_CONTINUE_HANDLER; + g_PauseTime += (currTime - m_pauseStartTime); + g_IsPaused = FALSE; - Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); + hr = RestartEEFromPauseAndSetResumeEvent(); - SString szTypeName(pwzTypeName); - StackScratchBuffer buff1; - const char* szTypeNameUTF8 = szTypeName.GetUTF8(buff1); - MethodTable *pMT = ClassLoader::LoadTypeByNameThrowing(pAssembly, - NULL, - szTypeNameUTF8).AsMethodTable(); - SString szMethodName(pwzMethodName); - StackScratchBuffer buff; - const char* szMethodNameUTF8 = szMethodName.GetUTF8(buff); - MethodDesc *pMethodMD = MemberLoader::FindMethod(pMT, szMethodNameUTF8, &gsig_SM_Str_RetInt); + END_ENTRYPOINT_NOTHROW; - if (!pMethodMD) - { - hr = COR_E_MISSINGMETHOD; - } - else - { - GCX_COOP(); + return hr; +} + + +#endif //!DACCESS_COMPILE - MethodDescCallSite method(pMethodMD); +#ifndef DACCESS_COMPILE +SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags = STARTUP_CONCURRENT_GC); +#else +SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags); +#endif - STRINGREF sref = NULL; - GCPROTECT_BEGIN(sref); +STARTUP_FLAGS CorHost2::GetStartupFlags() +{ + return m_dwStartupFlags; +} - if (pwzArgument) - sref = StringObject::NewString(pwzArgument); +#ifndef DACCESS_COMPILE - ARG_SLOT MethodArgs[] = - { - ObjToArgSlot(sref) - }; - DWORD retval = method.Call_RetI4(MethodArgs); - if (pReturnValue) - { - *pReturnValue = retval; - } - GCPROTECT_END(); +#ifdef FEATURE_COMINTEROP + +// Enumerate currently existing domains. +HRESULT CorRuntimeHostBase::EnumDomains(HDOMAINENUM *hEnum) +{ + CONTRACTL + { + NOTHROW; + MODE_PREEMPTIVE; + WRAPPER(GC_TRIGGERS); + ENTRY_POINT; } + CONTRACTL_END; - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - END_DOMAIN_TRANSITION; + if(hEnum == NULL) return E_POINTER; + + // Thread setup happens in BEGIN_EXTERNAL_ENTRYPOINT below. + // If the runtime has not started, we have nothing to do. + if (!g_fEEStarted) + { + return HOST_E_CLRNOTAVAILABLE; } - EX_CATCH_HRESULT(hr); -ErrExit: + HRESULT hr = E_OUTOFMEMORY; + *hEnum = NULL; + BEGIN_ENTRYPOINT_NOTHROW; + + BEGIN_EXTERNAL_ENTRYPOINT(&hr) + AppDomainIterator *pEnum = new (nothrow) AppDomainIterator(FALSE); + if(pEnum) { + *hEnum = (HDOMAINENUM) pEnum; + hr = S_OK; + } + END_EXTERNAL_ENTRYPOINT; END_ENTRYPOINT_NOTHROW; return hr; -#else // FEATURE_CORECLR - // Ensure that code is not loaded in the Default AppDomain - return HOST_E_INVALIDOPERATION; -#endif } -HRESULT ExecuteInAppDomainHelper(FExecuteInAppDomainCallback pCallback, - void * cookie) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_SO_INTOLERANT; - - HRESULT hr = S_OK; +#endif // FEATURE_COMINTEROP - BEGIN_SO_TOLERANT_CODE(GetThread()); - hr = pCallback(cookie); - END_SO_TOLERANT_CODE; +extern "C" +HRESULT GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk) +{ + WRAPPER_NO_CONTRACT; - return hr; + return CorHost2::CreateObject(riid, (void**)ppUnk); } -HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId, - FExecuteInAppDomainCallback pCallback, - void * cookie) + +STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) { + WRAPPER_NO_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; - // No point going further if the runtime is not running... - if (!IsRuntimeActive() -#ifdef FEATURE_CORECLR - || !m_fStarted -#endif // FEATURE_CORECLR - ) - { - return HOST_E_CLRNOTAVAILABLE; - } + if (!m_fStarted) + return HOST_E_INVALIDOPERATION; -#ifdef FEATURE_CORECLR - if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) + if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) { - // Ensure that code is not loaded in the Default AppDomain - if (dwAppDomainId == DefaultADID) - return HOST_E_INVALIDOPERATION; + if (!g_fEEStarted) + { + return HOST_E_CLRNOTAVAILABLE; + } + + if(!m_fAppDomainCreated) + { + return HOST_E_INVALIDOPERATION; + } + + HRESULT hr=S_OK; + BEGIN_ENTRYPOINT_NOTHROW; + + if (!m_fFirstToLoadCLR) + { + _ASSERTE(!"Not reachable"); + hr = HOST_E_CLRNOTAVAILABLE; + } + else + { + LONG refCount = m_RefCount; + if (refCount == 0) + { + hr = HOST_E_CLRNOTAVAILABLE; + } + else + if (1 == refCount) + { + // Stop coreclr on unload. + m_fStarted = FALSE; + EEShutDown(FALSE); + } + else + { + _ASSERTE(!"Not reachable"); + hr = S_FALSE; + } + } + END_ENTRYPOINT_NOTHROW; + + return hr; } -#endif // FEATURE_CORECLR + else - // Moved this here since no point validating the pointer - // if the basic checks [above] fail - if( pCallback == NULL) - return E_POINTER; + return CorRuntimeHostBase::UnloadAppDomain(dwDomainId, fWaitUntilDone); +} +HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fSync) +{ CONTRACTL { NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. + GC_TRIGGERS; + MODE_ANY; + FORBID_FAULT; // Unloading domains cannot fail due to OOM + ENTRY_POINT; } CONTRACTL_END; HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - ENTER_DOMAIN_ID(ADID(dwAppDomainId)) + // No point going further if the runtime is not running... { - // We are calling an unmanaged function pointer, either an unmanaged function, or a marshaled out delegate. - // The thread should be in preemptive mode, and SO_Tolerant. - GCX_PREEMP(); - hr=ExecuteInAppDomainHelper (pCallback, cookie); + // In IsRuntimeActive, we will call CanRunManagedCode that will + // check if the current thread has taken the loader lock or not, + // if MDA is supported. To do the check, MdaLoaderLock::ReportViolation + // will be invoked that will internally end up invoking + // MdaFactory::GetNext that will use the "new" operator + // that has the "FAULT" contract set, resulting in FAULT_VIOLATION since + // this method has the FORBID_FAULT contract set above. + // + // However, for a thread that holds the loader lock, unloading the appDomain is + // not a supported scenario. Thus, we should not be ending up in this code + // path for the FAULT violation. + // + // Hence, the CONTRACT_VIOLATION below for overriding the FORBID_FAULT + // for this scope only. + CONTRACT_VIOLATION(FaultViolation); + if (!IsRuntimeActive() + || !m_fStarted + ) + { + return HOST_E_CLRNOTAVAILABLE; + } } - END_DOMAIN_TRANSITION; - END_EXTERNAL_ENTRYPOINT; + + BEGIN_ENTRYPOINT_NOTHROW; + + // We do not use BEGIN_EXTERNAL_ENTRYPOINT here because + // we do not want to setup Thread. Process may be OOM, and we want Unload + // to work. + hr = AppDomain::UnloadById(ADID(dwDomainId), fSync); + END_ENTRYPOINT_NOTHROW; return hr; } -#define EMPTY_STRING_TO_NULL(s) {if(s && s[0] == 0) {s=NULL;};} +//***************************************************************************** +// Fiber Methods +//***************************************************************************** -HRESULT CorHost2::_CreateAppDomain( - LPCWSTR wszFriendlyName, - DWORD dwFlags, - LPCWSTR wszAppDomainManagerAssemblyName, - LPCWSTR wszAppDomainManagerTypeName, - int nProperties, - LPCWSTR* pPropertyNames, - LPCWSTR* pPropertyValues, -#if !defined(FEATURE_CORECLR) - ICLRPrivBinder* pBinder, -#endif - DWORD* pAppDomainID) +HRESULT CorRuntimeHostBase::LocksHeldByLogicalThread(DWORD *pCount) { + if (!pCount) + return E_POINTER; + CONTRACTL { NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. - } - CONTRACTL_END; - - HRESULT hr=S_OK; - -#ifdef FEATURE_CORECLR - //cannot call the function more than once when single appDomain is allowed - if (m_fAppDomainCreated && (m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) - { - return HOST_E_INVALIDOPERATION; + GC_NOTRIGGER; + ENTRY_POINT; } -#endif - - //normalize empty strings - EMPTY_STRING_TO_NULL(wszFriendlyName); - EMPTY_STRING_TO_NULL(wszAppDomainManagerAssemblyName); - EMPTY_STRING_TO_NULL(wszAppDomainManagerTypeName); - - if(pAppDomainID==NULL) - return E_POINTER; - -#ifdef FEATURE_CORECLR - if (!m_fStarted) - return HOST_E_INVALIDOPERATION; -#endif // FEATURE_CORECLR - - if(wszFriendlyName == NULL) - return E_INVALIDARG; - - if((wszAppDomainManagerAssemblyName == NULL) != (wszAppDomainManagerTypeName == NULL)) - return E_INVALIDARG; + CONTRACTL_END; BEGIN_ENTRYPOINT_NOTHROW; - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - - AppDomainCreationHolder pDomain; - -#ifdef FEATURE_CORECLR - // If StartupFlag specifies single appDomain then return the default domain instead of creating new one - if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) - { - pDomain.Assign(SystemDomain::System()->DefaultDomain()); - } + Thread* pThread = GetThread(); + if (pThread == NULL) + *pCount = 0; else -#endif - { - AppDomain::CreateUnmanagedObject(pDomain); - } + *pCount = pThread->m_dwLockCount; - ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName); + END_ENTRYPOINT_NOTHROW; -#ifdef FEATURE_CORECLR - if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS) - { - pDomain->SetIgnoreUnhandledExceptions(); - } -#endif // FEATURE_CORECLR + return S_OK; +} - if (dwFlags & APPDOMAIN_SECURITY_FORBID_CROSSAD_REVERSE_PINVOKE) - pDomain->SetReversePInvokeCannotEnter(); +//***************************************************************************** +// ICorConfiguration +//***************************************************************************** - if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS) - pDomain->SetForceTrivialWaitOperations(); +//***************************************************************************** +// IUnknown +//***************************************************************************** -#if !defined(FEATURE_CORECLR) - if (pBinder != NULL) - pDomain->SetLoadContextHostBinder(pBinder); -#endif - -#ifdef PROFILING_SUPPORTED - EX_TRY -#endif +ULONG CorRuntimeHostBase::AddRef() +{ + CONTRACTL { - pDomain->SetAppDomainManagerInfo(wszAppDomainManagerAssemblyName,wszAppDomainManagerTypeName,eInitializeNewDomainFlags_None); + WRAPPER(THROWS); + WRAPPER(GC_TRIGGERS); + SO_TOLERANT; + } + CONTRACTL_END; + return InterlockedIncrement(&m_cRef); +} - GCX_COOP(); - - struct - { - STRINGREF friendlyName; - PTRARRAYREF propertyNames; - PTRARRAYREF propertyValues; - STRINGREF sandboxName; - OBJECTREF setupInfo; - OBJECTREF adSetup; - } _gc; - ZeroMemory(&_gc,sizeof(_gc)); +ULONG CorHost2::Release() +{ + LIMITED_METHOD_CONTRACT; - GCPROTECT_BEGIN(_gc) - _gc.friendlyName=StringObject::NewString(wszFriendlyName); - - if(nProperties>0) - { - _gc.propertyNames = (PTRARRAYREF) AllocateObjectArray(nProperties, g_pStringClass); - _gc.propertyValues= (PTRARRAYREF) AllocateObjectArray(nProperties, g_pStringClass); - for (int i=0;i< nProperties;i++) - { - STRINGREF obj = StringObject::NewString(pPropertyNames[i]); - _gc.propertyNames->SetAt(i, obj); - - obj = StringObject::NewString(pPropertyValues[i]); - _gc.propertyValues->SetAt(i, obj); - } - } + ULONG cRef = InterlockedDecrement(&m_cRef); + if (!cRef) { +#ifdef FEATURE_INCLUDE_ALL_INTERFACES + // CorHost2 is allocated before host memory interface is set up. + if (GetHostMemoryManager() == NULL) +#endif // FEATURE_INCLUDE_ALL_INTERFACES + delete this; + } - if (dwFlags & APPDOMAIN_SECURITY_SANDBOXED) - { - _gc.sandboxName = StringObject::NewString(W("Internet")); - } - else - { - _gc.sandboxName = StringObject::NewString(W("FullTrust")); - } + return (cRef); +} - MethodDescCallSite prepareDataForSetup(METHOD__APP_DOMAIN__PREPARE_DATA_FOR_SETUP); - ARG_SLOT args[8]; - args[0]=ObjToArgSlot(_gc.friendlyName); - args[1]=ObjToArgSlot(NULL); - args[2]=ObjToArgSlot(NULL); - args[3]=ObjToArgSlot(NULL); -#ifdef FEATURE_CORECLR - //CoreCLR shouldn't have dependencies on parent app domain. - args[4]=ObjToArgSlot(NULL); -#else - args[4]=PtrToArgSlot(GetAppDomain()->GetSecurityDescriptor()); -#endif //FEATURE_CORECLR - args[5]=ObjToArgSlot(_gc.sandboxName); - args[6]=ObjToArgSlot(_gc.propertyNames); - args[7]=ObjToArgSlot(_gc.propertyValues); - _gc.setupInfo=prepareDataForSetup.Call_RetOBJECTREF(args); +HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk) +{ + if (!ppUnk) + return E_POINTER; - // - // Get the new flag values and set it to the domain - // - PTRARRAYREF handleArrayObj = (PTRARRAYREF) ObjectToOBJECTREF(_gc.setupInfo); - _gc.adSetup = ObjectToOBJECTREF(handleArrayObj->GetAt(1)); + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; // no global state updates that need guarding. + } + CONTRACTL_END; -#ifndef FEATURE_CORECLR - // We need to setup domain sorting before any other managed code runs in the domain, since that code - // could end up caching data based on the sorting mode of the domain. - pDomain->InitializeSorting(&_gc.adSetup); - pDomain->InitializeHashing(&_gc.adSetup); -#endif + if (ppUnk == NULL) + { + return E_POINTER; + } - pDomain->DoSetup(&_gc.setupInfo); + *ppUnk = 0; - pDomain->CacheStringsForDAC(); - - GCPROTECT_END(); + // Deliberately do NOT hand out ICorConfiguration. They must explicitly call + // GetConfiguration to obtain that interface. + if (riid == IID_IUnknown) + *ppUnk = static_cast(static_cast(this)); + else if (riid == IID_ICLRRuntimeHost2) + { + ULONG version = 2; + if (m_Version == 0) + FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - *pAppDomainID=pDomain->GetId().m_dwId; + *ppUnk = static_cast(this); + } + else if (riid == IID_ICLRExecutionManager) + { + ULONG version = 2; + if (m_Version == 0) + FastInterlockCompareExchange((LONG*)&m_Version, version, 0); -#ifdef FEATURE_CORECLR - // If StartupFlag specifies single appDomain then set the flag that appdomain has already been created - if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) - { - m_fAppDomainCreated = TRUE; - } -#endif + *ppUnk = static_cast(this); } -#ifdef PROFILING_SUPPORTED - EX_HOOK +#ifndef FEATURE_PAL + else if (riid == IID_IPrivateManagedExceptionReporting) { - // Need the first assembly loaded in to get any data on an app domain. - { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR()); - END_PIN_PROFILER(); - } + *ppUnk = static_cast(this); } - EX_END_HOOK; +#endif // !FEATURE_PAL + else + return (E_NOINTERFACE); + AddRef(); + return (S_OK); +} - // Need the first assembly loaded in to get any data on an app domain. + +#ifndef FEATURE_PAL +HRESULT CorHost2::GetBucketParametersForCurrentException(BucketParameters *pParams) +{ + CONTRACTL { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, S_OK); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + } + CONTRACTL_END; - // DoneCreating releases ownership of AppDomain. After this call, there should be no access to pDomain. - pDomain.DoneCreating(); + HRESULT hr = S_OK; + BEGIN_ENTRYPOINT_NOTHROW; - END_EXTERNAL_ENTRYPOINT; + // To avoid confusion, clear the buckets. + memset(pParams, 0, sizeof(BucketParameters)); + + // Defer to Watson helper. + hr = ::GetBucketParametersForCurrentException(pParams); END_ENTRYPOINT_NOTHROW; return hr; +} +#endif // !FEATURE_PAL -}; - -HRESULT CorHost2::_CreateDelegate( - DWORD appDomainID, - LPCWSTR wszAssemblyName, - LPCWSTR wszClassName, - LPCWSTR wszMethodName, - INT_PTR* fnPtr) +HRESULT CorHost2::CreateObject(REFIID riid, void **ppUnk) { - CONTRACTL { NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. + GC_NOTRIGGER; + SO_TOLERANT; } CONTRACTL_END; - HRESULT hr=S_OK; - - EMPTY_STRING_TO_NULL(wszAssemblyName); - EMPTY_STRING_TO_NULL(wszClassName); - EMPTY_STRING_TO_NULL(wszMethodName); - - if (fnPtr == NULL) - return E_POINTER; - *fnPtr = NULL; - - if(wszAssemblyName == NULL) - return E_INVALIDARG; - - if(wszClassName == NULL) - return E_INVALIDARG; - - if(wszMethodName == NULL) - return E_INVALIDARG; - -#ifdef FEATURE_CORECLR - if (!m_fStarted) - return HOST_E_INVALIDOPERATION; + HRESULT hr = S_OK; - if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)) + BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW; ); + CorHost2 *pCorHost = new (nothrow) CorHost2(); + if (!pCorHost) { - // Ensure that code is not loaded in the Default AppDomain - if (appDomainID == DefaultADID) - return HOST_E_INVALIDOPERATION; + hr = E_OUTOFMEMORY; } -#endif - - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - - MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName); - MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName); - MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName); - - ADID id; - id.m_dwId=appDomainID; - - ENTER_DOMAIN_ID(id) - - GCX_PREEMP(); - - AssemblySpec spec; - spec.Init(szAssemblyName); - Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE); - - // we have no signature to check so allowing calling partially trusted code - // can result in an exploit - if (!pAsm->GetSecurityDescriptor()->IsFullyTrusted()) - ThrowHR(COR_E_SECURITY); - - TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName); - MethodDesc* pMD=NULL; - - if (!th.IsTypeDesc()) + else { - pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique); - if (pMD == NULL) - { - // try again without the FM_Unique flag (error path) - pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default); - if (pMD != NULL) - { - // the method exists but is overloaded - ThrowHR(COR_E_AMBIGUOUSMATCH); - } - } + hr = pCorHost->QueryInterface(riid, ppUnk); + if (FAILED(hr)) + delete pCorHost; } - - if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables()) - ThrowHR(COR_E_MISSINGMETHOD); - -#ifdef FEATURE_CORECLR - // the target method must be decorated with AllowReversePInvokeCallsAttribute - if (!COMDelegate::IsMethodAllowedToSinkReversePInvoke(pMD)) - ThrowHR(COR_E_SECURITY); -#endif - - UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD); - *fnPtr = (INT_PTR)pUMEntryThunk->GetCode(); - - END_DOMAIN_TRANSITION; - - END_EXTERNAL_ENTRYPOINT; - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -#ifdef FEATURE_CORECLR -HRESULT CorHost2::CreateAppDomainWithManager( - LPCWSTR wszFriendlyName, - DWORD dwFlags, - LPCWSTR wszAppDomainManagerAssemblyName, - LPCWSTR wszAppDomainManagerTypeName, - int nProperties, - LPCWSTR* pPropertyNames, - LPCWSTR* pPropertyValues, - DWORD* pAppDomainID) -{ - WRAPPER_NO_CONTRACT; - - return _CreateAppDomain( - wszFriendlyName, - dwFlags, - wszAppDomainManagerAssemblyName, - wszAppDomainManagerTypeName, - nProperties, - pPropertyNames, - pPropertyValues, - pAppDomainID); + END_SO_INTOLERANT_CODE; + return (hr); } -HRESULT CorHost2::CreateDelegate( - DWORD appDomainID, - LPCWSTR wszAssemblyName, - LPCWSTR wszClassName, - LPCWSTR wszMethodName, - INT_PTR* fnPtr) -{ - WRAPPER_NO_CONTRACT; - return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr); -} +//----------------------------------------------------------------------------- +// MapFile - Maps a file into the runtime in a non-standard way +//----------------------------------------------------------------------------- -HRESULT CorHost2::Authenticate(ULONGLONG authKey) +static PEImage *MapFileHelper(HANDLE hFile) { CONTRACTL { - NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. + THROWS; + GC_TRIGGERS; + MODE_ANY; } CONTRACTL_END; - // Host authentication was used by Silverlight. It is no longer relevant for CoreCLR. - return S_OK; -} - -HRESULT CorHost2::RegisterMacEHPort() -{ - CONTRACTL - { - NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. - } - CONTRACTL_END; + GCX_PREEMP(); - return S_OK; -} + HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)); + if (hFileMap == NULL) + ThrowLastError(); -HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag) -{ - CONTRACTL - { - NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. - } - CONTRACTL_END; + CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0)); + if (base == NULL) + ThrowLastError(); - if (g_fEEStarted) + DWORD dwSize = SafeGetFileSize(hFile, NULL); + if (dwSize == 0xffffffff && GetLastError() != NOERROR) { - return HOST_E_INVALIDOPERATION; + ThrowLastError(); } - - m_dwStartupFlags = flag; - - return S_OK; + PEImageHolder pImage(PEImage::LoadFlat(base, dwSize)); + return pImage.Extract(); } -#endif //FEATURE_CORECLR - -#ifndef FEATURE_CORECLR -void PauseOneAppDomain(AppDomainIterator* pi) +HRESULT CorRuntimeHostBase::MapFile(HANDLE hFile, HMODULE* phHandle) { CONTRACTL { NOTHROW; - MODE_COOPERATIVE; GC_TRIGGERS; + MODE_PREEMPTIVE; + ENTRY_POINT; } CONTRACTL_END; - EX_TRY { - ENTER_DOMAIN_PTR(pi->GetDomain(),ADV_ITERATOR); + HRESULT hr; + BEGIN_ENTRYPOINT_NOTHROW; + + BEGIN_EXTERNAL_ENTRYPOINT(&hr) + { + *phHandle = (HMODULE) (MapFileHelper(hFile)->GetLoadedLayout()->GetBase()); + } + END_EXTERNAL_ENTRYPOINT; + END_ENTRYPOINT_NOTHROW; - MethodDescCallSite(METHOD__APP_DOMAIN__PAUSE).Call(NULL); - END_DOMAIN_TRANSITION; - } EX_CATCH { - } EX_END_CATCH(SwallowAllExceptions); + return hr; } -void ResumeOneAppDomain(AppDomainIterator* pi) -{ - CONTRACTL - { - NOTHROW; - MODE_COOPERATIVE; - GC_TRIGGERS; - } - CONTRACTL_END; +/////////////////////////////////////////////////////////////////////////////// +// IDebuggerInfo::IsDebuggerAttached - EX_TRY { - ENTER_DOMAIN_PTR(pi->GetDomain(),ADV_ITERATOR); +LONG CorHost2::m_RefCount = 0; - MethodDescCallSite(METHOD__APP_DOMAIN__RESUME).Call(NULL); +IHostControl *CorHost2::m_HostControl = NULL; - END_DOMAIN_TRANSITION; - } EX_CATCH { - } EX_END_CATCH(SwallowAllExceptions); -} +LPCWSTR CorHost2::s_wszAppDomainManagerAsm = NULL; +LPCWSTR CorHost2::s_wszAppDomainManagerType = NULL; +EInitializeNewDomainFlags CorHost2::s_dwDomainManagerInitFlags = eInitializeNewDomainFlags_None; -// see comments in SuspendEEFromPause -DWORD WINAPI SuspendAndResumeForPause(LPVOID arg) -{ - CONTRACTL - { - NOTHROW; - MODE_ANY; - GC_TRIGGERS; - } - CONTRACTL_END; - ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER); +#ifdef _DEBUG +extern void ValidateHostInterface(); +#endif - g_PauseCompletedEvent.Set(); - g_ClrResumeEvent.Wait(INFINITE, FALSE); +// fusion's global copy of host assembly manager stuff +BOOL g_bFusionHosted = FALSE; +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +ICLRAssemblyReferenceList *g_pHostAsmList = NULL; +IHostAssemblyStore *g_pHostAssemblyStore = NULL; +#endif // FEATURE_INCLUDE_ALL_INTERFACES - ThreadSuspend::RestartEE(FALSE, TRUE); - return 0; +/*static*/ BOOL CorHost2::IsLoadFromBlocked() // LoadFrom, LoadFile and Load(byte[]) are blocked in certain hosting scenarios +{ + LIMITED_METHOD_CONTRACT; +#ifdef FEATURE_INCLUDE_ALL_INTERFACES + return (g_bFusionHosted && (g_pHostAsmList != NULL)); +#else // !FEATURE_INCLUDE_ALL_INTERFACES + return FALSE; // as g_pHostAsmList is not defined for CoreCLR; hence above expression will be FALSE. +#endif // FEATURE_INCLUDE_ALL_INTERFACES } -#endif // !FEATURE_CORECLR +static Volatile fOneOnly = 0; -HRESULT SuspendEEForPause() +/////////////////////////////////////////////////////////////////////////////// +// ICLRRuntimeHost::SetHostControl +/////////////////////////////////////////////////////////////////////////////// +HRESULT CorHost2::SetHostControl(IHostControl* pHostControl) { CONTRACTL { NOTHROW; - MODE_PREEMPTIVE; - GC_TRIGGERS; + GC_NOTRIGGER; + ENTRY_POINT; } CONTRACTL_END; + if (m_Version < 2) + // CLR is hosted with v1 hosting interface. Some part of v2 hosting API are disabled. + return HOST_E_INVALIDOPERATION; - HRESULT hr = S_OK; + if (pHostControl == 0) + return E_INVALIDARG; -#ifdef FEATURE_CORECLR - // In CoreCLR, we always resume from the same thread that paused. So we can simply suspend the EE from this thread, - // knowing we'll restart from the same thread. - ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER); -#else - // In the CLR, we can resume from a different thread than the one that paused. We can't call SuspendEE directly, - // because we can't call RestartEE from another thread. So we queue a workitem to the ThreadPool to call SuspendEE - // and ResumeEE on our behalf. - - EX_TRY - { - if (!ThreadpoolMgr::QueueUserWorkItem(SuspendAndResumeForPause, NULL, QUEUE_ONLY)) - { - hr = HRESULT_FROM_GetLastError(); - } - else - { - // wait for SuspendEE to complete before returning. - g_PauseCompletedEvent.Wait(INFINITE,FALSE); - } - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); -#endif - - return hr; -} - -HRESULT RestartEEFromPauseAndSetResumeEvent() -{ - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - GC_TRIGGERS; - } - CONTRACTL_END; - - // see comments in SuspendEEFromPause -#ifdef FEATURE_CORECLR - ThreadSuspend::RestartEE(FALSE, TRUE); -#else - // setting the resume event below will restart the EE as well. We don't wait for the restart - // to complete, because we'll sync with it next time we go to cooperative mode. -#endif - - _ASSERTE(g_ClrResumeEvent.IsValid()); - g_ClrResumeEvent.Set(); - - return S_OK; -} - - - -CorExecutionManager::CorExecutionManager() - : m_dwFlags(0), m_pauseStartTime(0) -{ - LIMITED_METHOD_CONTRACT; - g_IsPaused = FALSE; - g_PauseTime = 0; -} - -HRESULT CorExecutionManager::Pause(DWORD dwAppDomainId, DWORD dwFlags) -{ - CONTRACTL - { - NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. - } - CONTRACTL_END; - - HRESULT hr = S_OK; - -#ifndef FEATURE_CORECLR - if (!IsRuntimeActive()) - return HOST_E_CLRNOTAVAILABLE; -#endif - - if(g_IsPaused) - return E_FAIL; - - EX_TRY - { - if(!g_ClrResumeEvent.IsValid()) - g_ClrResumeEvent.CreateManualEvent(FALSE); - else - g_ClrResumeEvent.Reset(); - -#ifndef FEATURE_CORECLR - if (!g_PauseCompletedEvent.IsValid()) - g_PauseCompletedEvent.CreateManualEvent(FALSE); - else - g_PauseCompletedEvent.Reset(); -#endif - } - EX_CATCH_HRESULT(hr); - - if (FAILED(hr)) - return hr; - - BEGIN_ENTRYPOINT_NOTHROW; - - m_dwFlags = dwFlags; - -#ifndef FEATURE_CORECLR - if ((m_dwFlags & PAUSE_APP_DOMAINS) != 0) - { - Thread* pThread = SetupThreadNoThrow(&hr); - if (pThread != NULL) - { - GCX_COOP_THREAD_EXISTS(pThread); - - AppDomainIterator ai(/*bOnlyActive:*/ TRUE); - while (ai.Next()) - PauseOneAppDomain(&ai); - } - } -#endif - - if (SUCCEEDED(hr)) - { - g_IsPaused = TRUE; - - hr = SuspendEEForPause(); - - // Even though this is named with TickCount, it returns milliseconds - m_pauseStartTime = (INT64)CLRGetTickCount64(); - } - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - - -HRESULT CorExecutionManager::Resume(DWORD dwAppDomainId) -{ - CONTRACTL - { - NOTHROW; - if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} - ENTRY_POINT; // This is called by a host. - } - CONTRACTL_END; - - HRESULT hr = S_OK; - -#ifndef FEATURE_CORECLR - if (!IsRuntimeActive()) - return HOST_E_CLRNOTAVAILABLE; -#endif - - if(!g_IsPaused) - return E_FAIL; - -#ifdef FEATURE_CORECLR - // GCThread is the thread that did the Pause. Resume should also happen on that same thread - Thread *pThread = GetThread(); - if(pThread != ThreadSuspend::GetSuspensionThread()) - { - _ASSERTE(!"HOST BUG: The same thread that did Pause should do the Resume"); - return E_FAIL; - } -#endif - - BEGIN_ENTRYPOINT_NOTHROW; - - // Even though this is named with TickCount, it returns milliseconds - INT64 currTime = (INT64)CLRGetTickCount64(); - _ASSERTE(currTime >= m_pauseStartTime); - _ASSERTE(m_pauseStartTime != 0); - - g_PauseTime += (currTime - m_pauseStartTime); - g_IsPaused = FALSE; - - hr = RestartEEFromPauseAndSetResumeEvent(); - -#ifndef FEATURE_CORECLR - if (SUCCEEDED(hr)) - { - if ((m_dwFlags & PAUSE_APP_DOMAINS) != 0) - { - Thread* pThread = SetupThreadNoThrow(&hr); - if (pThread != NULL) - { - GCX_COOP_THREAD_EXISTS(pThread); - - AppDomainIterator ai(/*bOnlyActive:*/ TRUE); - while (ai.Next()) - ResumeOneAppDomain(&ai); - } - } - } -#endif - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - - -#endif //!DACCESS_COMPILE - -#ifdef FEATURE_CORECLR -#ifndef DACCESS_COMPILE -SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags = STARTUP_CONCURRENT_GC); -#else -SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags); -#endif - -STARTUP_FLAGS CorHost2::GetStartupFlags() -{ - return m_dwStartupFlags; -} -#endif //FEATURE_CORECLR - -#ifndef DACCESS_COMPILE - -#if !defined(FEATURE_CORECLR) -/************************************************************************************* - ** ICLRPrivRuntime Methods - *************************************************************************************/ - -HRESULT CorHost2::GetInterface( - REFCLSID rclsid, - REFIID riid, - LPVOID * ppUnk) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - HRESULT hr = S_OK; - - EX_TRY - { - if (rclsid == __uuidof(CLRPrivAppXBinder)) - { - CLRPrivBinderAppX * pBinder = CLRPrivBinderAppX::GetOrCreateBinder(); - hr = pBinder->QueryInterface(riid, ppUnk); - } - else - { - hr = E_NOINTERFACE; - } - } - EX_CATCH_HRESULT(hr); - - return hr; -} - -HRESULT CorHost2::CreateAppDomain( - LPCWSTR pwzFriendlyName, - ICLRPrivBinder * pBinder, - LPDWORD pdwAppDomainId) -{ - return _CreateAppDomain( - pwzFriendlyName, - 0 /* default security */, - nullptr, /* domain manager */ - nullptr, /* domain manager */ - 0, /* property count */ - nullptr, /* property names */ - nullptr, /* property values */ - pBinder, - pdwAppDomainId); -} - -HRESULT CorHost2::CreateDelegate( - DWORD appDomainID, - LPCWSTR wszAssemblyName, - LPCWSTR wszClassName, - LPCWSTR wszMethodName, - LPVOID * ppvDelegate) -{ - return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, - wszMethodName, reinterpret_cast(ppvDelegate)); -} - -// Flag indicating if the EE was started up by an managed exe. Defined in ceemain.cpp. -extern BOOL g_fEEManagedEXEStartup; + // If Runtime has been started, do not allow setting HostMemoryManager + if (g_fEEStarted) + return E_ACCESSDENIED; -HRESULT CorHost2::ExecuteMain( - ICLRPrivBinder * pBinder, - int * pRetVal) -{ - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_ENTRY_POINT; - HRESULT hr = S_OK; - // If an exception passes through here, it will cause the - // "The application has generated an unhandled exception" dialog and offer to debug. - BEGIN_ENTRYPOINT_THROWS; - - // Indicates that the EE was started up by a managed exe. - g_fEEManagedEXEStartup = TRUE; - - IfFailGo(CorCommandLine::SetArgvW(WszGetCommandLine())); - - IfFailGo(EnsureEEStarted(COINITEE_MAIN)); - - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - - // - // Look for the [STAThread] or [MTAThread] attribute - // TODO delete this code when we move to the default AppDomain - // - HMODULE hMod = WszGetModuleHandle(NULL); - - PEImageHolder pTempImage(PEImage::LoadImage(hMod)); - PEFileHolder pTempFile(PEFile::Open(pTempImage.Extract())); - - // Check for CustomAttributes - Set up the DefaultDomain and the main thread - // Note that this has to be done before ExplicitBind() as it - // affects the bind - mdToken tkEntryPoint = pTempFile->GetEntryPointToken(); - // @TODO: What if the entrypoint is in another file of the assembly? - ReleaseHolder scope(pTempFile->GetMDImportWithRef()); - // In theory, we should have a valid executable image and scope should never be NULL, but we've been - // getting Watson failures for AVs here due to ISVs modifying image headers and some new OS loader - // checks (see Dev10# 718530 and Windows 7# 615596) - if (scope == NULL) - { - ThrowHR(COR_E_BADIMAGEFORMAT); - } - - Thread::ApartmentState state = Thread::AS_Unknown; - - if((!IsNilToken(tkEntryPoint)) && (TypeFromToken(tkEntryPoint) == mdtMethodDef)) { - if (scope->IsValidToken(tkEntryPoint)) - state = SystemDomain::GetEntryPointThreadAptState(scope, tkEntryPoint); - else - ThrowHR(COR_E_BADIMAGEFORMAT); - } - - BOOL fSetGlobalSharePolicyUsingAttribute = FALSE; - - if((!IsNilToken(tkEntryPoint)) && (TypeFromToken(tkEntryPoint) == mdtMethodDef)) - { - // The global share policy needs to be set before initializing default domain - // so that it is in place for loading of appdomain manager. - fSetGlobalSharePolicyUsingAttribute = SystemDomain::SetGlobalSharePolicyUsingAttribute(scope, tkEntryPoint); - } - - // If the entry point has an explicit thread apartment state, set it - // before running the AppDomainManager initialization code. - if (state == Thread::AS_InSTA || state == Thread::AS_InMTA) - SystemDomain::SetThreadAptState(scope, state); - - // This can potentially run managed code. - SystemDomain::InitializeDefaultDomain(FALSE, pBinder); - - // If we haven't set an explicit thread apartment state, set it after the - // AppDomainManager has got a chance to go set it in InitializeNewDomain. - if (state != Thread::AS_InSTA && state != Thread::AS_InMTA) - SystemDomain::SetThreadAptState(scope, state); - - if (fSetGlobalSharePolicyUsingAttribute) - SystemDomain::System()->DefaultDomain()->SetupLoaderOptimization(g_dwGlobalSharePolicy); - - ADID adId(DefaultADID); - - GCX_COOP(); - - ENTER_DOMAIN_ID(adId) - TESTHOOKCALL(EnteredAppDomain(adId.m_dwId)); - { - GCX_PREEMP(); - - AppDomain *pDomain = GetAppDomain(); - _ASSERTE(pDomain); - - PathString wzExeFileName; - - if (WszGetModuleFileName(nullptr, wzExeFileName) == 0) - IfFailThrow(E_UNEXPECTED); - - LPWSTR wzExeSimpleFileName = nullptr; - size_t cchExeSimpleFileName = 0; - SplitPathInterior( - wzExeFileName, - nullptr, nullptr, // drive - nullptr, nullptr, // dir - (LPCWSTR*)&wzExeSimpleFileName, &cchExeSimpleFileName, // filename - nullptr, nullptr); // ext - - // Remove the extension - wzExeSimpleFileName[cchExeSimpleFileName] = W('\0'); - - ReleaseHolder pAssemblyName; - IfFailThrow(CreateAssemblyNameObject( - &pAssemblyName, // Returned IAssemblyName - wzExeSimpleFileName, // Name of assembly - CANOF_PARSE_DISPLAY_NAME, // Parse as display name - nullptr)); // Reserved - - AssemblySpec specExe; - specExe.InitializeSpec(pAssemblyName, nullptr, false); - - PEAssemblyHolder pPEAssembly = pDomain->BindAssemblySpec(&specExe, TRUE, FALSE); - - pDomain->SetRootAssembly(pDomain->LoadAssembly(NULL, pPEAssembly, FILE_ACTIVE)); - - LOG((LF_CLASSLOADER | LF_CORDB, - LL_INFO10, - "Created domain for an executable at %p\n", - (pDomain->GetRootAssembly()? pDomain->GetRootAssembly()->Parent() : NULL))); - TESTHOOKCALL(RuntimeStarted(RTS_CALLINGENTRYPOINT)); - - // Set the friendly name to indicate that this is an immersive domain. - pDomain->SetFriendlyName(W("Immersive Application Domain"), TRUE); - - // Execute the main method - // NOTE: we call the entry point with our entry point exception filter active - // after the AppDomain transition which is a bit different from classic apps. - // this is so that we have the correct context when notifying the debugger - // or invoking WER on the main thread and mimics the behavior of classic apps. - // the assumption is that AppX entry points are always invoked post-AD transition. - ExecuteMainInner(pDomain->GetRootAssembly()); - - // Get the global latched exit code instead of the return value from ExecuteMainMethod - // because in the case of a "void Main" method the return code is always 0, - // while the latched exit code is set in either case. - *pRetVal = GetLatchedExitCode(); - } - END_DOMAIN_TRANSITION; - TESTHOOKCALL(LeftAppDomain(adId.m_dwId)); - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - -ErrExit: - END_ENTRYPOINT_THROWS; - - return hr; -} - -VOID CorHost2::ExecuteMainInner(Assembly* pRootAssembly) -{ - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_ENTRY_POINT; - - struct Param - { - Assembly* pRootAssembly; - } param; - - param.pRootAssembly = pRootAssembly; - - PAL_TRY(Param*, pParam, ¶m) - { - // since this is the thread 0 entry point for AppX apps we use - // the EntryPointFilter so that an unhandled exception here will - // trigger the same behavior as in classic apps. - pParam->pRootAssembly->ExecuteMainMethod(NULL, TRUE /* waitForOtherThreads */); - } - PAL_EXCEPT_FILTER(EntryPointFilter) - { - LOG((LF_STARTUP, LL_INFO10, "EntryPointFilter returned EXCEPTION_EXECUTE_HANDLER!")); - } - PAL_ENDTRY -} - -// static -HRESULT CorHost2::SetFlagsAndHostConfig(STARTUP_FLAGS dwStartupFlags, LPCWSTR pwzHostConfigFile, BOOL fFinalize) -{ - WRAPPER_NO_CONTRACT; - - HRESULT hr = E_INVALIDARG; - - if (pwzHostConfigFile == NULL) - pwzHostConfigFile = W(""); - - DangerousNonHostedSpinLockHolder lockHolder(&m_FlagsLock); - - if (m_dwFlagsFinalized) - { - // verify that flags and config file are the same - if (dwStartupFlags == m_dwStartupFlags && - _wcsicmp(pwzHostConfigFile, m_wzHostConfigFile) == 0) - { - hr = S_OK; - } - } - else - { - // overwrite the flags and config with the incoming values - if (wcslen(pwzHostConfigFile) < COUNTOF(m_wzHostConfigFile)) - { - VERIFY(wcscpy_s(m_wzHostConfigFile, COUNTOF(m_wzHostConfigFile), pwzHostConfigFile) == 0); - - // If they asked for the server gc but only have one processor, deny that option. - // Keep this in sync with shim logic in ComputeStartupFlagsAndFlavor that also switches to - // the workstation GC on uniprocessor boxes. - if (g_SystemInfo.dwNumberOfProcessors == 1 && (dwStartupFlags & STARTUP_SERVER_GC)) - dwStartupFlags = (STARTUP_FLAGS)(dwStartupFlags & ~(STARTUP_SERVER_GC | STARTUP_CONCURRENT_GC)); - - m_dwStartupFlags = dwStartupFlags; - - if (fFinalize) - m_dwFlagsFinalized = TRUE; - - hr = S_OK; - } - } - - return hr; -} - -// static -STARTUP_FLAGS CorHost2::GetStartupFlags() -{ - WRAPPER_NO_CONTRACT; - - if (!m_dwFlagsFinalized) // make sure we return consistent results - { - DangerousNonHostedSpinLockHolder lockHolder(&m_FlagsLock); - m_dwFlagsFinalized = TRUE; - } - - return m_dwStartupFlags; -} - -// static -LPCWSTR CorHost2::GetHostConfigFile() -{ - WRAPPER_NO_CONTRACT; - - if (!m_dwFlagsFinalized) // make sure we return consistent results - { - DangerousNonHostedSpinLockHolder lockHolder(&m_FlagsLock); - m_dwFlagsFinalized = TRUE; - } - - return m_wzHostConfigFile; -} - -// static -void CorHost2::GetDefaultAppDomainProperties(StringArrayList **pPropertyNames, StringArrayList **pPropertyValues) -{ - LIMITED_METHOD_CONTRACT; - - // We should only read these after the runtime has started to ensure that the host isn't modifying them - // still - _ASSERTE(g_fEEStarted || HasStarted()); - - *pPropertyNames = &s_defaultDomainPropertyNames; - *pPropertyValues = &s_defaultDomainPropertyValues; -} - -#endif // !FEATURE_CORECLR - -#ifdef FEATURE_COMINTEROP - -// Enumerate currently existing domains. -HRESULT CorRuntimeHostBase::EnumDomains(HDOMAINENUM *hEnum) -{ - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - WRAPPER(GC_TRIGGERS); - ENTRY_POINT; - } - CONTRACTL_END; - - if(hEnum == NULL) return E_POINTER; - - // Thread setup happens in BEGIN_EXTERNAL_ENTRYPOINT below. - // If the runtime has not started, we have nothing to do. - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - HRESULT hr = E_OUTOFMEMORY; - *hEnum = NULL; - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr) - - AppDomainIterator *pEnum = new (nothrow) AppDomainIterator(FALSE); - if(pEnum) { - *hEnum = (HDOMAINENUM) pEnum; - hr = S_OK; - } - END_EXTERNAL_ENTRYPOINT; - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -#endif // FEATURE_COMINTEROP - -extern "C" -HRESULT GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk) -{ - WRAPPER_NO_CONTRACT; - - return CorHost2::CreateObject(riid, (void**)ppUnk); -} - -#if defined(FEATURE_COMINTEROP) && !defined(FEATURE_CORECLR) - -HRESULT NextDomainWorker(AppDomainIterator *pEnum, - IUnknown** pAppDomain) -{ - CONTRACTL - { - DISABLED(NOTHROW); // nothrow contract's fs:0 handler gets called before the C++ EH fs:0 handler which is pushed in the prolog - GC_TRIGGERS; - SO_TOLERANT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - Thread *pThread = GetThread(); - BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, return COR_E_STACKOVERFLOW); - - EX_TRY - { - GCX_COOP_THREAD_EXISTS(pThread); - - if (pEnum->Next()) - { - AppDomain* pDomain = pEnum->GetDomain(); - // Need to enter the AppDomain to synchronize access to the exposed - // object properly (can't just take the system domain mutex since we - // might need to run code that uses higher ranking crsts). - ENTER_DOMAIN_PTR(pDomain,ADV_ITERATOR) - { - - hr = pDomain->GetComIPForExposedObject(pAppDomain); - } - END_DOMAIN_TRANSITION; - } - else - { - hr = S_FALSE; - } - } - EX_CATCH_HRESULT(hr); - - END_SO_INTOLERANT_CODE; - - return hr; -} - -// Returns S_FALSE when there are no more domains. A domain -// is passed out only when S_OK is returned. -HRESULT CorRuntimeHostBase::NextDomain(HDOMAINENUM hEnum, - IUnknown** pAppDomain) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - ENTRY_POINT; - } - CONTRACTL_END; - - if(hEnum == NULL || pAppDomain == NULL) - return E_POINTER; - - // If the runtime has not started, we have nothing to do. - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - HRESULT hr; - - BEGIN_ENTRYPOINT_NOTHROW; - - AppDomainIterator *pEnum = (AppDomainIterator *) hEnum; - - do - { - hr = NextDomainWorker(pEnum, pAppDomain); - // Might need to look at the next appdomain if we were attempting to get at - // the exposed appdomain object and were chucked out as the result of an - // appdomain unload. - } while (hr == COR_E_APPDOMAINUNLOADED); - END_ENTRYPOINT_NOTHROW; - return hr; -} - -// Creates a domain in the runtime. The identity array is -// a pointer to an array TYPE containing IIdentity objects defining -// the security identity. -HRESULT CorRuntimeHostBase::CreateDomainEx(LPCWSTR pwzFriendlyName, - IUnknown* pSetup, // Optional - IUnknown* pEvidence, // Optional - IUnknown ** pAppDomain) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - if(!pwzFriendlyName) return E_POINTER; - if(pAppDomain == NULL) return E_POINTER; - if(!g_fEEStarted) return E_FAIL; - - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - { - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - - struct _gc { - STRINGREF pName; - OBJECTREF pSetup; - OBJECTREF pEvidence; - APPDOMAINREF pDomain; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - if (FAILED(hr = EnsureComStartedNoThrow())) - goto lDone; - - GCPROTECT_BEGIN(gc); - - gc.pName = StringObject::NewString(pwzFriendlyName); - - if(pSetup) - GetObjectRefFromComIP(&gc.pSetup, pSetup); - if(pEvidence) - GetObjectRefFromComIP(&gc.pEvidence, pEvidence); - - MethodDescCallSite createDomain(METHOD__APP_DOMAIN__CREATE_DOMAIN); - - ARG_SLOT args[3] = { - ObjToArgSlot(gc.pName), - ObjToArgSlot(gc.pEvidence), - ObjToArgSlot(gc.pSetup), - }; - - gc.pDomain = (APPDOMAINREF) createDomain.Call_RetOBJECTREF(args); - - *pAppDomain = GetComIPFromObjectRef((OBJECTREF*) &gc.pDomain); - - GCPROTECT_END(); - -lDone: ; - } - END_EXTERNAL_ENTRYPOINT; - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -// Close the enumeration releasing resources -HRESULT CorRuntimeHostBase::CloseEnum(HDOMAINENUM hEnum) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - - if(hEnum) { - AppDomainIterator* pEnum = (AppDomainIterator*) hEnum; - delete pEnum; - } - - END_ENTRYPOINT_NOTHROW; - return hr; -} - - -HRESULT CorRuntimeHostBase::CreateDomainSetup(IUnknown **pAppDomainSetup) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - ENTRY_POINT; - MODE_PREEMPTIVE; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - if (!pAppDomainSetup) - return E_POINTER; - - // If the runtime has not started, we have nothing to do. - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - // Create the domain. - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - { - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - - struct _gc { - OBJECTREF pSetup; - } gc; - ZeroMemory(&gc, sizeof(gc)); - MethodTable* pMT = NULL; - - hr = EnsureComStartedNoThrow(); - if (FAILED(hr)) - goto lDone; - - pMT = MscorlibBinder::GetClass(CLASS__APPDOMAIN_SETUP); - - GCPROTECT_BEGIN(gc); - gc.pSetup = AllocateObject(pMT); - *pAppDomainSetup = GetComIPFromObjectRef((OBJECTREF*) &gc.pSetup); - GCPROTECT_END(); - -lDone: ; - } - END_EXTERNAL_ENTRYPOINT; - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -HRESULT CorRuntimeHostBase::CreateEvidence(IUnknown **pEvidence) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - if (!pEvidence) - return E_POINTER; - -#ifdef FEATURE_CAS_POLICY - - // If the runtime has not started, we have nothing to do. - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - // Create the domain. - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr); - { - GCX_COOP_THREAD_EXISTS(GET_THREAD()); - - struct _gc { - OBJECTREF pEvidence; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - MethodTable* pMT = NULL; - - hr = EnsureComStartedNoThrow(); - if (FAILED(hr)) - goto lDone; - - pMT = MscorlibBinder::GetClass(CLASS__EVIDENCE); - - GCPROTECT_BEGIN(gc); - gc.pEvidence = AllocateObject(pMT); - MethodDescCallSite ctor(METHOD__EVIDENCE__CTOR, &(gc.pEvidence)); - - // Call the Evidence class constructor. - ARG_SLOT CtorArgs[] = - { - ObjToArgSlot(gc.pEvidence) - }; - ctor.Call(CtorArgs); - - *pEvidence = GetComIPFromObjectRef((OBJECTREF*) &gc.pEvidence); - GCPROTECT_END(); - -lDone: ; - } - END_EXTERNAL_ENTRYPOINT; - END_ENTRYPOINT_NOTHROW; -#else // !FEATURE_CAS_POLICY - // There is no Evidence class support without CAS policy. - return E_NOTIMPL; -#endif // FEATURE_CAS_POLICY - - return hr; -} - -HRESULT CorRuntimeHostBase::UnloadDomain(IUnknown *pUnkDomain) -{ - CONTRACTL - { - DISABLED(NOTHROW); - GC_TRIGGERS; - MODE_ANY; - FORBID_FAULT; - ENTRY_POINT; - } - CONTRACTL_END; - - if (!pUnkDomain) - return E_POINTER; - - // If the runtime has not started, we have nothing to do. - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - CONTRACT_VIOLATION(FaultViolation); // This entire function is full of OOM potential: must fix. - - HRESULT hr = S_OK; - DWORD dwDomainId = 0; - BEGIN_ENTRYPOINT_NOTHROW; - - _ASSERTE (g_fComStarted); - - { - SystemDomain::LockHolder lh; - - ComCallWrapper* pWrap = GetCCWFromIUnknown(pUnkDomain, FALSE); - if (!pWrap) - { - hr = COR_E_APPDOMAINUNLOADED; - } - if (SUCCEEDED(hr)) - { - dwDomainId = pWrap->GetDomainID().m_dwId; - } - } - if (SUCCEEDED(hr)) - { - hr = UnloadAppDomain(dwDomainId, TRUE); - } - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -#endif // FEATURE_COMINTEROP && !FEATURE_CORECLR - -STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - -#ifdef FEATURE_CORECLR - if (!m_fStarted) - return HOST_E_INVALIDOPERATION; - - if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN) - { - if (!g_fEEStarted) - { - return HOST_E_CLRNOTAVAILABLE; - } - - if(!m_fAppDomainCreated) - { - return HOST_E_INVALIDOPERATION; - } - - HRESULT hr=S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - if (!m_fFirstToLoadCLR) - { - _ASSERTE(!"Not reachable"); - hr = HOST_E_CLRNOTAVAILABLE; - } - else - { - LONG refCount = m_RefCount; - if (refCount == 0) - { - hr = HOST_E_CLRNOTAVAILABLE; - } - else - if (1 == refCount) - { - // Stop coreclr on unload. - m_fStarted = FALSE; - EEShutDown(FALSE); - } - else - { - _ASSERTE(!"Not reachable"); - hr = S_FALSE; - } - } - END_ENTRYPOINT_NOTHROW; - - return hr; - } - else -#endif // FEATURE_CORECLR - - return CorRuntimeHostBase::UnloadAppDomain(dwDomainId, fWaitUntilDone); -} - -HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fSync) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - FORBID_FAULT; // Unloading domains cannot fail due to OOM - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - // No point going further if the runtime is not running... - { - // In IsRuntimeActive, we will call CanRunManagedCode that will - // check if the current thread has taken the loader lock or not, - // if MDA is supported. To do the check, MdaLoaderLock::ReportViolation - // will be invoked that will internally end up invoking - // MdaFactory::GetNext that will use the "new" operator - // that has the "FAULT" contract set, resulting in FAULT_VIOLATION since - // this method has the FORBID_FAULT contract set above. - // - // However, for a thread that holds the loader lock, unloading the appDomain is - // not a supported scenario. Thus, we should not be ending up in this code - // path for the FAULT violation. - // - // Hence, the CONTRACT_VIOLATION below for overriding the FORBID_FAULT - // for this scope only. - CONTRACT_VIOLATION(FaultViolation); - if (!IsRuntimeActive() - #ifdef FEATURE_CORECLR - || !m_fStarted - #endif // FEATURE_CORECLR - ) - { - return HOST_E_CLRNOTAVAILABLE; - } - } - - BEGIN_ENTRYPOINT_NOTHROW; - - // We do not use BEGIN_EXTERNAL_ENTRYPOINT here because - // we do not want to setup Thread. Process may be OOM, and we want Unload - // to work. - hr = AppDomain::UnloadById(ADID(dwDomainId), fSync); - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -//***************************************************************************** -// Fiber Methods -//***************************************************************************** -#if !defined(FEATURE_CORECLR) // simple hosting -HRESULT CorHost::CreateLogicalThreadState() -{ - CONTRACTL - { - NOTHROW; - DISABLED(GC_TRIGGERS); - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - if (CorHost::GetHostVersion() != 1) - { - hr=HOST_E_INVALIDOPERATION; - } - else - { - _ASSERTE (GetThread() == 0 || GetThread()->HasRightCacheStackBase()); - /* Thread *thread = */ SetupThreadNoThrow(&hr); - - } - END_ENTRYPOINT_NOTHROW; - return hr; -} - - -HRESULT CorHost::DeleteLogicalThreadState() -{ - if (CorHost::GetHostVersion() != 1) - { - return HOST_E_INVALIDOPERATION; - } - - Thread *pThread = GetThread(); - if (!pThread) - return E_UNEXPECTED; - - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - ENTRY_POINT; - } - CONTRACTL_END; - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - // We need to reset the TrapReturningThread count that was - // set when a thread is requested to be aborted. Otherwise - // every stub call is going to go through a slow path. - if (pThread->IsAbortRequested()) - pThread->UnmarkThreadForAbort(Thread::TAR_ALL); - - // see code:Thread::OnThreadTerminate#ReportDeadOnThreadTerminate - pThread->SetThreadState(Thread::TS_ReportDead); - - pThread->OnThreadTerminate(FALSE); - END_ENTRYPOINT_NOTHROW; - return hr; -} - - -HRESULT CorHost::SwitchInLogicalThreadState(DWORD *pFiberCookie) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_ANY; - STATIC_CONTRACT_ENTRY_POINT; - - if (CorHost::GetHostVersion() != 1) - { - return HOST_E_INVALIDOPERATION; - } - - if (!pFiberCookie) - { - return E_POINTER; - } - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - hr = ((Thread*)pFiberCookie)->SwitchIn(::GetCurrentThread()); - - END_ENTRYPOINT_NOTHROW; - return hr; - -} - -HRESULT CorHost::SwitchOutLogicalThreadState(DWORD **pFiberCookie) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_ANY; - STATIC_CONTRACT_ENTRY_POINT; - - if (CorHost::GetHostVersion() != 1) - { - return HOST_E_INVALIDOPERATION; - } - - if (!pFiberCookie) - { - return E_POINTER; - } - - Thread *pThread = GetThread(); - if (!pThread) - { - return E_UNEXPECTED; - } - - pThread->InternalSwitchOut(); - *pFiberCookie = (DWORD*)pThread; - - return S_OK; -} -#endif // !defined(FEATURE_CORECLR) - -HRESULT CorRuntimeHostBase::LocksHeldByLogicalThread(DWORD *pCount) -{ - if (!pCount) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - BEGIN_ENTRYPOINT_NOTHROW; - - Thread* pThread = GetThread(); - if (pThread == NULL) - *pCount = 0; - else - *pCount = pThread->m_dwLockCount; - - END_ENTRYPOINT_NOTHROW; - - return S_OK; -} - -//***************************************************************************** -// ICorConfiguration -//***************************************************************************** -#if !defined(FEATURE_CORECLR) -IGCThreadControl *CorConfiguration::m_CachedGCThreadControl = 0; -IGCHostControl *CorConfiguration::m_CachedGCHostControl = 0; -IDebuggerThreadControl *CorConfiguration::m_CachedDebuggerThreadControl = 0; -DWORD *CorConfiguration::m_DSTArray = 0; -DWORD CorConfiguration::m_DSTCount = 0; -DWORD CorConfiguration::m_DSTArraySize = 0; - -// *** ICorConfiguration methods *** - - -HRESULT CorConfiguration::SetGCThreadControl(IGCThreadControl *pGCThreadControl) -{ - if (!pGCThreadControl) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - BEGIN_ENTRYPOINT_NOTHROW; - - if (m_CachedGCThreadControl) - m_CachedGCThreadControl->Release(); - - m_CachedGCThreadControl = pGCThreadControl; - - if (m_CachedGCThreadControl) - m_CachedGCThreadControl->AddRef(); - - END_ENTRYPOINT_NOTHROW; - - return S_OK; -} - -HRESULT CorConfiguration::SetGCHostControl(IGCHostControl *pGCHostControl) -{ - if (!pGCHostControl) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - BEGIN_ENTRYPOINT_NOTHROW; - - if (m_CachedGCHostControl) - m_CachedGCHostControl->Release(); - - m_CachedGCHostControl = pGCHostControl; - - if (m_CachedGCHostControl) - m_CachedGCHostControl->AddRef(); - - END_ENTRYPOINT_NOTHROW; - - return S_OK; -} - -HRESULT CorConfiguration::SetDebuggerThreadControl(IDebuggerThreadControl *pDebuggerThreadControl) -{ - if (!pDebuggerThreadControl) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - -#ifdef DEBUGGING_SUPPORTED - // Can't change the debugger thread control object once its been set. - if (m_CachedDebuggerThreadControl != NULL) - IfFailGo(E_INVALIDARG); - - m_CachedDebuggerThreadControl = pDebuggerThreadControl; - - // If debugging is already initialized then provide this interface pointer to it. - // It will also addref the new one and release the old one. - if (g_pDebugInterface) - g_pDebugInterface->SetIDbgThreadControl(pDebuggerThreadControl); - - if (m_CachedDebuggerThreadControl) - m_CachedDebuggerThreadControl->AddRef(); - - hr = S_OK; -#else // !DEBUGGING_SUPPORTED - hr = E_NOTIMPL; -#endif // !DEBUGGING_SUPPORTED - -ErrExit: - END_ENTRYPOINT_NOTHROW; - return hr; - -} - - -HRESULT CorConfiguration::AddDebuggerSpecialThread(DWORD dwSpecialThreadId) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; // debugging not hardened for SO - } - CONTRACTL_END; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - -#ifdef DEBUGGING_SUPPORTED - // If it's already in the list, don't add it again. - if (IsDebuggerSpecialThread(dwSpecialThreadId)) - { - hr = S_OK; - goto ErrExit; - } - // Grow the array if necessary. - if (m_DSTCount >= m_DSTArraySize) - { - // There's probably only ever gonna be one or two of these - // things, so we'll start small. - DWORD newSize = (m_DSTArraySize == 0) ? 2 : m_DSTArraySize * 2; - - DWORD *newArray = new (nothrow) DWORD[newSize]; - IfNullGo(newArray); - - // If we're growing instead of starting, then copy the old array. - if (m_DSTArray) - { - memcpy(newArray, m_DSTArray, m_DSTArraySize * sizeof(DWORD)); - delete [] m_DSTArray; - } - - // Update to the new array and size. - m_DSTArray = newArray; - m_DSTArraySize = newSize; - } - - // Save the new thread ID. - m_DSTArray[m_DSTCount++] = dwSpecialThreadId; - - hr = (RefreshDebuggerSpecialThreadList()); -#else // !DEBUGGING_SUPPORTED - hr = E_NOTIMPL; -#endif // !DEBUGGING_SUPPORTED -ErrExit: - END_ENTRYPOINT_NOTHROW; - return hr; - -} -// Helper function to update the thread list in the debugger control block -HRESULT CorConfiguration::RefreshDebuggerSpecialThreadList() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - -#ifdef DEBUGGING_SUPPORTED - HRESULT hr = S_OK; - - if (g_pDebugInterface) - { - // Inform the debugger services that this list has changed - hr = g_pDebugInterface->UpdateSpecialThreadList( - m_DSTCount, m_DSTArray); - - _ASSERTE(SUCCEEDED(hr)); - } - - return (hr); -#else // !DEBUGGING_SUPPORTED - return E_NOTIMPL; -#endif // !DEBUGGING_SUPPORTED -} - - -// Helper func that returns true if the thread is in the debugger special thread list -BOOL CorConfiguration::IsDebuggerSpecialThread(DWORD dwThreadId) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - for (DWORD i = 0; i < m_DSTCount; i++) - { - if (m_DSTArray[i] == dwThreadId) - return (TRUE); - } - - return (FALSE); -} - - -// Clean up any debugger thread control object we may be holding, called at shutdown. -void CorConfiguration::CleanupDebuggerThreadControl() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - if (m_CachedDebuggerThreadControl != NULL) - { - // Note: we don't release the IDebuggerThreadControl object if we're cleaning up from - // our DllMain. The DLL that implements the object may already have been unloaded. - // Leaking the object is okay... the PDM doesn't care. - if (!IsAtProcessExit()) - m_CachedDebuggerThreadControl->Release(); - - m_CachedDebuggerThreadControl = NULL; - } -} -#endif // !defined(FEATURE_CORECLR) - -//***************************************************************************** -// IUnknown -//***************************************************************************** - -ULONG CorRuntimeHostBase::AddRef() -{ - CONTRACTL - { - WRAPPER(THROWS); - WRAPPER(GC_TRIGGERS); - SO_TOLERANT; - } - CONTRACTL_END; - return InterlockedIncrement(&m_cRef); -} - -#if !defined(FEATURE_CORECLR) // simple hosting -ULONG CorHost::Release() -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - - ULONG cRef = InterlockedDecrement(&m_cRef); - if (!cRef) { - delete this; - } - - return (cRef); -} -#endif // !defined(FEATURE_CORECLR) - -ULONG CorHost2::Release() -{ - LIMITED_METHOD_CONTRACT; - - ULONG cRef = InterlockedDecrement(&m_cRef); - if (!cRef) { -#ifdef FEATURE_INCLUDE_ALL_INTERFACES - // CorHost2 is allocated before host memory interface is set up. - if (GetHostMemoryManager() == NULL) -#endif // FEATURE_INCLUDE_ALL_INTERFACES - delete this; - } - - return (cRef); -} - -#if !defined(FEATURE_CORECLR) // simple hosting -HRESULT CorHost::QueryInterface(REFIID riid, void **ppUnk) -{ - if (!ppUnk) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; // no global state updates that need guarding. - } - CONTRACTL_END; - - if (ppUnk == NULL) - { - return E_POINTER; - } - - *ppUnk = 0; - - // Deliberately do NOT hand out ICorConfiguration. They must explicitly call - // GetConfiguration to obtain that interface. - if (riid == IID_IUnknown) - *ppUnk = (IUnknown *) (ICorRuntimeHost *) this; - else if (riid == IID_ICorRuntimeHost) - { - ULONG version = 1; - if (m_Version == 0) - FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - - if (m_Version != version && (g_singleVersionHosting || !g_fEEStarted)) - { - return HOST_E_INVALIDOPERATION; - } - - *ppUnk = (ICorRuntimeHost *) this; - } - else if (riid == IID_ICorThreadpool) - *ppUnk = (ICorThreadpool *) this; - else if (riid == IID_IGCHost) - *ppUnk = (IGCHost *) this; - else if (riid == IID_IGCHost2) - *ppUnk = (IGCHost2 *) this; - else if (riid == IID_IValidator) - *ppUnk = (IValidator *) this; - else if (riid == IID_IDebuggerInfo) - *ppUnk = (IDebuggerInfo *) this; - else if (riid == IID_ICLRExecutionManager) - *ppUnk = (ICLRExecutionManager *) this; - else - return (E_NOINTERFACE); - AddRef(); - return (S_OK); -} -#endif // !defined(FEATURE_CORECLR) - - -HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk) -{ - if (!ppUnk) - return E_POINTER; - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; // no global state updates that need guarding. - } - CONTRACTL_END; - - if (ppUnk == NULL) - { - return E_POINTER; - } - - *ppUnk = 0; - - // Deliberately do NOT hand out ICorConfiguration. They must explicitly call - // GetConfiguration to obtain that interface. - if (riid == IID_IUnknown) - *ppUnk = static_cast(static_cast(this)); -#ifdef FEATURE_CORECLR // CoreCLR only supports IID_ICLRRuntimeHost2 - else if (riid == IID_ICLRRuntimeHost2) - { - ULONG version = 2; - if (m_Version == 0) - FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - - *ppUnk = static_cast(this); - } -#else // DesktopCLR only supports IID_ICLRRuntimeHost - else if (riid == IID_ICLRRuntimeHost) - { - ULONG version = 2; - if (m_Version == 0) - FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - - *ppUnk = static_cast(this); - } -#endif // FEATURE_CORECLR - else if (riid == IID_ICLRExecutionManager) - { - ULONG version = 2; - if (m_Version == 0) - FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - - *ppUnk = static_cast(this); - } -#if !defined(FEATURE_CORECLR) - else if (riid == __uuidof(ICLRPrivRuntime)) - { - ULONG version = 2; - if (m_Version == 0) - FastInterlockCompareExchange((LONG*)&m_Version, version, 0); - - *ppUnk = static_cast(this); - } -#endif -#ifndef FEATURE_PAL - else if (riid == IID_IPrivateManagedExceptionReporting) - { - *ppUnk = static_cast(this); - } -#endif // !FEATURE_PAL -#ifndef FEATURE_CORECLR - else if (riid == IID_ICorThreadpool) - *ppUnk = static_cast(this); - // TODO: wwl Remove this after SQL uses new interface. - else if (riid == IID_IGCHost && - GetHostVersion() == 3) - *ppUnk = static_cast(this); - else if (riid == IID_ICLRValidator) - *ppUnk = static_cast(this); - else if (riid == IID_IDebuggerInfo) - *ppUnk = static_cast(this); -#ifdef FEATURE_TESTHOOKS - else if (riid == IID_ICLRTestHookManager) - { - *ppUnk=CLRTestHookManager::Start(); - if(*ppUnk==NULL) - return E_OUTOFMEMORY; - } -#endif // FEATURE_TESTHOOKS -#endif // FEATURE_CORECLR - else - return (E_NOINTERFACE); - AddRef(); - return (S_OK); -} - -#ifndef FEATURE_CORECLR // CorHost isn't exposed externally -//***************************************************************************** -// Called by the class factory template to create a new instance of this object. -//***************************************************************************** -HRESULT CorHost::CreateObject(REFIID riid, void **ppUnk) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - CorHost *pCorHost = new (nothrow) CorHost(); - if (!pCorHost) - { - hr = E_OUTOFMEMORY; - } - else - { - hr = pCorHost->QueryInterface(riid, ppUnk); - - if (FAILED(hr)) - delete pCorHost; - } - return (hr); -} -#endif // FEATURE_CORECLR - -#ifndef FEATURE_PAL -HRESULT CorHost2::GetBucketParametersForCurrentException(BucketParameters *pParams) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - // To avoid confusion, clear the buckets. - memset(pParams, 0, sizeof(BucketParameters)); - - // Defer to Watson helper. - hr = ::GetBucketParametersForCurrentException(pParams); - - END_ENTRYPOINT_NOTHROW; - - return hr; -} -#endif // !FEATURE_PAL - -HRESULT CorHost2::CreateObject(REFIID riid, void **ppUnk) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW; ); - CorHost2 *pCorHost = new (nothrow) CorHost2(); - if (!pCorHost) - { - hr = E_OUTOFMEMORY; - } - else - { - hr = pCorHost->QueryInterface(riid, ppUnk); - if (FAILED(hr)) - delete pCorHost; - } - END_SO_INTOLERANT_CODE; - return (hr); -} - - -//----------------------------------------------------------------------------- -// MapFile - Maps a file into the runtime in a non-standard way -//----------------------------------------------------------------------------- - -static PEImage *MapFileHelper(HANDLE hFile) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - GCX_PREEMP(); - - HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)); - if (hFileMap == NULL) - ThrowLastError(); - - CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0)); - if (base == NULL) - ThrowLastError(); - - DWORD dwSize = SafeGetFileSize(hFile, NULL); - if (dwSize == 0xffffffff && GetLastError() != NOERROR) - { - ThrowLastError(); - } - PEImageHolder pImage(PEImage::LoadFlat(base, dwSize)); - return pImage.Extract(); -} - -HRESULT CorRuntimeHostBase::MapFile(HANDLE hFile, HMODULE* phHandle) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_PREEMPTIVE; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr) - { - *phHandle = (HMODULE) (MapFileHelper(hFile)->GetLoadedLayout()->GetBase()); - } - END_EXTERNAL_ENTRYPOINT; - END_ENTRYPOINT_NOTHROW; - - - return hr; -} - -/////////////////////////////////////////////////////////////////////////////// -// IDebuggerInfo::IsDebuggerAttached -#if !defined(FEATURE_CORECLR) -HRESULT CorDebuggerInfo::IsDebuggerAttached(BOOL *pbAttached) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - if (pbAttached == NULL) - hr = E_INVALIDARG; - else -#ifdef DEBUGGING_SUPPORTED - *pbAttached = (CORDebuggerAttached() != 0); -#else - *pbAttached = FALSE; -#endif - - END_ENTRYPOINT_NOTHROW; - - return hr; -} -#endif // !defined(FEATURE_CORECLR) - -LONG CorHost2::m_RefCount = 0; - -IHostControl *CorHost2::m_HostControl = NULL; - -LPCWSTR CorHost2::s_wszAppDomainManagerAsm = NULL; -LPCWSTR CorHost2::s_wszAppDomainManagerType = NULL; -EInitializeNewDomainFlags CorHost2::s_dwDomainManagerInitFlags = eInitializeNewDomainFlags_None; - -#ifndef FEATURE_CORECLR // not supported - -StringArrayList CorHost2::s_defaultDomainPropertyNames; -StringArrayList CorHost2::s_defaultDomainPropertyValues; - -IHostMemoryManager *CorHost2::m_HostMemoryManager = NULL; -IHostMalloc *CorHost2::m_HostMalloc = NULL; -IHostTaskManager *CorHost2::m_HostTaskManager = NULL; -IHostThreadpoolManager *CorHost2::m_HostThreadpoolManager = NULL; -IHostIoCompletionManager *CorHost2::m_HostIoCompletionManager = NULL; -IHostSyncManager *CorHost2::m_HostSyncManager = NULL; -IHostAssemblyManager *CorHost2::m_HostAssemblyManager = NULL; -IHostGCManager *CorHost2::m_HostGCManager = NULL; -IHostSecurityManager *CorHost2::m_HostSecurityManager = NULL; -IHostPolicyManager *CorHost2::m_HostPolicyManager = NULL; -int CorHost2::m_HostOverlappedExtensionSize = -1; - -STARTUP_FLAGS CorHost2::m_dwStartupFlags = STARTUP_CONCURRENT_GC; -WCHAR CorHost2::m_wzHostConfigFile[_MAX_PATH] = { 0 }; - -BOOL CorHost2::m_dwFlagsFinalized = FALSE; -DangerousNonHostedSpinLock CorHost2::m_FlagsLock; - -class CCLRMemoryNotificationCallback: public ICLRMemoryNotificationCallback -{ -public: - virtual HRESULT STDMETHODCALLTYPE OnMemoryNotification(EMemoryAvailable eMemoryAvailable) { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - // We have not started runtime yet. - if (!g_fEEStarted) - return S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - - switch (eMemoryAvailable) - { - case eMemoryAvailableLow: - STRESS_LOG0(LF_GC, LL_INFO100, "Host delivers memory notification: Low\n"); - break; - case eMemoryAvailableNeutral: - STRESS_LOG0(LF_GC, LL_INFO100, "Host delivers memory notification: Neutral\n"); - break; - case eMemoryAvailableHigh: - STRESS_LOG0(LF_GC, LL_INFO100, "Host delivers memory notification: High\n"); - break; - } - static DWORD lastTime = (DWORD)-1; - if (eMemoryAvailable == eMemoryAvailableLow) - { - FastInterlockIncrement ((LONG *)&g_bLowMemoryFromHost); - DWORD curTime = GetTickCount(); - if (curTime < lastTime || curTime - lastTime >= 0x2000) - { - lastTime = curTime; - FinalizerThread::EnableFinalization(); - } - } - else - { - FastInterlockExchange ((LONG *)&g_bLowMemoryFromHost, FALSE); - } - END_ENTRYPOINT_NOTHROW; - - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) - { - LIMITED_METHOD_CONTRACT; - if (riid != IID_ICLRMemoryNotificationCallback && riid != IID_IUnknown) - return (E_NOINTERFACE); - *ppvObject = this; - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } -}; - -static CCLRMemoryNotificationCallback s_MemoryNotification; - -class CLRTaskManager : public ICLRTaskManager -{ -public: - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } - - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { - LIMITED_METHOD_CONTRACT; - if (riid != IID_ICLRTaskManager && riid != IID_IUnknown) - return (E_NOINTERFACE); - *ppvObject = this; - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } - - virtual HRESULT STDMETHODCALLTYPE CreateTask(ICLRTask **pTask) - { - CONTRACTL - { - NOTHROW; - DISABLED(GC_NOTRIGGER); - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - -#ifdef _DEBUG - _ASSERTE (!CLRTaskHosted() || GetCurrentHostTask()); -#endif - _ASSERTE (GetThread() == NULL); - Thread *pThread = NULL; - pThread = SetupThreadNoThrow(&hr); - *pTask = pThread; - - END_ENTRYPOINT_NOTHROW; - - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE GetCurrentTask(ICLRTask **pTask) - { - // This function may be called due SQL SwitchIn/Out. Contract may - // force memory allocation which is not allowed during Switch. - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_SO_TOLERANT; - STATIC_CONTRACT_ENTRY_POINT; - - *pTask = GetThread(); - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE SetUILocale(LCID lcid) - { - Thread *pThread = GetThread(); - if (pThread == NULL) - return HOST_E_INVALIDOPERATION; - - CONTRACTL - { - GC_TRIGGERS; - NOTHROW; - MODE_PREEMPTIVE; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - //BEGIN_ENTRYPOINT_NOTHROW; - BEGIN_EXTERNAL_ENTRYPOINT(&hr) - { - pThread->SetCultureId(lcid,TRUE); - } - END_EXTERNAL_ENTRYPOINT; - //END_ENTRYPOINT_NOTHROW; - - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE SetLocale(LCID lcid) - { - Thread *pThread = GetThread(); - if (pThread == NULL) - return HOST_E_INVALIDOPERATION; - - CONTRACTL - { - GC_TRIGGERS; - NOTHROW; - MODE_PREEMPTIVE; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = S_OK; - //BEGIN_ENTRYPOINT_NOTHROW; - - BEGIN_EXTERNAL_ENTRYPOINT(&hr) - { - pThread->SetCultureId(lcid,FALSE); - } - END_EXTERNAL_ENTRYPOINT; - //END_ENTRYPOINT_NOTHROW; - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE GetCurrentTaskType(ETaskType *pTaskType) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - ENTRY_POINT; - } - CONTRACTL_END; - - BEGIN_ENTRYPOINT_NOTHROW; - *pTaskType = ::GetCurrentTaskType(); - END_ENTRYPOINT_NOTHROW; - - return S_OK; - } -}; - -static CLRTaskManager s_CLRTaskManager; - -class CLRSyncManager : public ICLRSyncManager -{ -public: - virtual HRESULT STDMETHODCALLTYPE GetMonitorOwner(SIZE_T Cookie, - IHostTask **ppOwnerHostTask) - { - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - GC_NOTRIGGER; - ENTRY_POINT;; - } - CONTRACTL_END; - - BEGIN_ENTRYPOINT_NOTHROW; - - // Cookie is the SyncBlock - // TODO: Lifetime of Cookie? - AwareLock* pAwareLock = (AwareLock*)Cookie; - IHostTask *pTask = NULL; - Thread *pThread = pAwareLock->GetOwningThread(); - if (pThread) - { - ThreadStoreLockHolder tsLock; - pThread = pAwareLock->GetOwningThread(); - if (pThread) - { - // See if the lock is orphaned, and the Thread object has been deleted - Thread *pWalk = NULL; - while ((pWalk = ThreadStore::GetAllThreadList(pWalk, 0, 0)) != NULL) - { - if (pWalk == pThread) - { - pTask = pThread->GetHostTaskWithAddRef(); - break; - } - } - } - } - - *ppOwnerHostTask = pTask; - - END_ENTRYPOINT_NOTHROW; - - - return S_OK; - } - virtual HRESULT STDMETHODCALLTYPE CreateRWLockOwnerIterator(SIZE_T Cookie, - SIZE_T *pIterator) { - Thread *pThread = GetThread(); - - // We may open a window for GC here. - // A host should not hijack a coop thread to do deadlock detection. - if (pThread && pThread->PreemptiveGCDisabled()) - return HOST_E_INVALIDOPERATION; - - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - HRESULT hr = E_FAIL; - -#ifdef FEATURE_RWLOCK - BEGIN_ENTRYPOINT_NOTHROW; - ThreadStoreLockHolder tsLock; - // Cookie is a weak handle. We need to make sure that the object is not moving. - CRWLock *pRWLock = *(CRWLock **) Cookie; - *pIterator = NULL; - if (pRWLock == NULL) - { - hr = S_OK; - } - else - { - hr = pRWLock->CreateOwnerIterator(pIterator); - } - END_ENTRYPOINT_NOTHROW; -#endif // FEATURE_RWLOCK - - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE GetRWLockOwnerNext(SIZE_T Iterator, - IHostTask **ppOwnerHostTask) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - -#ifdef FEATURE_RWLOCK - BEGIN_ENTRYPOINT_NOTHROW; - CRWLock::GetNextOwner(Iterator,ppOwnerHostTask); - END_ENTRYPOINT_NOTHROW; -#endif // FEATURE_RWLOCK - - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE DeleteRWLockOwnerIterator(SIZE_T Iterator) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - -#ifdef FEATURE_RWLOCK - BEGIN_ENTRYPOINT_NOTHROW; - CRWLock::DeleteOwnerIterator(Iterator); - END_ENTRYPOINT_NOTHROW; -#endif // FEATURE_RWLOCK - - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) - { - LIMITED_METHOD_CONTRACT; - if (riid != IID_ICLRSyncManager && riid != IID_IUnknown) - return (E_NOINTERFACE); - *ppvObject = this; - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - LIMITED_METHOD_CONTRACT; - return 1; - } -}; - -static CLRSyncManager s_CLRSyncManager; - -extern void HostIOCompletionCallback(DWORD ErrorCode, - DWORD numBytesTransferred, - LPOVERLAPPED lpOverlapped); -class CCLRIoCompletionManager :public ICLRIoCompletionManager -{ -public: - virtual HRESULT STDMETHODCALLTYPE OnComplete(DWORD dwErrorCode, - DWORD NumberOfBytesTransferred, - void* pvOverlapped) - { - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_ENTRY_POINT; - - if (pvOverlapped) - { - BEGIN_ENTRYPOINT_NOTHROW; - HostIOCompletionCallback (dwErrorCode, NumberOfBytesTransferred, (LPOVERLAPPED)pvOverlapped); - END_ENTRYPOINT_NOTHROW; - } - - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - return 1; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - return 1; - } - BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - if (riid != IID_ICLRIoCompletionManager && riid != IID_IUnknown) - return (E_NOINTERFACE); - *ppvObject = this; - return S_OK; - } -}; - -static CCLRIoCompletionManager s_CLRIoCompletionManager; -#endif // FEATURE_CORECLR - -#ifdef _DEBUG -extern void ValidateHostInterface(); -#endif - -// fusion's global copy of host assembly manager stuff -BOOL g_bFusionHosted = FALSE; -#ifdef FEATURE_INCLUDE_ALL_INTERFACES -ICLRAssemblyReferenceList *g_pHostAsmList = NULL; -IHostAssemblyStore *g_pHostAssemblyStore = NULL; -#endif // FEATURE_INCLUDE_ALL_INTERFACES - -/*static*/ BOOL CorHost2::IsLoadFromBlocked() // LoadFrom, LoadFile and Load(byte[]) are blocked in certain hosting scenarios -{ - LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_INCLUDE_ALL_INTERFACES - return (g_bFusionHosted && (g_pHostAsmList != NULL)); -#else // !FEATURE_INCLUDE_ALL_INTERFACES - return FALSE; // as g_pHostAsmList is not defined for CoreCLR; hence above expression will be FALSE. -#endif // FEATURE_INCLUDE_ALL_INTERFACES -} - -static Volatile fOneOnly = 0; - -/////////////////////////////////////////////////////////////////////////////// -// ICLRRuntimeHost::SetHostControl -/////////////////////////////////////////////////////////////////////////////// -HRESULT CorHost2::SetHostControl(IHostControl* pHostControl) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - if (m_Version < 2) - // CLR is hosted with v1 hosting interface. Some part of v2 hosting API are disabled. - return HOST_E_INVALIDOPERATION; - - if (pHostControl == 0) - return E_INVALIDARG; - - // If Runtime has been started, do not allow setting HostMemoryManager - if (g_fEEStarted) - return E_ACCESSDENIED; - - HRESULT hr = S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - - DWORD dwSwitchCount = 0; - - while (FastInterlockExchange((LONG*)&fOneOnly, 1) == 1) - { - #ifndef FEATURE_CORECLR - if (m_HostTaskManager != NULL) - { - m_HostTaskManager->SwitchToTask(0); - } - else - { - IHostTaskManager *pHostTaskManager = NULL; - if (pHostControl->GetHostManager(IID_IHostTaskManager, (void**)&pHostTaskManager) == S_OK && - pHostTaskManager != NULL) - { - pHostTaskManager->SwitchToTask(0); - pHostTaskManager->Release(); - } - else - { - __SwitchToThread(0, ++dwSwitchCount); - } - } - #else - __SwitchToThread(0, ++dwSwitchCount); - #endif // FEATURE_CORECLR - } - -#ifndef FEATURE_CORECLR - -#ifdef _DEBUG - ValidateHostInterface(); -#endif - -#ifdef _DEBUG - DWORD dbg_HostManagerConfig = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HostManagerConfig); -#endif - - IHostMemoryManager *memoryManager = NULL; - IHostTaskManager *taskManager = NULL; - IHostThreadpoolManager *threadpoolManager = NULL; - IHostIoCompletionManager *ioCompletionManager = NULL; - IHostSyncManager *syncManager = NULL; - IHostAssemblyManager *assemblyManager = NULL; - IHostGCManager *gcManager = NULL; - IHostSecurityManager *securityManager = NULL; - IHostPolicyManager *policyManager = NULL; - - if (m_HostMemoryManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRMEMORYHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostMemoryManager,(void**)&memoryManager) == S_OK && - memoryManager != NULL) { - if (m_HostMalloc == NULL) - { - hr = memoryManager->CreateMalloc (MALLOC_THREADSAFE, &m_HostMalloc); - if (hr == S_OK) - { - memoryManager->RegisterMemoryNotificationCallback(&s_MemoryNotification); - } - else - { - memoryManager->Release(); - IfFailGo(E_UNEXPECTED); - } - } - m_HostMemoryManager = memoryManager; - g_fHostConfig |= CLRMEMORYHOSTED; - } - - if (m_HostTaskManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRTASKHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostTaskManager,(void**)&taskManager) == S_OK && - taskManager != NULL) { -#ifdef _TARGET_ARM_ // @ARMTODO: re-enable once we support hosted p/invokes. - IfFailGo(E_NOTIMPL); -#endif - m_HostTaskManager = taskManager; - m_HostTaskManager->SetCLRTaskManager(&s_CLRTaskManager); - g_fHostConfig |= CLRTASKHOSTED; - } - - if (m_HostThreadpoolManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRTHREADPOOLHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostThreadpoolManager,(void**)&threadpoolManager) == S_OK && - threadpoolManager != NULL) { - m_HostThreadpoolManager = threadpoolManager; - g_fHostConfig |= CLRTHREADPOOLHOSTED; - } - - if (m_HostIoCompletionManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRIOCOMPLETIONHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostIoCompletionManager,(void**)&ioCompletionManager) == S_OK && - ioCompletionManager != NULL) { - DWORD hostSize; - hr = ioCompletionManager->GetHostOverlappedSize(&hostSize); - if (FAILED(hr)) - { - ioCompletionManager->Release(); - IfFailGo(E_UNEXPECTED); - } - m_HostOverlappedExtensionSize = (int)hostSize; - m_HostIoCompletionManager = ioCompletionManager; - m_HostIoCompletionManager->SetCLRIoCompletionManager(&s_CLRIoCompletionManager); - g_fHostConfig |= CLRIOCOMPLETIONHOSTED; - } - - if (m_HostSyncManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRSYNCHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostSyncManager,(void**)&syncManager) == S_OK && - syncManager != NULL) { - m_HostSyncManager = syncManager; - m_HostSyncManager->SetCLRSyncManager(&s_CLRSyncManager); - g_fHostConfig |= CLRSYNCHOSTED; - } - - if (m_HostAssemblyManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRASSEMBLYHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostAssemblyManager,(void**)&assemblyManager) == S_OK && - assemblyManager != NULL) { - - assemblyManager->GetAssemblyStore(&g_pHostAssemblyStore); - - hr = assemblyManager->GetNonHostStoreAssemblies(&g_pHostAsmList); - if (FAILED(hr)) - { - assemblyManager->Release(); - IfFailGo(hr); - } - - if (g_pHostAssemblyStore || g_pHostAsmList) - g_bFusionHosted = TRUE; - m_HostAssemblyManager = assemblyManager; - g_fHostConfig |= CLRASSEMBLYHOSTED; - } - - if (m_HostGCManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRGCHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostGCManager, - (void**)&gcManager) == S_OK && - gcManager != NULL) { - m_HostGCManager = gcManager; - g_fHostConfig |= CLRGCHOSTED; - } - - if (m_HostSecurityManager == NULL && -#ifdef _DEBUG - (dbg_HostManagerConfig & CLRSECURITYHOSTED) && -#endif - pHostControl->GetHostManager(IID_IHostSecurityManager, - (void**)&securityManager) == S_OK && - securityManager != NULL) { - g_fHostConfig |= CLRSECURITYHOSTED; - m_HostSecurityManager = securityManager; -#ifdef FEATURE_CAS_POLICY - HostExecutionContextManager::InitializeRestrictedContext(); -#endif // #ifdef FEATURE_CAS_POLICY - } - - if (m_HostPolicyManager == NULL && - pHostControl->GetHostManager(IID_IHostPolicyManager, - (void**)&policyManager) == S_OK && - policyManager != NULL) { - m_HostPolicyManager = policyManager; - } -#endif //!FEATURE_CORECLR - - if (m_HostControl == NULL) - { - m_HostControl = pHostControl; - m_HostControl->AddRef(); - } - - goto ErrExit; - -ErrExit: - fOneOnly = 0; - - END_ENTRYPOINT_NOTHROW; - - return hr; -} - -class CCLRPolicyManager: public ICLRPolicyManager -{ -public: - virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(EClrOperation operation, - EPolicyAction action) - { - LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_CORECLR - STATIC_CONTRACT_ENTRY_POINT; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetDefaultAction(operation, action); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif // !FEATURE_CORECLR - } - - virtual HRESULT STDMETHODCALLTYPE SetTimeout(EClrOperation operation, - DWORD dwMilliseconds) - { - LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_CORECLR - STATIC_CONTRACT_ENTRY_POINT; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetTimeout(operation,dwMilliseconds); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif // !FEATURE_CORECLR - } - - virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(EClrOperation operation, - EPolicyAction action) - { - LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_CORECLR - STATIC_CONTRACT_ENTRY_POINT; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetActionOnTimeout(operation,action); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif // !FEATURE_CORECLR - } - - virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(EClrOperation operation, DWORD dwMilliseconds, - EPolicyAction action) - { - LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_CORECLR - STATIC_CONTRACT_SO_TOLERANT; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetTimeoutAndAction(operation,dwMilliseconds,action); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif // !FEATURE_CORECLR - } - - virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(EClrFailure failure, - EPolicyAction action) - { - // This is enabled for CoreCLR since a host can use this to - // specify action for handling AV. - STATIC_CONTRACT_ENTRY_POINT; - LIMITED_METHOD_CONTRACT; - HRESULT hr; -#ifdef FEATURE_CORECLR - // For CoreCLR, this method just supports FAIL_AccessViolation as a valid - // failure input arg. The validation of the specified action for the failure - // will be done in EEPolicy::IsValidActionForFailure. - if (failure != FAIL_AccessViolation) - { - return E_INVALIDARG; - } -#endif // FEATURE_CORECLR - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetActionOnFailure(failure,action); - END_ENTRYPOINT_NOTHROW; - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(EClrUnhandledException policy) - { - LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_CORECLR - STATIC_CONTRACT_ENTRY_POINT; - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - hr = GetEEPolicy()->SetUnhandledExceptionPolicy(policy); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR - return E_NOTIMPL; -#endif // !FEATURE_CORECLR - } - - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - return 1; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - return 1; - } - - BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, - void **ppvObject) - { - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - if (riid != IID_ICLRPolicyManager && riid != IID_IUnknown) - return (E_NOINTERFACE); - - // Ensure that the out going pointer is not null - if (ppvObject == NULL) - return E_POINTER; - - *ppvObject = this; - return S_OK; - } -}; - -static CCLRPolicyManager s_PolicyManager; - -#ifndef FEATURE_CORECLR // not supported -class CCLROnEventManager: public ICLROnEventManager -{ -public: - virtual HRESULT STDMETHODCALLTYPE RegisterActionOnEvent(EClrEvent event, - IActionOnCLREvent *pAction) - { - CONTRACTL - { - GC_TRIGGERS; - NOTHROW; - ENTRY_POINT; - - // This function is always called from outside the Runtime. So, we assert that we either don't have a - // managed thread, or if we do, that we're in preemptive GC mode. - PRECONDITION((GetThread() == NULL) || !GetThread()->PreemptiveGCDisabled()); - } - CONTRACTL_END; - - if (event >= MaxClrEvent || pAction == NULL || event < (EClrEvent)0) - return E_INVALIDARG; - - HRESULT hr = S_OK; - BEGIN_ENTRYPOINT_NOTHROW; - - // Note: its only safe to use a straight ReleaseHolder from within the VM directory when we know we're - // called from outside the Runtime. We assert that above, just to be sure. - ReleaseHolder actionHolder(pAction); - pAction->AddRef(); - - CrstHolderWithState ch(m_pLock); - - DWORD dwSwitchCount = 0; - while (m_ProcessEvent != 0) - { - ch.Release(); - __SwitchToThread(0, ++dwSwitchCount); - ch.Acquire(); - } - - if (m_pAction[event] == NULL) - { - m_pAction[event] = new (nothrow)ActionNode; - if (m_pAction[event] == NULL) - hr = E_OUTOFMEMORY; - } - - if (SUCCEEDED(hr)) - { - ActionNode *walk = m_pAction[event]; - while (TRUE) - { - int n = 0; - for ( ; n < ActionNode::ActionArraySize; n ++) - { - if (walk->pAction[n] == NULL) - { - walk->pAction[n] = pAction; - actionHolder.SuppressRelease(); - hr = S_OK; - break; - } - } - if (n < ActionNode::ActionArraySize) - { - break; - } - if (walk->pNext == NULL) - { - walk->pNext = new (nothrow) ActionNode; - if (walk->pNext == NULL) - { - hr = E_OUTOFMEMORY; - break; - } - } - walk = walk->pNext; - } - } - - END_ENTRYPOINT_NOTHROW; - return hr; - } - - virtual HRESULT STDMETHODCALLTYPE UnregisterActionOnEvent(EClrEvent event, - IActionOnCLREvent *pAction) - { - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - ENTRY_POINT; - } - CONTRACTL_END; - - if (event == Event_StackOverflow) - { - // We don't want to take a lock when we process StackOverflow event, because we may - // not have enough stack to do it. - // So we do not release our cache of the callback in order to avoid race. - return HOST_E_INVALIDOPERATION; - } - - HRESULT hr = S_OK; - - ActionNode *walk = NULL; - ActionNode *prev = NULL; - - - BEGIN_ENTRYPOINT_NOTHROW; - - CrstHolderWithState ch(m_pLock); - - DWORD dwSwitchCount = 0; - while (m_ProcessEvent != 0) - { - ch.Release(); - __SwitchToThread(0, ++dwSwitchCount); - ch.Acquire(); - } - - if (m_pAction[event] == NULL) - IfFailGo(HOST_E_INVALIDOPERATION); - - walk = m_pAction[event]; - while (walk) - { - BOOL fInUse = FALSE; - for (int n = 0; n < ActionNode::ActionArraySize; n ++) - { - if (prev && !fInUse && walk->pAction[n]) - fInUse = TRUE; - if (walk->pAction[n] == pAction) - { - walk->pAction[n] = NULL; - ch.Release(); - pAction->Release(); - hr = S_OK; - goto ErrExit; - } - } - if (prev && !fInUse) - { - prev->pNext = walk->pNext; - delete walk; - walk = prev; - } - prev = walk; - walk = walk->pNext; - } - hr = HOST_E_INVALIDOPERATION; -ErrExit: - END_ENTRYPOINT_NOTHROW; - - return hr; - } - - virtual ULONG STDMETHODCALLTYPE AddRef(void) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - return 1; - } - - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppUnk) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - if (riid != IID_ICLROnEventManager && riid != IID_IUnknown) - return (E_NOINTERFACE); - *ppUnk = this; - return S_OK; - } - - virtual ULONG STDMETHODCALLTYPE Release(void) - { - STATIC_CONTRACT_SO_TOLERANT; - LIMITED_METHOD_CONTRACT; - return 1; - } - - // This function is to work around an issue in scan.exe. - // scan.exe is not smart to handle that if (){} else {}. - void ProcessSOEvent(void *data) - { - STATIC_CONTRACT_SO_TOLERANT; - WRAPPER_NO_CONTRACT; - - if (m_pLock == NULL) - return; - - ActionNode *walk = m_pAction[Event_StackOverflow]; - - while (walk) - { - for (int n = 0; n < ActionNode::ActionArraySize; n ++) - { - if (walk->pAction[n]) - { - walk->pAction[n]->OnEvent(Event_StackOverflow,data); - } - } - walk = walk->pNext; - } - } - - void ProcessEvent(EClrEvent event, void *data) - { - WRAPPER_NO_CONTRACT; - - if (m_pLock == NULL) - { - return; - } - - _ASSERTE (event != Event_StackOverflow); - - { - CrstHolder ch(m_pLock); - - if (event == Event_ClrDisabled) - { - if (m_CLRDisabled) - { - return; - } - m_CLRDisabled = TRUE; - } - m_ProcessEvent ++; - - // Release the lock around the call into the host. Is this correct? - // It seems that we need to hold the lock except for the actual callback itself. - } - - BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread()); - { - ActionNode *walk = m_pAction[event]; - while (walk) - { - for (int n = 0; n < ActionNode::ActionArraySize; n ++) - { - if (walk->pAction[n]) - { - walk->pAction[n]->OnEvent(event,data); - } - } - walk = walk->pNext; - } - } - END_SO_TOLERANT_CODE_CALLING_HOST; + BEGIN_ENTRYPOINT_NOTHROW; + + DWORD dwSwitchCount = 0; - { - CrstHolder ch(m_pLock); - m_ProcessEvent --; - } + while (FastInterlockExchange((LONG*)&fOneOnly, 1) == 1) + { + __SwitchToThread(0, ++dwSwitchCount); } + - BOOL IsActionRegisteredForEvent(EClrEvent event) + if (m_HostControl == NULL) { - WRAPPER_NO_CONTRACT; + m_HostControl = pHostControl; + m_HostControl->AddRef(); + } - // Check to see if the event manager has been set up. - if (m_pLock == NULL) - return FALSE; + goto ErrExit; - CrstHolder ch(m_pLock); +ErrExit: + fOneOnly = 0; - ActionNode *walk = m_pAction[event]; - while (walk) - { - for (int n = 0; n < ActionNode::ActionArraySize; n ++) - { - if (walk->pAction[n] != NULL) - { - // We found an action registered for this event. - return TRUE; - } - } - walk = walk->pNext; - } + END_ENTRYPOINT_NOTHROW; - // There weren't any actions registered. - return FALSE; - } + return hr; +} - HRESULT Init() +class CCLRPolicyManager: public ICLRPolicyManager +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(EClrOperation operation, + EPolicyAction action) { - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_ANY; - STATIC_CONTRACT_SO_TOLERANT; - - HRESULT hr = S_OK; - if (m_pLock == NULL) - { - EX_TRY - { - BEGIN_SO_INTOLERANT_CODE(GetThread()); - { - InitHelper(); - } - END_SO_INTOLERANT_CODE; - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - } - - return hr; + LIMITED_METHOD_CONTRACT; + return E_NOTIMPL; } -#if 0 - // We do not need this one. We have one instance of this class - // and it is static. - CCLROnEventManager() + virtual HRESULT STDMETHODCALLTYPE SetTimeout(EClrOperation operation, + DWORD dwMilliseconds) { LIMITED_METHOD_CONTRACT; - for (int n = 0; n < MaxClrEvent; n ++) - m_pAction[n] = NULL; + return E_NOTIMPL; } -#endif -private: - struct ActionNode + virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(EClrOperation operation, + EPolicyAction action) { - static const int ActionArraySize = 8; + LIMITED_METHOD_CONTRACT; + return E_NOTIMPL; + } - IActionOnCLREvent *pAction[ActionArraySize]; - ActionNode *pNext; + virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(EClrOperation operation, DWORD dwMilliseconds, + EPolicyAction action) + { + LIMITED_METHOD_CONTRACT; + return E_NOTIMPL; + } - ActionNode () - : pNext(NULL) + virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(EClrFailure failure, + EPolicyAction action) + { + // This is enabled for CoreCLR since a host can use this to + // specify action for handling AV. + STATIC_CONTRACT_ENTRY_POINT; + LIMITED_METHOD_CONTRACT; + HRESULT hr; + // For CoreCLR, this method just supports FAIL_AccessViolation as a valid + // failure input arg. The validation of the specified action for the failure + // will be done in EEPolicy::IsValidActionForFailure. + if (failure != FAIL_AccessViolation) { - LIMITED_METHOD_CONTRACT; - - for (int n = 0; n < ActionArraySize; n ++) - pAction[n] = 0; + return E_INVALIDARG; } - }; - ActionNode *m_pAction[MaxClrEvent]; + BEGIN_ENTRYPOINT_NOTHROW; + hr = GetEEPolicy()->SetActionOnFailure(failure,action); + END_ENTRYPOINT_NOTHROW; + return hr; + } - Crst* m_pLock; + virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(EClrUnhandledException policy) + { + LIMITED_METHOD_CONTRACT; + return E_NOTIMPL; + } - BOOL m_CLRDisabled; + virtual ULONG STDMETHODCALLTYPE AddRef(void) + { + LIMITED_METHOD_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + return 1; + } - // We can not call out into host while holding the lock. At the same time - // we need to make our data consistent. Therefore, m_ProcessEvent is a marker - // to forbid touching the data structure from Register and UnRegister. - DWORD m_ProcessEvent; + virtual ULONG STDMETHODCALLTYPE Release(void) + { + LIMITED_METHOD_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + return 1; + } - void InitHelper() + BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, + void **ppvObject) { - CONTRACTL - { - GC_NOTRIGGER; - THROWS; - MODE_ANY; - } - CONTRACTL_END; + LIMITED_METHOD_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + if (riid != IID_ICLRPolicyManager && riid != IID_IUnknown) + return (E_NOINTERFACE); - m_ProcessEvent = 0; + // Ensure that the out going pointer is not null + if (ppvObject == NULL) + return E_POINTER; - Crst* tmp = new Crst(CrstOnEventManager, CrstFlags(CRST_DEFAULT | CRST_DEBUGGER_THREAD)); - if (FastInterlockCompareExchangePointer(&m_pLock, tmp, NULL) != NULL) - delete tmp; + *ppvObject = this; + return S_OK; } }; -static CCLROnEventManager s_OnEventManager; -#endif // FEATURE_CORECLR +static CCLRPolicyManager s_PolicyManager; + void ProcessEventForHost(EClrEvent event, void *data) { -#ifndef FEATURE_CORECLR - WRAPPER_NO_CONTRACT; - - _ASSERTE (event != Event_StackOverflow); - - GCX_PREEMP(); - - s_OnEventManager.ProcessEvent(event,data); -#endif // FEATURE_CORECLR } // We do not call ProcessEventForHost for stack overflow, since we have limit stack // and we should avoid calling GCX_PREEMPT void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant) { -#ifndef FEATURE_CORECLR - WRAPPER_NO_CONTRACT; - - StackOverflowInfo soInfo; - if (fInSoTolerant) - { - soInfo.soType = SO_Managed; - } - else if (pExceptionInfo == NULL || IsIPInModule(g_pMSCorEE, GetIP(pExceptionInfo->ContextRecord))) - { - soInfo.soType = SO_ClrEngine; - } - else - { - soInfo.soType = SO_Other; - } - - soInfo.pExceptionInfo = pExceptionInfo; - s_OnEventManager.ProcessSOEvent(&soInfo); -#endif // FEATURE_CORECLR } BOOL IsHostRegisteredForEvent(EClrEvent event) { WRAPPER_NO_CONTRACT; -#ifdef FEATURE_CORECLR return FALSE; -#else // FEATURE_CORECLR - return s_OnEventManager.IsActionRegisteredForEvent(event); -#endif // FEATURE_CORECLR } inline size_t SizeInKBytes(size_t cbSize) @@ -5154,7 +1933,7 @@ void UpdateGCSettingFromHost () } } -#if !defined(FEATURE_CORECLR) || defined(FEATURE_WINDOWSPHONE) +#if defined(FEATURE_WINDOWSPHONE) class CCLRGCManager: public ICLRGCManager2 { public: @@ -5562,17 +2341,7 @@ public: if (ppObject == NULL) return E_INVALIDARG; -#ifndef FEATURE_CORECLR - // ErrorReportingManager is allowed, even if runtime is started, so - // make this check first. - // Host must call release on CLRErrorReportingManager after this call - if (riid == IID_ICLRErrorReportingManager) - { - *ppObject = &g_CLRErrorReportingManager; - return S_OK; - } - else -#elif defined(FEATURE_WINDOWSPHONE) +#if defined(FEATURE_WINDOWSPHONE) if (riid == IID_ICLRErrorReportingManager2) { *ppObject = &g_CLRErrorReportingManager; @@ -5585,12 +2354,6 @@ public: // If runtime has been started, do not allow user to obtain CLR managers. return HOST_E_INVALIDOPERATION; } -#ifndef FEATURE_CORECLR - else if (riid == IID_ICLRTaskManager) { - *ppObject = &s_CLRTaskManager; - return S_OK; - } -#endif // !FEATURE_CORECLR // CoreCLR supports ICLRPolicyManager since it allows the host // to specify the policy for AccessViolation. @@ -5599,30 +2362,8 @@ public: FastInterlockExchange((LONG*)&g_CLRPolicyRequested, TRUE); return S_OK; } -#ifndef FEATURE_CORECLR - else if (riid == IID_ICLRHostProtectionManager) { - *ppObject = GetHostProtectionManager(); - return S_OK; - } - - // Host must call release on CLRDebugManager after this call - else if (riid == IID_ICLRDebugManager) - { - *ppObject = &s_CLRDebugManager; - return S_OK; - } - - else if (riid == IID_ICLROnEventManager) - { - HRESULT hr = s_OnEventManager.Init(); - if (FAILED(hr)) - return hr; - *ppObject = &s_OnEventManager; - return S_OK; - } -#endif // !FEATURE_CORECLR -#if !defined(FEATURE_CORECLR) || defined(FEATURE_WINDOWSPHONE) +#if defined(FEATURE_WINDOWSPHONE) else if ((riid == IID_ICLRGCManager) || (riid == IID_ICLRGCManager2)) { *ppObject = &s_GCManager; @@ -5646,29 +2387,9 @@ public: LPCWSTR pwzAppDomainManagerAssembly, LPCWSTR pwzAppDomainManagerType) { -#ifndef FEATURE_CORECLR - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; // no global state updates - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - - hr = CorHost2::SetAppDomainManagerType(pwzAppDomainManagerAssembly, - pwzAppDomainManagerType, - eInitializeNewDomainFlags_None); - END_ENTRYPOINT_NOTHROW; - return hr; -#else // FEATURE_CORECLR // CoreCLR does not support this method return E_NOTIMPL; -#endif // !FEATURE_CORECLR } virtual ULONG STDMETHODCALLTYPE AddRef(void) @@ -5713,9 +2434,6 @@ private: // After CLR starts, we give out s_CorCLRControlLimited which allows limited access to managers. static CCorCLRControl s_CorCLRControl; -#ifndef FEATURE_CORECLR -static CCorCLRControl s_CorCLRControlLimited; -#endif // FEATURE_CORECLR /////////////////////////////////////////////////////////////////////////////// // ICLRRuntimeHost::GetCLRControl @@ -5740,11 +2458,6 @@ HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl) } else { -#ifndef FEATURE_CORECLR - // Even CLR is hosted by v1 hosting interface, we still allow part of CLRControl, like IID_ICLRErrorReportingManager. - s_CorCLRControlLimited.SetAccess(FALSE); - *pCLRControl = &s_CorCLRControlLimited; -#else // FEATURE_CORECLR // If : // 1) request comes for interface other than ICLRControl*, OR // 2) runtime has already started, OR @@ -5761,175 +2474,30 @@ HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl) { hr = E_NOTIMPL; } -#endif // !FEATURE_CORECLR } END_ENTRYPOINT_NOTHROW; return hr; } -#ifndef FEATURE_CORECLR - -// static -HRESULT CorHost2::SetPropertiesForDefaultAppDomain(DWORD nProperties, - __in_ecount(nProperties) LPCWSTR *pwszPropertyNames, - __in_ecount(nProperties) LPCWSTR *pwszPropertyValues) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // Default domain properties can only be set before the CLR has started - if (g_fEEStarted || HasStarted()) - { - return HOST_E_INVALIDOPERATION; - } - - // If the host is specifying properties, they should be there - if (nProperties > 0 && (pwszPropertyNames == NULL || pwszPropertyValues == NULL)) - { - return E_POINTER; - } - - // v4 - since this property is being added late in the cycle to address a specific scenario, we - // reject any attempt to set anything but a single well known property name. This restriction - // can be removed in the future. - for (DWORD iProperty = 0; iProperty < nProperties; ++iProperty) - { - if (pwszPropertyNames[iProperty] == NULL) - { - return E_POINTER; - } - if (pwszPropertyValues[iProperty] == NULL) - { - return E_POINTER; - } - if (wcscmp(PARTIAL_TRUST_VISIBLE_ASSEMBLIES_PROPERTY, pwszPropertyNames[iProperty]) != 0) - { - return HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY); - } - } - - HRESULT hr = S_OK; - - EX_TRY - { - for (DWORD iProperty = 0; iProperty < nProperties; ++iProperty) - { - SString propertyName(pwszPropertyNames[iProperty]); - s_defaultDomainPropertyNames.Append(propertyName); - - SString propertyValue(pwszPropertyValues[iProperty]); - s_defaultDomainPropertyValues.Append(propertyValue); - } - } - EX_CATCH_HRESULT(hr); - - return hr; -} - -// static -HRESULT CorHost2::SetAppDomainManagerType(LPCWSTR wszAppDomainManagerAssembly, - LPCWSTR wszAppDomainManagerType, - EInitializeNewDomainFlags dwInitializeDomainFlags) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // The AppDomainManger can only be set by the host before the CLR has started - if (g_fEEStarted || HasStarted()) - { - return HOST_E_INVALIDOPERATION; - } - - // Both the type and assembly must be specified - if (wszAppDomainManagerAssembly == NULL || wszAppDomainManagerType == NULL) - { - return E_INVALIDARG; - } - - // Make sure we understand the incoming flags - const EInitializeNewDomainFlags knownFlags = eInitializeNewDomainFlags_NoSecurityChanges; - if ((dwInitializeDomainFlags & (~knownFlags)) != eInitializeNewDomainFlags_None) - { - return E_INVALIDARG; - } - - // Get a copy of the AppDomainManager assembly - size_t cchAsm = wcslen(wszAppDomainManagerAssembly) + 1; - NewArrayHolder wszAppDomainManagerAssemblyCopy(new (nothrow) WCHAR[cchAsm]); - if (wszAppDomainManagerAssemblyCopy == NULL) - { - return E_OUTOFMEMORY; - } - wcsncpy_s(wszAppDomainManagerAssemblyCopy, cchAsm, wszAppDomainManagerAssembly, cchAsm - 1); - - // And of the AppDomainManagerType - size_t cchType = wcslen(wszAppDomainManagerType) + 1; - NewArrayHolder wszAppDomainManagerTypeCopy(new (nothrow) WCHAR[cchType]); - if (wszAppDomainManagerTypeCopy == NULL) - { - return E_OUTOFMEMORY; - } - wcsncpy_s(wszAppDomainManagerTypeCopy, cchType, wszAppDomainManagerType, cchType - 1); - - LPCWSTR wszOldAsmValue = FastInterlockCompareExchangePointer(&s_wszAppDomainManagerAsm, - static_cast(wszAppDomainManagerAssemblyCopy.GetValue()), - NULL); - if (wszOldAsmValue != NULL) - { - // We've tried to setup an AppDomainManager twice ... that's not allowed - return HOST_E_INVALIDOPERATION; - } - - s_wszAppDomainManagerType = wszAppDomainManagerTypeCopy; - s_dwDomainManagerInitFlags = dwInitializeDomainFlags; - - wszAppDomainManagerAssemblyCopy.SuppressRelease(); - wszAppDomainManagerTypeCopy.SuppressRelease(); - return S_OK; -} -#endif // !FEATURE_CORECLR LPCWSTR CorHost2::GetAppDomainManagerAsm() { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_CORECLR return NULL; -#else // FEATURE_CORECLR - _ASSERTE (g_fEEStarted); - return s_wszAppDomainManagerAsm; -#endif // FEATURE_CORECLR } LPCWSTR CorHost2::GetAppDomainManagerType() { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_CORECLR return NULL; -#else // FEATURE_CORECLR - _ASSERTE (g_fEEStarted); - return s_wszAppDomainManagerType; -#endif // FEATURE_CORECLR } // static EInitializeNewDomainFlags CorHost2::GetAppDomainManagerInitializeNewDomainFlags() { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_CORECLR return eInitializeNewDomainFlags_None; -#else // FEAUTRE_CORECLR - _ASSERTE (g_fEEStarted); - return s_dwDomainManagerInitFlags; -#endif // FEATURE_CORECLR } #ifdef FEATURE_INCLUDE_ALL_INTERFACES @@ -7229,9 +3797,6 @@ struct ClrTlsInfo #define DataToClrTlsInfo(a) (a)?(ClrTlsInfo*)((BYTE*)a - offsetof(ClrTlsInfo, data)):NULL -#if !defined(FEATURE_CORECLR) -#define HAS_FLS_SUPPORT 1 -#endif #ifdef HAS_FLS_SUPPORT @@ -8338,7 +4903,7 @@ SIZE_T STDMETHODCALLTYPE CExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, } #define ClrVirtualQuery EEVirtualQuery -#if defined(_DEBUG) && defined(FEATURE_CORECLR) && !defined(FEATURE_PAL) +#if defined(_DEBUG) && !defined(FEATURE_PAL) static VolatilePtr s_pStartOfUEFSection = NULL; static VolatilePtr s_pEndOfUEFSectionBoundary = NULL; static Volatile s_dwProtection = 0; @@ -8388,7 +4953,7 @@ BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, // // We assert if either of the two conditions above are true. -#if defined(_DEBUG) && defined(FEATURE_CORECLR) && !defined(FEATURE_PAL) +#if defined(_DEBUG) && !defined(FEATURE_PAL) // We do this check in debug/checked builds only // Do we have the UEF details? @@ -8569,7 +5134,6 @@ LocaleID RuntimeGetFileSystemLocale() }; #endif -#ifdef FEATURE_CORECLR HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName, IActivationFactory ** factory) { #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION @@ -8599,7 +5163,6 @@ HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName return E_NOTIMPL; #endif } -#endif #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION @@ -8624,16 +5187,6 @@ HRESULT STDMETHODCALLTYPE DllGetActivationFactoryImpl(LPCWSTR wszAssemblyName, AppDomain* pDomain = SystemDomain::System()->DefaultDomain(); _ASSERTE(pDomain); -#ifndef FEATURE_CORECLR // coreclr uses winrt binder which does not allow redirects - { - BaseDomain::LockHolder lh(pDomain); - if (!pDomain->HasLoadContextHostBinder()) - { - // don't allow redirects - SystemDomain::InitializeDefaultDomain(FALSE); - } - } -#endif BEGIN_EXTERNAL_ENTRYPOINT(&hr); { -- cgit v1.2.3