1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | //***************************************************************************** |
5 | // CorHost.cpp |
6 | // |
7 | // Implementation for the meta data dispenser code. |
8 | // |
9 | |
10 | //***************************************************************************** |
11 | |
12 | #include "common.h" |
13 | |
14 | #include "mscoree.h" |
15 | #include "corhost.h" |
16 | #include "excep.h" |
17 | #include "threads.h" |
18 | #include "jitinterface.h" |
19 | #include "eeconfig.h" |
20 | #include "dbginterface.h" |
21 | #include "ceemain.h" |
22 | #include "hosting.h" |
23 | #include "eepolicy.h" |
24 | #include "clrex.h" |
25 | #include "comcallablewrapper.h" |
26 | #include "invokeutil.h" |
27 | #include "appdomain.inl" |
28 | #include "vars.hpp" |
29 | #include "comdelegate.h" |
30 | #include "dllimportcallback.h" |
31 | #include "eventtrace.h" |
32 | |
33 | #include "win32threadpool.h" |
34 | #include "eventtrace.h" |
35 | #include "finalizerthread.h" |
36 | #include "threadsuspend.h" |
37 | |
38 | #ifndef FEATURE_PAL |
39 | #include "dwreport.h" |
40 | #endif // !FEATURE_PAL |
41 | |
42 | #include "stringarraylist.h" |
43 | #ifdef FEATURE_PERFTRACING |
44 | #include "eventpipe.h" |
45 | #endif // FEATURE_PERFTRACING |
46 | |
47 | #ifdef FEATURE_COMINTEROP |
48 | #include "winrttypenameconverter.h" |
49 | #endif |
50 | |
51 | |
52 | GVAL_IMPL_INIT(DWORD, g_fHostConfig, 0); |
53 | |
54 | #ifndef __llvm__ |
55 | EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo; |
56 | #else // !__llvm__ |
57 | EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo; |
58 | #endif // !__llvm__ |
59 | #ifndef FEATURE_PAL |
60 | EXTERN_C UINT32 _tls_index; |
61 | #else // FEATURE_PAL |
62 | UINT32 _tls_index = 0; |
63 | #endif // FEATURE_PAL |
64 | |
65 | #if defined(FEATURE_WINDOWSPHONE) |
66 | SVAL_IMPL_INIT(ECustomDumpFlavor, CCLRErrorReportingManager, g_ECustomDumpFlavor, DUMP_FLAVOR_Default); |
67 | #endif |
68 | |
69 | #ifndef DACCESS_COMPILE |
70 | |
71 | extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading); |
72 | extern HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags); |
73 | extern void PrintToStdOutA(const char *pszString); |
74 | extern void PrintToStdOutW(const WCHAR *pwzString); |
75 | extern BOOL g_fEEHostedStartup; |
76 | |
77 | INT64 g_PauseTime; // Total time in millisecond the CLR has been paused |
78 | Volatile<BOOL> g_IsPaused; // True if the runtime is paused (FAS) |
79 | CLREventStatic g_ClrResumeEvent; // Event that is fired at FAS Resuming |
80 | |
81 | extern BYTE g_rbTestKeyBuffer[]; |
82 | |
83 | //*************************************************************************** |
84 | |
85 | ULONG CorRuntimeHostBase::m_Version = 0; |
86 | |
87 | |
88 | #if defined(FEATURE_WINDOWSPHONE) |
89 | CCLRErrorReportingManager g_CLRErrorReportingManager; |
90 | #endif // defined(FEATURE_WINDOWSPHONE) |
91 | |
92 | #endif // !DAC |
93 | |
94 | typedef DPTR(CONNID) PTR_CONNID; |
95 | |
96 | |
97 | |
98 | // Keep track connection id and name |
99 | |
100 | #ifndef DACCESS_COMPILE |
101 | |
102 | |
103 | |
104 | |
105 | // *** ICorRuntimeHost methods *** |
106 | |
107 | CorHost2::CorHost2() : m_fFirstToLoadCLR(FALSE), m_fStarted(FALSE), m_fAppDomainCreated(FALSE) |
108 | { |
109 | LIMITED_METHOD_CONTRACT; |
110 | } |
111 | |
112 | static DangerousNonHostedSpinLock lockOnlyOneToInvokeStart; |
113 | |
114 | STDMETHODIMP CorHost2::Start() |
115 | { |
116 | CONTRACTL |
117 | { |
118 | NOTHROW; |
119 | GC_TRIGGERS; |
120 | ENTRY_POINT; |
121 | }CONTRACTL_END; |
122 | |
123 | HRESULT hr; |
124 | |
125 | BEGIN_ENTRYPOINT_NOTHROW; |
126 | |
127 | // Ensure that only one thread at a time gets in here |
128 | DangerousNonHostedSpinLockHolder lockHolder(&lockOnlyOneToInvokeStart); |
129 | |
130 | // To provide the complete semantic of Start/Stop in context of a given host, we check m_fStarted and let |
131 | // them invoke the Start only if they have not already. Likewise, they can invoke the Stop method |
132 | // only if they have invoked Start prior to that. |
133 | // |
134 | // This prevents a host from invoking Stop twice and hitting the refCount to zero, when another |
135 | // host is using the CLR, as CLR instance sharing across hosts is a scenario for CoreCLR. |
136 | |
137 | if (g_fEEStarted) |
138 | { |
139 | hr = S_OK; |
140 | // CoreCLR is already running - but was Start already invoked by this host? |
141 | if (m_fStarted) |
142 | { |
143 | // This host had already invoked the Start method - return them an error |
144 | hr = HOST_E_INVALIDOPERATION; |
145 | } |
146 | else |
147 | { |
148 | // Increment the global (and dynamic) refCount... |
149 | FastInterlockIncrement(&m_RefCount); |
150 | |
151 | // And set our flag that this host has invoked the Start... |
152 | m_fStarted = TRUE; |
153 | } |
154 | } |
155 | else |
156 | { |
157 | // Using managed C++ libraries, its possible that when the runtime is already running, |
158 | // MC++ will use CorBindToRuntimeEx to make callbacks into specific appdomain of its |
159 | // choice. Now, CorBindToRuntimeEx results in CorHost2::CreateObject being invoked |
160 | // that will set runtime hosted flag "g_fHostConfig |= CLRHOSTED". |
161 | // |
162 | // For the case when managed code started without CLR hosting and MC++ does a |
163 | // CorBindToRuntimeEx, setting the CLR hosted flag is incorrect. |
164 | // |
165 | // Thus, before we attempt to start the runtime, we save the status of it being |
166 | // already running or not. Next, if we are able to successfully start the runtime |
167 | // and ONLY if it was not started earlier will we set the hosted flag below. |
168 | if (!g_fEEStarted) |
169 | { |
170 | g_fHostConfig |= CLRHOSTED; |
171 | } |
172 | |
173 | hr = CorRuntimeHostBase::Start(); |
174 | if (SUCCEEDED(hr)) |
175 | { |
176 | // Set our flag that this host invoked the Start method. |
177 | m_fStarted = TRUE; |
178 | |
179 | // And they also loaded the CoreCLR DLL in the memory (for this version). |
180 | // This is a special flag as the host that has got this flag set will be allowed |
181 | // to repeatedly invoke Stop method (without corresponding Start method invocations). |
182 | // This is to support scenarios like that of Office where they need to bring down |
183 | // the CLR at any cost. |
184 | // |
185 | // So, if you want to do that, just make sure you are the first host to load the |
186 | // specific version of CLR in memory AND start it. |
187 | m_fFirstToLoadCLR = TRUE; |
188 | FastInterlockIncrement(&m_RefCount); |
189 | } |
190 | } |
191 | |
192 | END_ENTRYPOINT_NOTHROW; |
193 | return hr; |
194 | } |
195 | |
196 | // Starts the runtime. This is equivalent to CoInitializeEE(); |
197 | HRESULT CorRuntimeHostBase::Start() |
198 | { |
199 | CONTRACTL |
200 | { |
201 | NOTHROW; |
202 | DISABLED(GC_TRIGGERS); |
203 | ENTRY_POINT; |
204 | } |
205 | CONTRACTL_END; |
206 | |
207 | HRESULT hr = S_OK; |
208 | |
209 | BEGIN_ENTRYPOINT_NOTHROW; |
210 | { |
211 | m_Started = TRUE; |
212 | #ifdef FEATURE_EVENT_TRACE |
213 | g_fEEHostedStartup = TRUE; |
214 | #endif // FEATURE_EVENT_TRACE |
215 | hr = InitializeEE(COINITEE_DEFAULT); |
216 | } |
217 | END_ENTRYPOINT_NOTHROW; |
218 | |
219 | return hr; |
220 | } |
221 | |
222 | |
223 | HRESULT CorHost2::Stop() |
224 | { |
225 | CONTRACTL |
226 | { |
227 | NOTHROW; |
228 | ENTRY_POINT; // We're bringing the EE down, so no point in probing |
229 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
230 | } |
231 | CONTRACTL_END; |
232 | if (!g_fEEStarted) |
233 | { |
234 | return E_UNEXPECTED; |
235 | } |
236 | HRESULT hr=S_OK; |
237 | BEGIN_ENTRYPOINT_NOTHROW; |
238 | |
239 | // Is this host eligible to invoke the Stop method? |
240 | if ((!m_fStarted) && (!m_fFirstToLoadCLR)) |
241 | { |
242 | // Well - since this host never invoked Start, it is not eligible to invoke Stop. |
243 | // Semantically, for such a host, CLR is not available in the process. The only |
244 | // exception to this condition is the host that first loaded this version of the |
245 | // CLR and invoked Start method. For details, refer to comments in CorHost2::Start implementation. |
246 | hr = HOST_E_CLRNOTAVAILABLE; |
247 | } |
248 | else |
249 | { |
250 | while (TRUE) |
251 | { |
252 | LONG refCount = m_RefCount; |
253 | if (refCount == 0) |
254 | { |
255 | hr = HOST_E_CLRNOTAVAILABLE; |
256 | break; |
257 | } |
258 | else |
259 | if (FastInterlockCompareExchange(&m_RefCount, refCount - 1, refCount) == refCount) |
260 | { |
261 | // Indicate that we have got a Stop for a corresponding Start call from the |
262 | // Host. Semantically, CoreCLR has stopped for them. |
263 | m_fStarted = FALSE; |
264 | |
265 | if (refCount > 1) |
266 | { |
267 | hr=S_FALSE; |
268 | break; |
269 | } |
270 | else |
271 | { |
272 | break; |
273 | } |
274 | } |
275 | } |
276 | } |
277 | END_ENTRYPOINT_NOTHROW; |
278 | |
279 | |
280 | return hr; |
281 | } |
282 | |
283 | |
284 | HRESULT CorHost2::GetCurrentAppDomainId(DWORD *pdwAppDomainId) |
285 | { |
286 | CONTRACTL |
287 | { |
288 | NOTHROW; |
289 | GC_NOTRIGGER; |
290 | ENTRY_POINT; |
291 | } |
292 | CONTRACTL_END; |
293 | |
294 | // No point going further if the runtime is not running... |
295 | // We use CanRunManagedCode() instead of IsRuntimeActive() because this allows us |
296 | // to specify test using the form that does not trigger a GC. |
297 | if (!(g_fEEStarted && CanRunManagedCode(LoaderLockCheck::None))) |
298 | { |
299 | return HOST_E_CLRNOTAVAILABLE; |
300 | } |
301 | |
302 | HRESULT hr = S_OK; |
303 | |
304 | BEGIN_ENTRYPOINT_NOTHROW; |
305 | |
306 | if(pdwAppDomainId == NULL) |
307 | { |
308 | hr = E_POINTER; |
309 | } |
310 | else |
311 | { |
312 | Thread *pThread = GetThread(); |
313 | if (!pThread) |
314 | { |
315 | hr = E_UNEXPECTED; |
316 | } |
317 | else |
318 | { |
319 | *pdwAppDomainId = SystemDomain::GetCurrentDomain()->GetId().m_dwId; |
320 | } |
321 | } |
322 | |
323 | END_ENTRYPOINT_NOTHROW; |
324 | |
325 | return hr; |
326 | } |
327 | |
328 | HRESULT CorHost2::ExecuteApplication(LPCWSTR pwzAppFullName, |
329 | DWORD dwManifestPaths, |
330 | LPCWSTR *ppwzManifestPaths, |
331 | DWORD dwActivationData, |
332 | LPCWSTR *ppwzActivationData, |
333 | int *pReturnValue) |
334 | { |
335 | return E_NOTIMPL; |
336 | } |
337 | |
338 | /* |
339 | * This method processes the arguments sent to the host which are then used |
340 | * to invoke the main method. |
341 | * Note - |
342 | * [0] - points to the assemblyName that has been sent by the host. |
343 | * The rest are the arguments sent to the assembly. |
344 | * Also note, this might not always return the exact same identity as the cmdLine |
345 | * used to invoke the method. |
346 | * |
347 | * For example :- |
348 | * ActualCmdLine - Foo arg1 arg2. |
349 | * (Host1) - Full_path_to_Foo arg1 arg2 |
350 | */ |
351 | void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) |
352 | { |
353 | CONTRACTL |
354 | { |
355 | THROWS; |
356 | GC_TRIGGERS; |
357 | MODE_COOPERATIVE; |
358 | } |
359 | CONTRACTL_END; |
360 | |
361 | // Send the command line to EventPipe. |
362 | #ifdef FEATURE_PERFTRACING |
363 | EventPipe::SaveCommandLine(pwzAssemblyPath, argc, argv); |
364 | #endif // FEATURE_PERFTRACING |
365 | |
366 | // Send the command line to System.Environment. |
367 | struct _gc |
368 | { |
369 | PTRARRAYREF cmdLineArgs; |
370 | } gc; |
371 | |
372 | ZeroMemory(&gc, sizeof(gc)); |
373 | GCPROTECT_BEGIN(gc); |
374 | |
375 | gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); |
376 | OBJECTREF orAssemblyPath = StringObject::NewString(pwzAssemblyPath); |
377 | gc.cmdLineArgs->SetAt(0, orAssemblyPath); |
378 | |
379 | for (int i = 0; i < argc; ++i) |
380 | { |
381 | OBJECTREF argument = StringObject::NewString(argv[i]); |
382 | gc.cmdLineArgs->SetAt(i + 1, argument); |
383 | } |
384 | |
385 | MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS); |
386 | |
387 | ARG_SLOT args[] = |
388 | { |
389 | ObjToArgSlot(gc.cmdLineArgs), |
390 | }; |
391 | setCmdLineArgs.Call(args); |
392 | |
393 | GCPROTECT_END(); |
394 | } |
395 | |
396 | HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, |
397 | LPCWSTR pwzAssemblyPath, |
398 | int argc, |
399 | LPCWSTR* argv, |
400 | DWORD *pReturnValue) |
401 | { |
402 | CONTRACTL |
403 | { |
404 | THROWS; // Throws...as we do not want it to swallow the managed exception |
405 | ENTRY_POINT; |
406 | } |
407 | CONTRACTL_END; |
408 | |
409 | // This is currently supported in default domain only |
410 | if (dwAppDomainId != DefaultADID) |
411 | return HOST_E_INVALIDOPERATION; |
412 | |
413 | // No point going further if the runtime is not running... |
414 | if (!IsRuntimeActive()) |
415 | { |
416 | return HOST_E_CLRNOTAVAILABLE; |
417 | } |
418 | |
419 | if(!pwzAssemblyPath) |
420 | return E_POINTER; |
421 | |
422 | if(argc < 0) |
423 | { |
424 | return E_INVALIDARG; |
425 | } |
426 | |
427 | if(argc > 0 && argv == NULL) |
428 | { |
429 | return E_INVALIDARG; |
430 | } |
431 | |
432 | HRESULT hr = S_OK; |
433 | |
434 | AppDomain *pCurDomain = SystemDomain::GetCurrentDomain(); |
435 | |
436 | Thread *pThread = GetThread(); |
437 | if (pThread == NULL) |
438 | { |
439 | pThread = SetupThreadNoThrow(&hr); |
440 | if (pThread == NULL) |
441 | { |
442 | goto ErrExit; |
443 | } |
444 | } |
445 | |
446 | if(pCurDomain->GetId().m_dwId != DefaultADID) |
447 | { |
448 | return HOST_E_INVALIDOPERATION; |
449 | } |
450 | |
451 | INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; |
452 | INSTALL_UNWIND_AND_CONTINUE_HANDLER; |
453 | |
454 | _ASSERTE (!pThread->PreemptiveGCDisabled()); |
455 | |
456 | Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); |
457 | |
458 | #if defined(FEATURE_MULTICOREJIT) |
459 | pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain); |
460 | #endif // defined(FEATURE_MULTICOREJIT) |
461 | |
462 | { |
463 | GCX_COOP(); |
464 | |
465 | // Here we call the managed method that gets the cmdLineArgs array. |
466 | SetCommandLineArgs(pwzAssemblyPath, argc, argv); |
467 | |
468 | PTRARRAYREF arguments = NULL; |
469 | GCPROTECT_BEGIN(arguments); |
470 | |
471 | arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass); |
472 | for (int i = 0; i < argc; ++i) |
473 | { |
474 | STRINGREF argument = StringObject::NewString(argv[i]); |
475 | arguments->SetAt(i, argument); |
476 | } |
477 | |
478 | DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */); |
479 | if (pReturnValue) |
480 | { |
481 | *pReturnValue = retval; |
482 | } |
483 | |
484 | GCPROTECT_END(); |
485 | |
486 | } |
487 | |
488 | UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; |
489 | UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; |
490 | |
491 | ErrExit: |
492 | |
493 | return hr; |
494 | } |
495 | |
496 | HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath, |
497 | LPCWSTR pwzTypeName, |
498 | LPCWSTR pwzMethodName, |
499 | LPCWSTR pwzArgument, |
500 | DWORD *pReturnValue) |
501 | { |
502 | CONTRACTL |
503 | { |
504 | NOTHROW; |
505 | ENTRY_POINT; |
506 | } |
507 | CONTRACTL_END; |
508 | |
509 | // No point going further if the runtime is not running... |
510 | if (!IsRuntimeActive()) |
511 | { |
512 | return HOST_E_CLRNOTAVAILABLE; |
513 | } |
514 | |
515 | if(! (pwzAssemblyPath && pwzTypeName && pwzMethodName) ) |
516 | return E_POINTER; |
517 | |
518 | HRESULT hr = S_OK; |
519 | |
520 | BEGIN_ENTRYPOINT_NOTHROW; |
521 | |
522 | Thread *pThread = GetThread(); |
523 | if (pThread == NULL) |
524 | { |
525 | pThread = SetupThreadNoThrow(&hr); |
526 | if (pThread == NULL) |
527 | { |
528 | goto ErrExit; |
529 | } |
530 | } |
531 | |
532 | _ASSERTE (!pThread->PreemptiveGCDisabled()); |
533 | |
534 | _ASSERTE (SystemDomain::GetCurrentDomain()->GetId().m_dwId == DefaultADID); |
535 | |
536 | INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; |
537 | INSTALL_UNWIND_AND_CONTINUE_HANDLER; |
538 | |
539 | EX_TRY |
540 | { |
541 | Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); |
542 | |
543 | SString szTypeName(pwzTypeName); |
544 | StackScratchBuffer buff1; |
545 | const char* szTypeNameUTF8 = szTypeName.GetUTF8(buff1); |
546 | MethodTable *pMT = ClassLoader::LoadTypeByNameThrowing(pAssembly, |
547 | NULL, |
548 | szTypeNameUTF8).AsMethodTable(); |
549 | |
550 | SString szMethodName(pwzMethodName); |
551 | StackScratchBuffer buff; |
552 | const char* szMethodNameUTF8 = szMethodName.GetUTF8(buff); |
553 | MethodDesc *pMethodMD = MemberLoader::FindMethod(pMT, szMethodNameUTF8, &gsig_SM_Str_RetInt); |
554 | |
555 | if (!pMethodMD) |
556 | { |
557 | hr = COR_E_MISSINGMETHOD; |
558 | } |
559 | else |
560 | { |
561 | GCX_COOP(); |
562 | |
563 | MethodDescCallSite method(pMethodMD); |
564 | |
565 | STRINGREF sref = NULL; |
566 | GCPROTECT_BEGIN(sref); |
567 | |
568 | if (pwzArgument) |
569 | sref = StringObject::NewString(pwzArgument); |
570 | |
571 | ARG_SLOT MethodArgs[] = |
572 | { |
573 | ObjToArgSlot(sref) |
574 | }; |
575 | DWORD retval = method.Call_RetI4(MethodArgs); |
576 | if (pReturnValue) |
577 | { |
578 | *pReturnValue = retval; |
579 | } |
580 | |
581 | GCPROTECT_END(); |
582 | } |
583 | } |
584 | EX_CATCH_HRESULT(hr); |
585 | |
586 | UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; |
587 | UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; |
588 | |
589 | ErrExit: |
590 | |
591 | END_ENTRYPOINT_NOTHROW; |
592 | |
593 | return hr; |
594 | } |
595 | |
596 | HRESULT ExecuteInAppDomainHelper(FExecuteInAppDomainCallback pCallback, |
597 | void * cookie) |
598 | { |
599 | STATIC_CONTRACT_THROWS; |
600 | STATIC_CONTRACT_SO_INTOLERANT; |
601 | |
602 | HRESULT hr = S_OK; |
603 | |
604 | BEGIN_SO_TOLERANT_CODE(GetThread()); |
605 | hr = pCallback(cookie); |
606 | END_SO_TOLERANT_CODE; |
607 | |
608 | return hr; |
609 | } |
610 | |
611 | HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId, |
612 | FExecuteInAppDomainCallback pCallback, |
613 | void * cookie) |
614 | { |
615 | |
616 | // No point going further if the runtime is not running... |
617 | if (!IsRuntimeActive()) |
618 | { |
619 | return HOST_E_CLRNOTAVAILABLE; |
620 | } |
621 | |
622 | // Moved this here since no point validating the pointer |
623 | // if the basic checks [above] fail |
624 | if( pCallback == NULL) |
625 | return E_POINTER; |
626 | |
627 | CONTRACTL |
628 | { |
629 | NOTHROW; |
630 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
631 | ENTRY_POINT; // This is called by a host. |
632 | } |
633 | CONTRACTL_END; |
634 | |
635 | HRESULT hr = S_OK; |
636 | |
637 | BEGIN_ENTRYPOINT_NOTHROW; |
638 | BEGIN_EXTERNAL_ENTRYPOINT(&hr); |
639 | GCX_COOP_THREAD_EXISTS(GET_THREAD()); |
640 | ENTER_DOMAIN_ID(ADID(dwAppDomainId)) |
641 | { |
642 | // We are calling an unmanaged function pointer, either an unmanaged function, or a marshaled out delegate. |
643 | // The thread should be in preemptive mode, and SO_Tolerant. |
644 | GCX_PREEMP(); |
645 | hr=ExecuteInAppDomainHelper (pCallback, cookie); |
646 | } |
647 | END_DOMAIN_TRANSITION; |
648 | END_EXTERNAL_ENTRYPOINT; |
649 | END_ENTRYPOINT_NOTHROW; |
650 | |
651 | return hr; |
652 | } |
653 | |
654 | #define EMPTY_STRING_TO_NULL(s) {if(s && s[0] == 0) {s=NULL;};} |
655 | |
656 | HRESULT CorHost2::_CreateAppDomain( |
657 | LPCWSTR wszFriendlyName, |
658 | DWORD dwFlags, |
659 | LPCWSTR wszAppDomainManagerAssemblyName, |
660 | LPCWSTR wszAppDomainManagerTypeName, |
661 | int nProperties, |
662 | LPCWSTR* pPropertyNames, |
663 | LPCWSTR* pPropertyValues, |
664 | DWORD* pAppDomainID) |
665 | { |
666 | CONTRACTL |
667 | { |
668 | NOTHROW; |
669 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
670 | ENTRY_POINT; // This is called by a host. |
671 | } |
672 | CONTRACTL_END; |
673 | |
674 | HRESULT hr=S_OK; |
675 | |
676 | //cannot call the function more than once when single appDomain is allowed |
677 | if (m_fAppDomainCreated) |
678 | { |
679 | return HOST_E_INVALIDOPERATION; |
680 | } |
681 | |
682 | //normalize empty strings |
683 | EMPTY_STRING_TO_NULL(wszFriendlyName); |
684 | EMPTY_STRING_TO_NULL(wszAppDomainManagerAssemblyName); |
685 | EMPTY_STRING_TO_NULL(wszAppDomainManagerTypeName); |
686 | |
687 | if (pAppDomainID==NULL) |
688 | return E_POINTER; |
689 | |
690 | if (!m_fStarted) |
691 | return HOST_E_INVALIDOPERATION; |
692 | |
693 | if (wszFriendlyName == NULL) |
694 | return E_INVALIDARG; |
695 | |
696 | if ((wszAppDomainManagerAssemblyName != NULL) || (wszAppDomainManagerTypeName != NULL)) |
697 | return E_INVALIDARG; |
698 | |
699 | BEGIN_ENTRYPOINT_NOTHROW; |
700 | |
701 | BEGIN_EXTERNAL_ENTRYPOINT(&hr); |
702 | |
703 | AppDomain* pDomain = SystemDomain::System()->DefaultDomain(); |
704 | |
705 | pDomain->SetFriendlyName(wszFriendlyName); |
706 | |
707 | ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName); |
708 | |
709 | if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS) |
710 | pDomain->SetIgnoreUnhandledExceptions(); |
711 | |
712 | if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS) |
713 | pDomain->SetForceTrivialWaitOperations(); |
714 | |
715 | pDomain->CreateFusionContext(); |
716 | |
717 | { |
718 | GCX_COOP(); |
719 | |
720 | MethodDescCallSite setup(METHOD__APPCONTEXT__SETUP); |
721 | |
722 | ARG_SLOT args[3]; |
723 | args[0] = PtrToArgSlot(pPropertyNames); |
724 | args[1] = PtrToArgSlot(pPropertyValues); |
725 | args[2] = PtrToArgSlot(nProperties); |
726 | |
727 | setup.Call(args); |
728 | } |
729 | |
730 | LPCWSTR pwzNativeDllSearchDirectories = NULL; |
731 | LPCWSTR pwzTrustedPlatformAssemblies = NULL; |
732 | LPCWSTR pwzPlatformResourceRoots = NULL; |
733 | LPCWSTR pwzAppPaths = NULL; |
734 | LPCWSTR pwzAppNiPaths = NULL; |
735 | #ifdef FEATURE_COMINTEROP |
736 | LPCWSTR pwzAppLocalWinMD = NULL; |
737 | #endif |
738 | |
739 | for (int i = 0; i < nProperties; i++) |
740 | { |
741 | if (wcscmp(pPropertyNames[i], W("NATIVE_DLL_SEARCH_DIRECTORIES" )) == 0) |
742 | { |
743 | pwzNativeDllSearchDirectories = pPropertyValues[i]; |
744 | } |
745 | else |
746 | if (wcscmp(pPropertyNames[i], W("TRUSTED_PLATFORM_ASSEMBLIES" )) == 0) |
747 | { |
748 | pwzTrustedPlatformAssemblies = pPropertyValues[i]; |
749 | } |
750 | else |
751 | if (wcscmp(pPropertyNames[i], W("PLATFORM_RESOURCE_ROOTS" )) == 0) |
752 | { |
753 | pwzPlatformResourceRoots = pPropertyValues[i]; |
754 | } |
755 | else |
756 | if (wcscmp(pPropertyNames[i], W("APP_PATHS" )) == 0) |
757 | { |
758 | pwzAppPaths = pPropertyValues[i]; |
759 | } |
760 | else |
761 | if (wcscmp(pPropertyNames[i], W("APP_NI_PATHS" )) == 0) |
762 | { |
763 | pwzAppNiPaths = pPropertyValues[i]; |
764 | } |
765 | #ifdef FEATURE_COMINTEROP |
766 | else |
767 | if (wcscmp(pPropertyNames[i], W("APP_LOCAL_WINMETADATA" )) == 0) |
768 | { |
769 | pwzAppLocalWinMD = pPropertyValues[i]; |
770 | } |
771 | #endif |
772 | } |
773 | |
774 | pDomain->SetNativeDllSearchDirectories(pwzNativeDllSearchDirectories); |
775 | |
776 | { |
777 | SString sTrustedPlatformAssemblies(pwzTrustedPlatformAssemblies); |
778 | SString sPlatformResourceRoots(pwzPlatformResourceRoots); |
779 | SString sAppPaths(pwzAppPaths); |
780 | SString sAppNiPaths(pwzAppNiPaths); |
781 | |
782 | CLRPrivBinderCoreCLR *pBinder = pDomain->GetTPABinderContext(); |
783 | _ASSERTE(pBinder != NULL); |
784 | IfFailThrow(pBinder->SetupBindingPaths( |
785 | sTrustedPlatformAssemblies, |
786 | sPlatformResourceRoots, |
787 | sAppPaths, |
788 | sAppNiPaths)); |
789 | } |
790 | |
791 | #ifdef FEATURE_COMINTEROP |
792 | if (WinRTSupported()) |
793 | { |
794 | pDomain->SetWinrtApplicationContext(pwzAppLocalWinMD); |
795 | } |
796 | #endif |
797 | |
798 | *pAppDomainID=pDomain->GetId().m_dwId; |
799 | |
800 | m_fAppDomainCreated = TRUE; |
801 | |
802 | END_EXTERNAL_ENTRYPOINT; |
803 | |
804 | END_ENTRYPOINT_NOTHROW; |
805 | |
806 | return hr; |
807 | } |
808 | |
809 | HRESULT CorHost2::_CreateDelegate( |
810 | DWORD appDomainID, |
811 | LPCWSTR wszAssemblyName, |
812 | LPCWSTR wszClassName, |
813 | LPCWSTR wszMethodName, |
814 | INT_PTR* fnPtr) |
815 | { |
816 | |
817 | CONTRACTL |
818 | { |
819 | NOTHROW; |
820 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
821 | ENTRY_POINT; // This is called by a host. |
822 | } |
823 | CONTRACTL_END; |
824 | |
825 | HRESULT hr=S_OK; |
826 | |
827 | EMPTY_STRING_TO_NULL(wszAssemblyName); |
828 | EMPTY_STRING_TO_NULL(wszClassName); |
829 | EMPTY_STRING_TO_NULL(wszMethodName); |
830 | |
831 | if (fnPtr == NULL) |
832 | return E_POINTER; |
833 | *fnPtr = NULL; |
834 | |
835 | if(wszAssemblyName == NULL) |
836 | return E_INVALIDARG; |
837 | |
838 | if(wszClassName == NULL) |
839 | return E_INVALIDARG; |
840 | |
841 | if(wszMethodName == NULL) |
842 | return E_INVALIDARG; |
843 | |
844 | BEGIN_ENTRYPOINT_NOTHROW; |
845 | |
846 | BEGIN_EXTERNAL_ENTRYPOINT(&hr); |
847 | GCX_COOP_THREAD_EXISTS(GET_THREAD()); |
848 | |
849 | MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName); |
850 | MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName); |
851 | MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName); |
852 | |
853 | ADID id; |
854 | id.m_dwId=appDomainID; |
855 | |
856 | ENTER_DOMAIN_ID(id) |
857 | |
858 | GCX_PREEMP(); |
859 | |
860 | AssemblySpec spec; |
861 | spec.Init(szAssemblyName); |
862 | Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE); |
863 | |
864 | TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName); |
865 | MethodDesc* pMD=NULL; |
866 | |
867 | if (!th.IsTypeDesc()) |
868 | { |
869 | pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique); |
870 | if (pMD == NULL) |
871 | { |
872 | // try again without the FM_Unique flag (error path) |
873 | pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default); |
874 | if (pMD != NULL) |
875 | { |
876 | // the method exists but is overloaded |
877 | ThrowHR(COR_E_AMBIGUOUSMATCH); |
878 | } |
879 | } |
880 | } |
881 | |
882 | if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables()) |
883 | ThrowHR(COR_E_MISSINGMETHOD); |
884 | |
885 | UMEntryThunk *pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD); |
886 | *fnPtr = (INT_PTR)pUMEntryThunk->GetCode(); |
887 | |
888 | END_DOMAIN_TRANSITION; |
889 | |
890 | END_EXTERNAL_ENTRYPOINT; |
891 | |
892 | END_ENTRYPOINT_NOTHROW; |
893 | |
894 | return hr; |
895 | } |
896 | |
897 | HRESULT CorHost2::CreateAppDomainWithManager( |
898 | LPCWSTR wszFriendlyName, |
899 | DWORD dwFlags, |
900 | LPCWSTR wszAppDomainManagerAssemblyName, |
901 | LPCWSTR wszAppDomainManagerTypeName, |
902 | int nProperties, |
903 | LPCWSTR* pPropertyNames, |
904 | LPCWSTR* pPropertyValues, |
905 | DWORD* pAppDomainID) |
906 | { |
907 | WRAPPER_NO_CONTRACT; |
908 | |
909 | return _CreateAppDomain( |
910 | wszFriendlyName, |
911 | dwFlags, |
912 | wszAppDomainManagerAssemblyName, |
913 | wszAppDomainManagerTypeName, |
914 | nProperties, |
915 | pPropertyNames, |
916 | pPropertyValues, |
917 | pAppDomainID); |
918 | } |
919 | |
920 | HRESULT CorHost2::CreateDelegate( |
921 | DWORD appDomainID, |
922 | LPCWSTR wszAssemblyName, |
923 | LPCWSTR wszClassName, |
924 | LPCWSTR wszMethodName, |
925 | INT_PTR* fnPtr) |
926 | { |
927 | WRAPPER_NO_CONTRACT; |
928 | |
929 | return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr); |
930 | } |
931 | |
932 | HRESULT CorHost2::Authenticate(ULONGLONG authKey) |
933 | { |
934 | CONTRACTL |
935 | { |
936 | NOTHROW; |
937 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
938 | ENTRY_POINT; // This is called by a host. |
939 | } |
940 | CONTRACTL_END; |
941 | |
942 | // Host authentication was used by Silverlight. It is no longer relevant for CoreCLR. |
943 | return S_OK; |
944 | } |
945 | |
946 | HRESULT CorHost2::RegisterMacEHPort() |
947 | { |
948 | CONTRACTL |
949 | { |
950 | NOTHROW; |
951 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
952 | ENTRY_POINT; // This is called by a host. |
953 | } |
954 | CONTRACTL_END; |
955 | |
956 | return S_OK; |
957 | } |
958 | |
959 | HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag) |
960 | { |
961 | CONTRACTL |
962 | { |
963 | NOTHROW; |
964 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
965 | ENTRY_POINT; // This is called by a host. |
966 | } |
967 | CONTRACTL_END; |
968 | |
969 | if (g_fEEStarted) |
970 | { |
971 | return HOST_E_INVALIDOPERATION; |
972 | } |
973 | |
974 | m_dwStartupFlags = flag; |
975 | |
976 | return S_OK; |
977 | } |
978 | |
979 | |
980 | |
981 | HRESULT SuspendEEForPause() |
982 | { |
983 | CONTRACTL |
984 | { |
985 | NOTHROW; |
986 | MODE_PREEMPTIVE; |
987 | GC_TRIGGERS; |
988 | } |
989 | CONTRACTL_END; |
990 | |
991 | HRESULT hr = S_OK; |
992 | |
993 | // In CoreCLR, we always resume from the same thread that paused. So we can simply suspend the EE from this thread, |
994 | // knowing we'll restart from the same thread. |
995 | ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER); |
996 | |
997 | return hr; |
998 | } |
999 | |
1000 | HRESULT RestartEEFromPauseAndSetResumeEvent() |
1001 | { |
1002 | CONTRACTL |
1003 | { |
1004 | NOTHROW; |
1005 | MODE_PREEMPTIVE; |
1006 | GC_TRIGGERS; |
1007 | } |
1008 | CONTRACTL_END; |
1009 | |
1010 | // see comments in SuspendEEFromPause |
1011 | ThreadSuspend::RestartEE(FALSE, TRUE); |
1012 | |
1013 | _ASSERTE(g_ClrResumeEvent.IsValid()); |
1014 | g_ClrResumeEvent.Set(); |
1015 | |
1016 | return S_OK; |
1017 | } |
1018 | |
1019 | |
1020 | |
1021 | CorExecutionManager::CorExecutionManager() |
1022 | : m_dwFlags(0), m_pauseStartTime(0) |
1023 | { |
1024 | LIMITED_METHOD_CONTRACT; |
1025 | g_IsPaused = FALSE; |
1026 | g_PauseTime = 0; |
1027 | } |
1028 | |
1029 | HRESULT CorExecutionManager::Pause(DWORD dwAppDomainId, DWORD dwFlags) |
1030 | { |
1031 | CONTRACTL |
1032 | { |
1033 | NOTHROW; |
1034 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
1035 | ENTRY_POINT; // This is called by a host. |
1036 | } |
1037 | CONTRACTL_END; |
1038 | |
1039 | HRESULT hr = S_OK; |
1040 | |
1041 | |
1042 | if(g_IsPaused) |
1043 | return E_FAIL; |
1044 | |
1045 | EX_TRY |
1046 | { |
1047 | if(!g_ClrResumeEvent.IsValid()) |
1048 | g_ClrResumeEvent.CreateManualEvent(FALSE); |
1049 | else |
1050 | g_ClrResumeEvent.Reset(); |
1051 | |
1052 | } |
1053 | EX_CATCH_HRESULT(hr); |
1054 | |
1055 | if (FAILED(hr)) |
1056 | return hr; |
1057 | |
1058 | BEGIN_ENTRYPOINT_NOTHROW; |
1059 | |
1060 | m_dwFlags = dwFlags; |
1061 | |
1062 | |
1063 | if (SUCCEEDED(hr)) |
1064 | { |
1065 | g_IsPaused = TRUE; |
1066 | |
1067 | hr = SuspendEEForPause(); |
1068 | |
1069 | // Even though this is named with TickCount, it returns milliseconds |
1070 | m_pauseStartTime = (INT64)CLRGetTickCount64(); |
1071 | } |
1072 | |
1073 | END_ENTRYPOINT_NOTHROW; |
1074 | |
1075 | return hr; |
1076 | } |
1077 | |
1078 | |
1079 | HRESULT CorExecutionManager::Resume(DWORD dwAppDomainId) |
1080 | { |
1081 | CONTRACTL |
1082 | { |
1083 | NOTHROW; |
1084 | if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} |
1085 | ENTRY_POINT; // This is called by a host. |
1086 | } |
1087 | CONTRACTL_END; |
1088 | |
1089 | HRESULT hr = S_OK; |
1090 | |
1091 | |
1092 | if(!g_IsPaused) |
1093 | return E_FAIL; |
1094 | |
1095 | // GCThread is the thread that did the Pause. Resume should also happen on that same thread |
1096 | Thread *pThread = GetThread(); |
1097 | if(pThread != ThreadSuspend::GetSuspensionThread()) |
1098 | { |
1099 | _ASSERTE(!"HOST BUG: The same thread that did Pause should do the Resume" ); |
1100 | return E_FAIL; |
1101 | } |
1102 | |
1103 | BEGIN_ENTRYPOINT_NOTHROW; |
1104 | |
1105 | // Even though this is named with TickCount, it returns milliseconds |
1106 | INT64 currTime = (INT64)CLRGetTickCount64(); |
1107 | _ASSERTE(currTime >= m_pauseStartTime); |
1108 | _ASSERTE(m_pauseStartTime != 0); |
1109 | |
1110 | g_PauseTime += (currTime - m_pauseStartTime); |
1111 | g_IsPaused = FALSE; |
1112 | |
1113 | hr = RestartEEFromPauseAndSetResumeEvent(); |
1114 | |
1115 | |
1116 | END_ENTRYPOINT_NOTHROW; |
1117 | |
1118 | return hr; |
1119 | } |
1120 | |
1121 | |
1122 | #endif //!DACCESS_COMPILE |
1123 | |
1124 | #ifndef DACCESS_COMPILE |
1125 | SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags = STARTUP_CONCURRENT_GC); |
1126 | #else |
1127 | SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags); |
1128 | #endif |
1129 | |
1130 | STARTUP_FLAGS CorHost2::GetStartupFlags() |
1131 | { |
1132 | return m_dwStartupFlags; |
1133 | } |
1134 | |
1135 | #ifndef DACCESS_COMPILE |
1136 | |
1137 | |
1138 | #ifdef FEATURE_COMINTEROP |
1139 | |
1140 | // Enumerate currently existing domains. |
1141 | HRESULT CorRuntimeHostBase::EnumDomains(HDOMAINENUM *hEnum) |
1142 | { |
1143 | CONTRACTL |
1144 | { |
1145 | NOTHROW; |
1146 | MODE_PREEMPTIVE; |
1147 | WRAPPER(GC_TRIGGERS); |
1148 | ENTRY_POINT; |
1149 | } |
1150 | CONTRACTL_END; |
1151 | |
1152 | if(hEnum == NULL) return E_POINTER; |
1153 | |
1154 | // Thread setup happens in BEGIN_EXTERNAL_ENTRYPOINT below. |
1155 | // If the runtime has not started, we have nothing to do. |
1156 | if (!g_fEEStarted) |
1157 | { |
1158 | return HOST_E_CLRNOTAVAILABLE; |
1159 | } |
1160 | |
1161 | HRESULT hr = E_OUTOFMEMORY; |
1162 | *hEnum = NULL; |
1163 | BEGIN_ENTRYPOINT_NOTHROW; |
1164 | |
1165 | BEGIN_EXTERNAL_ENTRYPOINT(&hr) |
1166 | |
1167 | AppDomainIterator *pEnum = new (nothrow) AppDomainIterator(FALSE); |
1168 | if(pEnum) { |
1169 | *hEnum = (HDOMAINENUM) pEnum; |
1170 | hr = S_OK; |
1171 | } |
1172 | END_EXTERNAL_ENTRYPOINT; |
1173 | END_ENTRYPOINT_NOTHROW; |
1174 | |
1175 | return hr; |
1176 | } |
1177 | |
1178 | #endif // FEATURE_COMINTEROP |
1179 | |
1180 | extern "C" |
1181 | HRESULT GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk) |
1182 | { |
1183 | WRAPPER_NO_CONTRACT; |
1184 | |
1185 | return CorHost2::CreateObject(riid, (void**)ppUnk); |
1186 | } |
1187 | |
1188 | |
1189 | STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) |
1190 | { |
1191 | return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr); |
1192 | } |
1193 | |
1194 | STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode) |
1195 | { |
1196 | WRAPPER_NO_CONTRACT; |
1197 | STATIC_CONTRACT_SO_TOLERANT; |
1198 | |
1199 | if (!m_fStarted) |
1200 | return HOST_E_INVALIDOPERATION; |
1201 | |
1202 | if (!g_fEEStarted) |
1203 | { |
1204 | return HOST_E_CLRNOTAVAILABLE; |
1205 | } |
1206 | |
1207 | if(!m_fAppDomainCreated) |
1208 | { |
1209 | return HOST_E_INVALIDOPERATION; |
1210 | } |
1211 | |
1212 | HRESULT hr=S_OK; |
1213 | BEGIN_ENTRYPOINT_NOTHROW; |
1214 | |
1215 | if (!m_fFirstToLoadCLR) |
1216 | { |
1217 | _ASSERTE(!"Not reachable" ); |
1218 | hr = HOST_E_CLRNOTAVAILABLE; |
1219 | } |
1220 | else |
1221 | { |
1222 | LONG refCount = m_RefCount; |
1223 | if (refCount == 0) |
1224 | { |
1225 | hr = HOST_E_CLRNOTAVAILABLE; |
1226 | } |
1227 | else |
1228 | if (1 == refCount) |
1229 | { |
1230 | // Stop coreclr on unload. |
1231 | EEShutDown(FALSE); |
1232 | } |
1233 | else |
1234 | { |
1235 | _ASSERTE(!"Not reachable" ); |
1236 | hr = S_FALSE; |
1237 | } |
1238 | } |
1239 | END_ENTRYPOINT_NOTHROW; |
1240 | |
1241 | if (pLatchedExitCode) |
1242 | { |
1243 | *pLatchedExitCode = GetLatchedExitCode(); |
1244 | } |
1245 | |
1246 | return hr; |
1247 | } |
1248 | |
1249 | HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone) |
1250 | { |
1251 | return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr); |
1252 | } |
1253 | |
1254 | HRESULT CorRuntimeHostBase::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode) |
1255 | { |
1256 | CONTRACTL |
1257 | { |
1258 | NOTHROW; |
1259 | GC_TRIGGERS; |
1260 | MODE_ANY; |
1261 | FORBID_FAULT; // Unloading domains cannot fail due to OOM |
1262 | ENTRY_POINT; |
1263 | } |
1264 | CONTRACTL_END; |
1265 | |
1266 | return COR_E_CANNOTUNLOADAPPDOMAIN; |
1267 | } |
1268 | |
1269 | //***************************************************************************** |
1270 | // Fiber Methods |
1271 | //***************************************************************************** |
1272 | |
1273 | HRESULT CorRuntimeHostBase::LocksHeldByLogicalThread(DWORD *pCount) |
1274 | { |
1275 | if (!pCount) |
1276 | return E_POINTER; |
1277 | |
1278 | CONTRACTL |
1279 | { |
1280 | NOTHROW; |
1281 | GC_NOTRIGGER; |
1282 | ENTRY_POINT; |
1283 | } |
1284 | CONTRACTL_END; |
1285 | |
1286 | BEGIN_ENTRYPOINT_NOTHROW; |
1287 | |
1288 | Thread* pThread = GetThread(); |
1289 | if (pThread == NULL) |
1290 | *pCount = 0; |
1291 | else |
1292 | *pCount = pThread->m_dwLockCount; |
1293 | |
1294 | END_ENTRYPOINT_NOTHROW; |
1295 | |
1296 | return S_OK; |
1297 | } |
1298 | |
1299 | //***************************************************************************** |
1300 | // ICorConfiguration |
1301 | //***************************************************************************** |
1302 | |
1303 | //***************************************************************************** |
1304 | // IUnknown |
1305 | //***************************************************************************** |
1306 | |
1307 | ULONG CorRuntimeHostBase::AddRef() |
1308 | { |
1309 | CONTRACTL |
1310 | { |
1311 | WRAPPER(THROWS); |
1312 | WRAPPER(GC_TRIGGERS); |
1313 | SO_TOLERANT; |
1314 | } |
1315 | CONTRACTL_END; |
1316 | return InterlockedIncrement(&m_cRef); |
1317 | } |
1318 | |
1319 | |
1320 | ULONG CorHost2::Release() |
1321 | { |
1322 | LIMITED_METHOD_CONTRACT; |
1323 | |
1324 | ULONG cRef = InterlockedDecrement(&m_cRef); |
1325 | if (!cRef) { |
1326 | delete this; |
1327 | } |
1328 | |
1329 | return (cRef); |
1330 | } |
1331 | |
1332 | |
1333 | |
1334 | HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk) |
1335 | { |
1336 | if (!ppUnk) |
1337 | return E_POINTER; |
1338 | |
1339 | CONTRACTL |
1340 | { |
1341 | NOTHROW; |
1342 | GC_NOTRIGGER; |
1343 | SO_TOLERANT; // no global state updates that need guarding. |
1344 | } |
1345 | CONTRACTL_END; |
1346 | |
1347 | if (ppUnk == NULL) |
1348 | { |
1349 | return E_POINTER; |
1350 | } |
1351 | |
1352 | *ppUnk = 0; |
1353 | |
1354 | // Deliberately do NOT hand out ICorConfiguration. They must explicitly call |
1355 | // GetConfiguration to obtain that interface. |
1356 | if (riid == IID_IUnknown) |
1357 | { |
1358 | *ppUnk = static_cast<IUnknown *>(static_cast<ICLRRuntimeHost *>(this)); |
1359 | } |
1360 | else if (riid == IID_ICLRRuntimeHost) |
1361 | { |
1362 | *ppUnk = static_cast<ICLRRuntimeHost *>(this); |
1363 | } |
1364 | else if (riid == IID_ICLRRuntimeHost2) |
1365 | { |
1366 | ULONG version = 2; |
1367 | if (m_Version == 0) |
1368 | FastInterlockCompareExchange((LONG*)&m_Version, version, 0); |
1369 | |
1370 | *ppUnk = static_cast<ICLRRuntimeHost2 *>(this); |
1371 | } |
1372 | else if (riid == IID_ICLRRuntimeHost4) |
1373 | { |
1374 | ULONG version = 4; |
1375 | if (m_Version == 0) |
1376 | FastInterlockCompareExchange((LONG*)&m_Version, version, 0); |
1377 | |
1378 | *ppUnk = static_cast<ICLRRuntimeHost4 *>(this); |
1379 | } |
1380 | else if (riid == IID_ICLRExecutionManager) |
1381 | { |
1382 | ULONG version = 2; |
1383 | if (m_Version == 0) |
1384 | FastInterlockCompareExchange((LONG*)&m_Version, version, 0); |
1385 | |
1386 | *ppUnk = static_cast<ICLRExecutionManager *>(this); |
1387 | } |
1388 | #ifndef FEATURE_PAL |
1389 | else if (riid == IID_IPrivateManagedExceptionReporting) |
1390 | { |
1391 | *ppUnk = static_cast<IPrivateManagedExceptionReporting *>(this); |
1392 | } |
1393 | #endif // !FEATURE_PAL |
1394 | else |
1395 | return (E_NOINTERFACE); |
1396 | AddRef(); |
1397 | return (S_OK); |
1398 | } |
1399 | |
1400 | |
1401 | #ifndef FEATURE_PAL |
1402 | HRESULT CorHost2::GetBucketParametersForCurrentException(BucketParameters *pParams) |
1403 | { |
1404 | CONTRACTL |
1405 | { |
1406 | NOTHROW; |
1407 | GC_NOTRIGGER; |
1408 | SO_TOLERANT; |
1409 | } |
1410 | CONTRACTL_END; |
1411 | |
1412 | HRESULT hr = S_OK; |
1413 | BEGIN_ENTRYPOINT_NOTHROW; |
1414 | |
1415 | // To avoid confusion, clear the buckets. |
1416 | memset(pParams, 0, sizeof(BucketParameters)); |
1417 | |
1418 | // Defer to Watson helper. |
1419 | hr = ::GetBucketParametersForCurrentException(pParams); |
1420 | |
1421 | END_ENTRYPOINT_NOTHROW; |
1422 | |
1423 | return hr; |
1424 | } |
1425 | #endif // !FEATURE_PAL |
1426 | |
1427 | HRESULT CorHost2::CreateObject(REFIID riid, void **ppUnk) |
1428 | { |
1429 | CONTRACTL |
1430 | { |
1431 | NOTHROW; |
1432 | GC_NOTRIGGER; |
1433 | SO_TOLERANT; |
1434 | } |
1435 | CONTRACTL_END; |
1436 | |
1437 | HRESULT hr = S_OK; |
1438 | |
1439 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW; ); |
1440 | CorHost2 *pCorHost = new (nothrow) CorHost2(); |
1441 | if (!pCorHost) |
1442 | { |
1443 | hr = E_OUTOFMEMORY; |
1444 | } |
1445 | else |
1446 | { |
1447 | hr = pCorHost->QueryInterface(riid, ppUnk); |
1448 | if (FAILED(hr)) |
1449 | delete pCorHost; |
1450 | } |
1451 | END_SO_INTOLERANT_CODE; |
1452 | return (hr); |
1453 | } |
1454 | |
1455 | |
1456 | //----------------------------------------------------------------------------- |
1457 | // MapFile - Maps a file into the runtime in a non-standard way |
1458 | //----------------------------------------------------------------------------- |
1459 | |
1460 | static PEImage *MapFileHelper(HANDLE hFile) |
1461 | { |
1462 | CONTRACTL |
1463 | { |
1464 | THROWS; |
1465 | GC_TRIGGERS; |
1466 | MODE_ANY; |
1467 | } |
1468 | CONTRACTL_END; |
1469 | |
1470 | GCX_PREEMP(); |
1471 | |
1472 | HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)); |
1473 | if (hFileMap == NULL) |
1474 | ThrowLastError(); |
1475 | |
1476 | CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0)); |
1477 | if (base == NULL) |
1478 | ThrowLastError(); |
1479 | |
1480 | DWORD dwSize = SafeGetFileSize(hFile, NULL); |
1481 | if (dwSize == 0xffffffff && GetLastError() != NOERROR) |
1482 | { |
1483 | ThrowLastError(); |
1484 | } |
1485 | PEImageHolder pImage(PEImage::LoadFlat(base, dwSize)); |
1486 | return pImage.Extract(); |
1487 | } |
1488 | |
1489 | HRESULT CorRuntimeHostBase::MapFile(HANDLE hFile, HMODULE* phHandle) |
1490 | { |
1491 | CONTRACTL |
1492 | { |
1493 | NOTHROW; |
1494 | GC_TRIGGERS; |
1495 | MODE_PREEMPTIVE; |
1496 | ENTRY_POINT; |
1497 | } |
1498 | CONTRACTL_END; |
1499 | |
1500 | HRESULT hr; |
1501 | BEGIN_ENTRYPOINT_NOTHROW; |
1502 | |
1503 | BEGIN_EXTERNAL_ENTRYPOINT(&hr) |
1504 | { |
1505 | *phHandle = (HMODULE) (MapFileHelper(hFile)->GetLoadedLayout()->GetBase()); |
1506 | } |
1507 | END_EXTERNAL_ENTRYPOINT; |
1508 | END_ENTRYPOINT_NOTHROW; |
1509 | |
1510 | |
1511 | return hr; |
1512 | } |
1513 | |
1514 | /////////////////////////////////////////////////////////////////////////////// |
1515 | // IDebuggerInfo::IsDebuggerAttached |
1516 | |
1517 | LONG CorHost2::m_RefCount = 0; |
1518 | |
1519 | IHostControl *CorHost2::m_HostControl = NULL; |
1520 | |
1521 | #ifdef _DEBUG |
1522 | extern void ValidateHostInterface(); |
1523 | #endif |
1524 | |
1525 | static Volatile<BOOL> fOneOnly = 0; |
1526 | |
1527 | /////////////////////////////////////////////////////////////////////////////// |
1528 | // ICLRRuntimeHost::SetHostControl |
1529 | /////////////////////////////////////////////////////////////////////////////// |
1530 | HRESULT CorHost2::SetHostControl(IHostControl* pHostControl) |
1531 | { |
1532 | CONTRACTL |
1533 | { |
1534 | NOTHROW; |
1535 | GC_NOTRIGGER; |
1536 | ENTRY_POINT; |
1537 | } |
1538 | CONTRACTL_END; |
1539 | if (m_Version < 2) |
1540 | // CLR is hosted with v1 hosting interface. Some part of v2 hosting API are disabled. |
1541 | return HOST_E_INVALIDOPERATION; |
1542 | |
1543 | if (pHostControl == 0) |
1544 | return E_INVALIDARG; |
1545 | |
1546 | // If Runtime has been started, do not allow setting HostMemoryManager |
1547 | if (g_fEEStarted) |
1548 | return E_ACCESSDENIED; |
1549 | |
1550 | HRESULT hr = S_OK; |
1551 | |
1552 | BEGIN_ENTRYPOINT_NOTHROW; |
1553 | |
1554 | DWORD dwSwitchCount = 0; |
1555 | |
1556 | while (FastInterlockExchange((LONG*)&fOneOnly, 1) == 1) |
1557 | { |
1558 | __SwitchToThread(0, ++dwSwitchCount); |
1559 | } |
1560 | |
1561 | |
1562 | if (m_HostControl == NULL) |
1563 | { |
1564 | m_HostControl = pHostControl; |
1565 | m_HostControl->AddRef(); |
1566 | } |
1567 | |
1568 | goto ErrExit; |
1569 | |
1570 | ErrExit: |
1571 | fOneOnly = 0; |
1572 | |
1573 | END_ENTRYPOINT_NOTHROW; |
1574 | |
1575 | return hr; |
1576 | } |
1577 | |
1578 | class CCLRPolicyManager: public ICLRPolicyManager |
1579 | { |
1580 | public: |
1581 | virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(EClrOperation operation, |
1582 | EPolicyAction action) |
1583 | { |
1584 | LIMITED_METHOD_CONTRACT; |
1585 | return E_NOTIMPL; |
1586 | } |
1587 | |
1588 | virtual HRESULT STDMETHODCALLTYPE SetTimeout(EClrOperation operation, |
1589 | DWORD dwMilliseconds) |
1590 | { |
1591 | LIMITED_METHOD_CONTRACT; |
1592 | return E_NOTIMPL; |
1593 | } |
1594 | |
1595 | virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(EClrOperation operation, |
1596 | EPolicyAction action) |
1597 | { |
1598 | LIMITED_METHOD_CONTRACT; |
1599 | return E_NOTIMPL; |
1600 | } |
1601 | |
1602 | virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(EClrOperation operation, DWORD dwMilliseconds, |
1603 | EPolicyAction action) |
1604 | { |
1605 | LIMITED_METHOD_CONTRACT; |
1606 | return E_NOTIMPL; |
1607 | } |
1608 | |
1609 | virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(EClrFailure failure, |
1610 | EPolicyAction action) |
1611 | { |
1612 | // This is enabled for CoreCLR since a host can use this to |
1613 | // specify action for handling AV. |
1614 | STATIC_CONTRACT_ENTRY_POINT; |
1615 | LIMITED_METHOD_CONTRACT; |
1616 | HRESULT hr; |
1617 | // For CoreCLR, this method just supports FAIL_AccessViolation as a valid |
1618 | // failure input arg. The validation of the specified action for the failure |
1619 | // will be done in EEPolicy::IsValidActionForFailure. |
1620 | if (failure != FAIL_AccessViolation) |
1621 | { |
1622 | return E_INVALIDARG; |
1623 | } |
1624 | BEGIN_ENTRYPOINT_NOTHROW; |
1625 | hr = GetEEPolicy()->SetActionOnFailure(failure,action); |
1626 | END_ENTRYPOINT_NOTHROW; |
1627 | return hr; |
1628 | } |
1629 | |
1630 | virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(EClrUnhandledException policy) |
1631 | { |
1632 | LIMITED_METHOD_CONTRACT; |
1633 | return E_NOTIMPL; |
1634 | } |
1635 | |
1636 | virtual ULONG STDMETHODCALLTYPE AddRef(void) |
1637 | { |
1638 | LIMITED_METHOD_CONTRACT; |
1639 | STATIC_CONTRACT_SO_TOLERANT; |
1640 | return 1; |
1641 | } |
1642 | |
1643 | virtual ULONG STDMETHODCALLTYPE Release(void) |
1644 | { |
1645 | LIMITED_METHOD_CONTRACT; |
1646 | STATIC_CONTRACT_SO_TOLERANT; |
1647 | return 1; |
1648 | } |
1649 | |
1650 | BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, |
1651 | void **ppvObject) |
1652 | { |
1653 | LIMITED_METHOD_CONTRACT; |
1654 | STATIC_CONTRACT_SO_TOLERANT; |
1655 | if (riid != IID_ICLRPolicyManager && riid != IID_IUnknown) |
1656 | return (E_NOINTERFACE); |
1657 | |
1658 | // Ensure that the out going pointer is not null |
1659 | if (ppvObject == NULL) |
1660 | return E_POINTER; |
1661 | |
1662 | *ppvObject = this; |
1663 | return S_OK; |
1664 | } |
1665 | }; |
1666 | |
1667 | static CCLRPolicyManager s_PolicyManager; |
1668 | |
1669 | |
1670 | |
1671 | void ProcessEventForHost(EClrEvent event, void *data) |
1672 | { |
1673 | } |
1674 | |
1675 | // We do not call ProcessEventForHost for stack overflow, since we have limit stack |
1676 | // and we should avoid calling GCX_PREEMPT |
1677 | void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant) |
1678 | { |
1679 | } |
1680 | |
1681 | BOOL IsHostRegisteredForEvent(EClrEvent event) |
1682 | { |
1683 | WRAPPER_NO_CONTRACT; |
1684 | return FALSE; |
1685 | } |
1686 | |
1687 | inline size_t SizeInKBytes(size_t cbSize) |
1688 | { |
1689 | LIMITED_METHOD_CONTRACT; |
1690 | size_t cb = (cbSize % 1024) ? 1 : 0; |
1691 | return ((cbSize / 1024) + cb); |
1692 | } |
1693 | |
1694 | SIZE_T Host_SegmentSize = 0; |
1695 | SIZE_T Host_MaxGen0Size = 0; |
1696 | BOOL Host_fSegmentSizeSet = FALSE; |
1697 | BOOL Host_fMaxGen0SizeSet = FALSE; |
1698 | |
1699 | void UpdateGCSettingFromHost () |
1700 | { |
1701 | WRAPPER_NO_CONTRACT; |
1702 | _ASSERTE (g_pConfig); |
1703 | if (Host_fSegmentSizeSet) |
1704 | { |
1705 | g_pConfig->SetSegmentSize(Host_SegmentSize); |
1706 | } |
1707 | if (Host_fMaxGen0SizeSet) |
1708 | { |
1709 | g_pConfig->SetGCgen0size(Host_MaxGen0Size); |
1710 | } |
1711 | } |
1712 | |
1713 | #if defined(FEATURE_WINDOWSPHONE) |
1714 | class CCLRGCManager: public ICLRGCManager2 |
1715 | { |
1716 | public: |
1717 | virtual HRESULT STDMETHODCALLTYPE Collect(LONG Generation) |
1718 | { |
1719 | CONTRACTL |
1720 | { |
1721 | NOTHROW; |
1722 | GC_TRIGGERS; |
1723 | ENTRY_POINT; |
1724 | } |
1725 | CONTRACTL_END; |
1726 | |
1727 | HRESULT hr = S_OK; |
1728 | |
1729 | if (Generation > (int) GCHeapUtilities::GetGCHeap()->GetMaxGeneration()) |
1730 | hr = E_INVALIDARG; |
1731 | |
1732 | if (SUCCEEDED(hr)) |
1733 | { |
1734 | // Set up a Thread object if this is called on a native thread. |
1735 | Thread *pThread; |
1736 | pThread = GetThread(); |
1737 | if (pThread == NULL) |
1738 | pThread = SetupThreadNoThrow(&hr); |
1739 | if (pThread != NULL) |
1740 | { |
1741 | BEGIN_ENTRYPOINT_NOTHROW_WITH_THREAD(pThread); |
1742 | GCX_COOP(); |
1743 | |
1744 | EX_TRY |
1745 | { |
1746 | STRESS_LOG0(LF_GC, LL_INFO100, "Host triggers GC\n" ); |
1747 | hr = GCHeapUtilities::GetGCHeap()->GarbageCollect(Generation); |
1748 | } |
1749 | EX_CATCH |
1750 | { |
1751 | hr = GET_EXCEPTION()->GetHR(); |
1752 | } |
1753 | EX_END_CATCH(SwallowAllExceptions); |
1754 | |
1755 | END_ENTRYPOINT_NOTHROW_WITH_THREAD; |
1756 | } |
1757 | } |
1758 | |
1759 | return (hr); |
1760 | } |
1761 | |
1762 | virtual HRESULT STDMETHODCALLTYPE GetStats(COR_GC_STATS *pStats) |
1763 | { |
1764 | CONTRACTL |
1765 | { |
1766 | NOTHROW; |
1767 | GC_NOTRIGGER; |
1768 | ENTRY_POINT; |
1769 | } |
1770 | CONTRACTL_END; |
1771 | |
1772 | HRESULT hr = S_OK; |
1773 | BEGIN_ENTRYPOINT_NOTHROW; |
1774 | |
1775 | #if defined(ENABLE_PERF_COUNTERS) |
1776 | |
1777 | Perf_GC *pgc = &GetPerfCounters().m_GC; |
1778 | |
1779 | if (!pStats) |
1780 | IfFailGo(E_INVALIDARG); |
1781 | |
1782 | if (pStats->Flags & COR_GC_COUNTS) |
1783 | { |
1784 | pStats->ExplicitGCCount = pgc->cInducedGCs; |
1785 | |
1786 | for (int idx=0; idx<3; idx++) |
1787 | pStats->GenCollectionsTaken[idx] = pgc->cGenCollections[idx]; |
1788 | } |
1789 | |
1790 | if (pStats->Flags & COR_GC_MEMORYUSAGE) |
1791 | { |
1792 | pStats->CommittedKBytes = SizeInKBytes(pgc->cTotalCommittedBytes); |
1793 | pStats->ReservedKBytes = SizeInKBytes(pgc->cTotalReservedBytes); |
1794 | pStats->Gen0HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[0]); |
1795 | pStats->Gen1HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[1]); |
1796 | pStats->Gen2HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[2]); |
1797 | pStats->LargeObjectHeapSizeKBytes = SizeInKBytes(pgc->cLrgObjSize); |
1798 | pStats->KBytesPromotedFromGen0 = SizeInKBytes(pgc->cbPromotedMem[0]); |
1799 | pStats->KBytesPromotedFromGen1 = SizeInKBytes(pgc->cbPromotedMem[1]); |
1800 | } |
1801 | hr = S_OK; |
1802 | ErrExit: |
1803 | #else |
1804 | hr = E_NOTIMPL; |
1805 | #endif // ENABLE_PERF_COUNTERS |
1806 | |
1807 | END_ENTRYPOINT_NOTHROW; |
1808 | return hr; |
1809 | } |
1810 | virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimits( |
1811 | DWORD SegmentSize, |
1812 | DWORD MaxGen0Size) |
1813 | { |
1814 | CONTRACTL |
1815 | { |
1816 | NOTHROW; |
1817 | GC_NOTRIGGER; |
1818 | ENTRY_POINT; |
1819 | |
1820 | } |
1821 | CONTRACTL_END; |
1822 | |
1823 | HRESULT hr = S_OK; |
1824 | BEGIN_ENTRYPOINT_NOTHROW; |
1825 | |
1826 | // Set default overrides if specified by caller. |
1827 | if (SegmentSize != (DWORD) ~0 && SegmentSize > 0) |
1828 | { |
1829 | hr = _SetGCSegmentSize(SegmentSize); |
1830 | } |
1831 | |
1832 | if (SUCCEEDED(hr) && MaxGen0Size != (DWORD) ~0 && MaxGen0Size > 0) |
1833 | { |
1834 | hr = _SetGCMaxGen0Size(MaxGen0Size); |
1835 | } |
1836 | |
1837 | END_ENTRYPOINT_NOTHROW; |
1838 | |
1839 | return (hr); |
1840 | } |
1841 | |
1842 | virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimitsEx( |
1843 | SIZE_T SegmentSize, |
1844 | SIZE_T MaxGen0Size) |
1845 | { |
1846 | CONTRACTL |
1847 | { |
1848 | NOTHROW; |
1849 | GC_NOTRIGGER; |
1850 | ENTRY_POINT; |
1851 | |
1852 | } |
1853 | CONTRACTL_END; |
1854 | |
1855 | HRESULT hr = S_OK; |
1856 | BEGIN_ENTRYPOINT_NOTHROW; |
1857 | |
1858 | // Set default overrides if specified by caller. |
1859 | if (SegmentSize != (SIZE_T) ~0 && SegmentSize > 0) |
1860 | { |
1861 | hr = _SetGCSegmentSize(SegmentSize); |
1862 | } |
1863 | |
1864 | if (SUCCEEDED(hr) && MaxGen0Size != (SIZE_T) ~0 && MaxGen0Size > 0) |
1865 | { |
1866 | hr = _SetGCMaxGen0Size(MaxGen0Size); |
1867 | } |
1868 | |
1869 | END_ENTRYPOINT_NOTHROW; |
1870 | |
1871 | return (hr); |
1872 | } |
1873 | |
1874 | virtual ULONG STDMETHODCALLTYPE AddRef(void) |
1875 | { |
1876 | LIMITED_METHOD_CONTRACT; |
1877 | return 1; |
1878 | } |
1879 | |
1880 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk) |
1881 | { |
1882 | LIMITED_METHOD_CONTRACT; |
1883 | if (riid != IID_ICLRGCManager && riid != IID_ICLRGCManager2 && riid != IID_IUnknown) |
1884 | return (E_NOINTERFACE); |
1885 | *ppUnk = this; |
1886 | return S_OK; |
1887 | } |
1888 | |
1889 | virtual ULONG STDMETHODCALLTYPE Release(void) |
1890 | { |
1891 | LIMITED_METHOD_CONTRACT; |
1892 | return 1; |
1893 | } |
1894 | private: |
1895 | HRESULT _SetGCSegmentSize(SIZE_T SegmentSize); |
1896 | HRESULT _SetGCMaxGen0Size(SIZE_T MaxGen0Size); |
1897 | }; |
1898 | |
1899 | |
1900 | HRESULT CCLRGCManager::_SetGCSegmentSize(SIZE_T SegmentSize) |
1901 | { |
1902 | CONTRACTL |
1903 | { |
1904 | NOTHROW; |
1905 | GC_NOTRIGGER; |
1906 | SO_TOLERANT; |
1907 | } |
1908 | CONTRACTL_END; |
1909 | |
1910 | HRESULT hr = S_OK; |
1911 | |
1912 | // Sanity check the value, it must be a power of two and big enough. |
1913 | if (!GCHeapUtilities::GetGCHeap()->IsValidSegmentSize(SegmentSize)) |
1914 | { |
1915 | hr = E_INVALIDARG; |
1916 | } |
1917 | else |
1918 | { |
1919 | Host_SegmentSize = SegmentSize; |
1920 | Host_fSegmentSizeSet = TRUE; |
1921 | } |
1922 | |
1923 | return (hr); |
1924 | } |
1925 | |
1926 | HRESULT CCLRGCManager::_SetGCMaxGen0Size(SIZE_T MaxGen0Size) |
1927 | { |
1928 | CONTRACTL |
1929 | { |
1930 | NOTHROW; |
1931 | GC_NOTRIGGER; |
1932 | SO_TOLERANT; |
1933 | } |
1934 | CONTRACTL_END; |
1935 | |
1936 | HRESULT hr = S_OK; |
1937 | |
1938 | // Sanity check the value is at least large enough. |
1939 | if (!GCHeapUtilities::GetGCHeap()->IsValidGen0MaxSize(MaxGen0Size)) |
1940 | { |
1941 | hr = E_INVALIDARG; |
1942 | } |
1943 | else |
1944 | { |
1945 | Host_MaxGen0Size = MaxGen0Size; |
1946 | Host_fMaxGen0SizeSet = TRUE; |
1947 | } |
1948 | |
1949 | return (hr); |
1950 | } |
1951 | |
1952 | static CCLRGCManager s_GCManager; |
1953 | #endif //FEATURE_WINDOWSPHONE |
1954 | |
1955 | #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING |
1956 | class CCLRAppDomainResourceMonitor : public ICLRAppDomainResourceMonitor |
1957 | { |
1958 | public: |
1959 | virtual HRESULT STDMETHODCALLTYPE GetCurrentAllocated(DWORD dwAppDomainId, |
1960 | ULONGLONG* pBytesAllocated) |
1961 | { |
1962 | CONTRACTL |
1963 | { |
1964 | NOTHROW; |
1965 | GC_NOTRIGGER; |
1966 | ENTRY_POINT; |
1967 | } |
1968 | CONTRACTL_END; |
1969 | |
1970 | HRESULT hr = S_OK; |
1971 | |
1972 | BEGIN_ENTRYPOINT_NOTHROW; |
1973 | |
1974 | SystemDomain::LockHolder lh; |
1975 | |
1976 | AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD); |
1977 | if (pBytesAllocated) |
1978 | { |
1979 | *pBytesAllocated = pAppDomain->GetAllocBytes(); |
1980 | } |
1981 | |
1982 | END_ENTRYPOINT_NOTHROW; |
1983 | |
1984 | return (hr); |
1985 | } |
1986 | |
1987 | virtual HRESULT STDMETHODCALLTYPE GetCurrentSurvived(DWORD dwAppDomainId, |
1988 | ULONGLONG* pAppDomainBytesSurvived, |
1989 | ULONGLONG* pTotalBytesSurvived) |
1990 | { |
1991 | CONTRACTL |
1992 | { |
1993 | NOTHROW; |
1994 | GC_NOTRIGGER; |
1995 | ENTRY_POINT; |
1996 | } |
1997 | CONTRACTL_END; |
1998 | |
1999 | HRESULT hr = S_OK; |
2000 | BEGIN_ENTRYPOINT_NOTHROW; |
2001 | |
2002 | SystemDomain::LockHolder lh; |
2003 | |
2004 | AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD); |
2005 | if (pAppDomainBytesSurvived) |
2006 | { |
2007 | *pAppDomainBytesSurvived = pAppDomain->GetSurvivedBytes(); |
2008 | } |
2009 | if (pTotalBytesSurvived) |
2010 | { |
2011 | *pTotalBytesSurvived = SystemDomain::GetTotalSurvivedBytes(); |
2012 | } |
2013 | |
2014 | END_ENTRYPOINT_NOTHROW; |
2015 | |
2016 | return (hr); |
2017 | } |
2018 | |
2019 | virtual HRESULT STDMETHODCALLTYPE GetCurrentCpuTime(DWORD dwAppDomainId, |
2020 | ULONGLONG* pMilliseconds) |
2021 | { |
2022 | CONTRACTL |
2023 | { |
2024 | NOTHROW; |
2025 | GC_TRIGGERS; |
2026 | ENTRY_POINT; |
2027 | } |
2028 | CONTRACTL_END; |
2029 | |
2030 | HRESULT hr = S_OK; |
2031 | |
2032 | BEGIN_ENTRYPOINT_NOTHROW; |
2033 | |
2034 | { |
2035 | SystemDomain::LockHolder lh; |
2036 | |
2037 | AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD); |
2038 | if (pMilliseconds) |
2039 | { |
2040 | *pMilliseconds = pAppDomain->QueryProcessorUsage() / 10000; |
2041 | } |
2042 | } |
2043 | |
2044 | END_ENTRYPOINT_NOTHROW; |
2045 | |
2046 | return hr; |
2047 | } |
2048 | |
2049 | virtual ULONG STDMETHODCALLTYPE AddRef(void) |
2050 | { |
2051 | LIMITED_METHOD_CONTRACT; |
2052 | return 1; |
2053 | } |
2054 | |
2055 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk) |
2056 | { |
2057 | LIMITED_METHOD_CONTRACT; |
2058 | *ppUnk = NULL; |
2059 | if (riid == IID_IUnknown) |
2060 | *ppUnk = (IUnknown*)this; |
2061 | else if (riid == IID_ICLRAppDomainResourceMonitor) |
2062 | *ppUnk = (ICLRAppDomainResourceMonitor*)this; |
2063 | else |
2064 | return E_NOINTERFACE; |
2065 | return S_OK; |
2066 | } |
2067 | |
2068 | virtual ULONG STDMETHODCALLTYPE Release(void) |
2069 | { |
2070 | LIMITED_METHOD_CONTRACT; |
2071 | return 1; |
2072 | } |
2073 | }; |
2074 | static CCLRAppDomainResourceMonitor s_Arm; |
2075 | #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING |
2076 | |
2077 | |
2078 | BOOL g_CLRPolicyRequested = FALSE; |
2079 | |
2080 | class CCorCLRControl: public ICLRControl |
2081 | { |
2082 | public: |
2083 | virtual HRESULT STDMETHODCALLTYPE GetCLRManager(REFIID riid, void **ppObject) |
2084 | { |
2085 | CONTRACTL |
2086 | { |
2087 | NOTHROW; |
2088 | GC_NOTRIGGER; |
2089 | SO_TOLERANT; // no global state updates |
2090 | } |
2091 | CONTRACTL_END; |
2092 | |
2093 | // Sanity check. |
2094 | if (ppObject == NULL) |
2095 | return E_INVALIDARG; |
2096 | |
2097 | #if defined(FEATURE_WINDOWSPHONE) |
2098 | if (riid == IID_ICLRErrorReportingManager2) |
2099 | { |
2100 | *ppObject = &g_CLRErrorReportingManager; |
2101 | return S_OK; |
2102 | } |
2103 | else |
2104 | #endif //defined(FEATURE_WINDOWSPHONE) |
2105 | if (g_fEEStarted && !m_fFullAccess) |
2106 | { |
2107 | // If runtime has been started, do not allow user to obtain CLR managers. |
2108 | return HOST_E_INVALIDOPERATION; |
2109 | } |
2110 | |
2111 | // CoreCLR supports ICLRPolicyManager since it allows the host |
2112 | // to specify the policy for AccessViolation. |
2113 | else if (riid == IID_ICLRPolicyManager) { |
2114 | *ppObject = &s_PolicyManager; |
2115 | FastInterlockExchange((LONG*)&g_CLRPolicyRequested, TRUE); |
2116 | return S_OK; |
2117 | } |
2118 | |
2119 | #if defined(FEATURE_WINDOWSPHONE) |
2120 | else if ((riid == IID_ICLRGCManager) || (riid == IID_ICLRGCManager2)) |
2121 | { |
2122 | *ppObject = &s_GCManager; |
2123 | return S_OK; |
2124 | } |
2125 | #endif //FEATURE_WINDOWSPHONE |
2126 | |
2127 | #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING |
2128 | else if (riid == IID_ICLRAppDomainResourceMonitor) |
2129 | { |
2130 | EnableARM(); |
2131 | *ppObject = &s_Arm; |
2132 | return S_OK; |
2133 | } |
2134 | #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING |
2135 | else |
2136 | return (E_NOINTERFACE); |
2137 | } |
2138 | |
2139 | virtual HRESULT STDMETHODCALLTYPE SetAppDomainManagerType( |
2140 | LPCWSTR pwzAppDomainManagerAssembly, |
2141 | LPCWSTR pwzAppDomainManagerType) |
2142 | { |
2143 | |
2144 | // CoreCLR does not support this method |
2145 | return E_NOTIMPL; |
2146 | } |
2147 | |
2148 | virtual ULONG STDMETHODCALLTYPE AddRef(void) |
2149 | { |
2150 | LIMITED_METHOD_CONTRACT; |
2151 | return 1; |
2152 | } |
2153 | |
2154 | virtual ULONG STDMETHODCALLTYPE Release(void) |
2155 | { |
2156 | LIMITED_METHOD_CONTRACT; |
2157 | return 1; |
2158 | } |
2159 | |
2160 | BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, |
2161 | void **ppvObject) |
2162 | { |
2163 | LIMITED_METHOD_CONTRACT; |
2164 | if (riid != IID_ICLRControl && riid != IID_IUnknown) |
2165 | return (E_NOINTERFACE); |
2166 | |
2167 | // Ensure that the out going pointer is not null |
2168 | if (ppvObject == NULL) |
2169 | return E_POINTER; |
2170 | |
2171 | *ppvObject = this; |
2172 | return S_OK; |
2173 | } |
2174 | |
2175 | // This is to avoid having ctor. We have static objects, and it is |
2176 | // difficult to support ctor on certain platform. |
2177 | void SetAccess(BOOL fFullAccess) |
2178 | { |
2179 | LIMITED_METHOD_CONTRACT; |
2180 | m_fFullAccess = fFullAccess; |
2181 | } |
2182 | private: |
2183 | BOOL m_fFullAccess; |
2184 | }; |
2185 | |
2186 | // Before CLR starts, we give out s_CorCLRControl which has full access to all managers. |
2187 | // After CLR starts, we give out s_CorCLRControlLimited which allows limited access to managers. |
2188 | static CCorCLRControl s_CorCLRControl; |
2189 | |
2190 | |
2191 | /////////////////////////////////////////////////////////////////////////////// |
2192 | // ICLRRuntimeHost::GetCLRControl |
2193 | HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl) |
2194 | { |
2195 | LIMITED_METHOD_CONTRACT; |
2196 | |
2197 | // Ensure that we have a valid pointer |
2198 | if (pCLRControl == NULL) |
2199 | { |
2200 | return E_POINTER; |
2201 | } |
2202 | |
2203 | HRESULT hr = S_OK; |
2204 | |
2205 | STATIC_CONTRACT_ENTRY_POINT; |
2206 | BEGIN_ENTRYPOINT_NOTHROW; |
2207 | if (!g_fEEStarted && m_Version >= 2) |
2208 | { |
2209 | s_CorCLRControl.SetAccess(TRUE); |
2210 | *pCLRControl = &s_CorCLRControl; |
2211 | } |
2212 | else |
2213 | { |
2214 | // If : |
2215 | // 1) request comes for interface other than ICLRControl*, OR |
2216 | // 2) runtime has already started, OR |
2217 | // 3) version is not 2 |
2218 | // |
2219 | // we will return failure and set the out pointer to NULL |
2220 | *pCLRControl = NULL; |
2221 | if (g_fEEStarted) |
2222 | { |
2223 | // Return HOST_E_INVALIDOPERATION as per MSDN if runtime has already started |
2224 | hr = HOST_E_INVALIDOPERATION; |
2225 | } |
2226 | else |
2227 | { |
2228 | hr = E_NOTIMPL; |
2229 | } |
2230 | } |
2231 | END_ENTRYPOINT_NOTHROW; |
2232 | |
2233 | return hr; |
2234 | } |
2235 | |
2236 | // static |
2237 | EInitializeNewDomainFlags CorHost2::GetAppDomainManagerInitializeNewDomainFlags() |
2238 | { |
2239 | LIMITED_METHOD_CONTRACT; |
2240 | return eInitializeNewDomainFlags_None; |
2241 | } |
2242 | |
2243 | |
2244 | #endif // !DAC |
2245 | |
2246 | |
2247 | #ifdef DACCESS_COMPILE |
2248 | |
2249 | |
2250 | #endif //DACCESS_COMPILE |
2251 | |
2252 | #ifndef DACCESS_COMPILE |
2253 | |
2254 | |
2255 | #if defined(FEATURE_WINDOWSPHONE) |
2256 | |
2257 | HRESULT CCLRErrorReportingManager::QueryInterface(REFIID riid, void** ppUnk) |
2258 | { |
2259 | if (!ppUnk) |
2260 | return E_POINTER; |
2261 | |
2262 | CONTRACTL |
2263 | { |
2264 | NOTHROW; |
2265 | GC_NOTRIGGER; |
2266 | SO_TOLERANT; |
2267 | } |
2268 | CONTRACTL_END; |
2269 | |
2270 | HRESULT hr = S_OK; |
2271 | |
2272 | if (ppUnk == NULL) |
2273 | { |
2274 | return E_POINTER; |
2275 | } |
2276 | |
2277 | *ppUnk = 0; |
2278 | |
2279 | // Deliberately do NOT hand out ICorConfiguration. They must explicitly call |
2280 | // GetConfiguration to obtain that interface. |
2281 | if (riid == IID_IUnknown) |
2282 | { |
2283 | *ppUnk = (IUnknown *) this; |
2284 | } |
2285 | else if (riid == IID_ICLRErrorReportingManager) |
2286 | { |
2287 | *ppUnk = (ICLRErrorReportingManager *) this; |
2288 | } |
2289 | #ifdef FEATURE_WINDOWSPHONE |
2290 | else if (riid == IID_ICLRErrorReportingManager2) |
2291 | { |
2292 | *ppUnk = (ICLRErrorReportingManager2 *) this; |
2293 | } |
2294 | #endif // FEATURE_WINDOWSPHONE |
2295 | else |
2296 | { |
2297 | hr = E_NOINTERFACE; |
2298 | } |
2299 | |
2300 | return hr; |
2301 | |
2302 | } // HRESULT CCLRErrorReportingManager::QueryInterface() |
2303 | |
2304 | ULONG CCLRErrorReportingManager::AddRef() |
2305 | { |
2306 | LIMITED_METHOD_CONTRACT; |
2307 | return 1; |
2308 | } // HRESULT CCLRErrorReportingManager::AddRef() |
2309 | |
2310 | ULONG CCLRErrorReportingManager::Release() |
2311 | { |
2312 | LIMITED_METHOD_CONTRACT; |
2313 | return 1; |
2314 | } // HRESULT CCLRErrorReportingManager::Release() |
2315 | |
2316 | // Get Watson bucket parameters for "current" exception (on calling thread). |
2317 | HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException( |
2318 | BucketParameters *pParams) |
2319 | { |
2320 | CONTRACTL |
2321 | { |
2322 | WRAPPER(THROWS); |
2323 | WRAPPER(GC_TRIGGERS); |
2324 | ENTRY_POINT; |
2325 | } |
2326 | CONTRACTL_END; |
2327 | |
2328 | HRESULT hr = S_OK; |
2329 | BEGIN_ENTRYPOINT_NOTHROW; |
2330 | |
2331 | // To avoid confusion, clear the buckets. |
2332 | memset(pParams, 0, sizeof(BucketParameters)); |
2333 | |
2334 | #ifndef FEATURE_PAL |
2335 | // Defer to Watson helper. |
2336 | hr = ::GetBucketParametersForCurrentException(pParams); |
2337 | #else |
2338 | // Watson doesn't exist on non-windows platforms |
2339 | hr = E_NOTIMPL; |
2340 | #endif // !FEATURE_PAL |
2341 | |
2342 | END_ENTRYPOINT_NOTHROW; |
2343 | |
2344 | return hr; |
2345 | |
2346 | } // HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException() |
2347 | |
2348 | // |
2349 | // The BeginCustomDump function configures the custom dump support |
2350 | // |
2351 | // Parameters - |
2352 | // dwFlavor - The flavor of the dump |
2353 | // dwNumItems - The number of items in the CustomDumpItem array. |
2354 | // Should always be zero today, since no custom items are defined |
2355 | // items - Array of CustomDumpItem structs specifying items to be added to the dump. |
2356 | // Should always be NULL today, since no custom items are defined. |
2357 | // dwReserved - reserved for future use. Must be zero today |
2358 | // |
2359 | HRESULT CCLRErrorReportingManager::BeginCustomDump( ECustomDumpFlavor dwFlavor, |
2360 | DWORD dwNumItems, |
2361 | CustomDumpItem items[], |
2362 | DWORD dwReserved) |
2363 | { |
2364 | STATIC_CONTRACT_ENTRY_POINT; |
2365 | HRESULT hr = S_OK; |
2366 | |
2367 | BEGIN_ENTRYPOINT_NOTHROW; |
2368 | |
2369 | if (dwNumItems != 0 || items != NULL || dwReserved != 0) |
2370 | { |
2371 | IfFailGo(E_INVALIDARG); |
2372 | } |
2373 | if (g_ECustomDumpFlavor != DUMP_FLAVOR_Default) |
2374 | { |
2375 | // BeginCustomDump is called without matching EndCustomDump |
2376 | IfFailGo(E_INVALIDARG); |
2377 | } |
2378 | g_ECustomDumpFlavor = dwFlavor; |
2379 | |
2380 | ErrExit: |
2381 | END_ENTRYPOINT_NOTHROW; |
2382 | |
2383 | return hr; |
2384 | } |
2385 | |
2386 | // |
2387 | // EndCustomDump clears the custom dump configuration |
2388 | // |
2389 | HRESULT CCLRErrorReportingManager::EndCustomDump() |
2390 | { |
2391 | STATIC_CONTRACT_ENTRY_POINT; |
2392 | // NOT IMPLEMENTED YET |
2393 | BEGIN_ENTRYPOINT_NOTHROW; |
2394 | g_ECustomDumpFlavor = DUMP_FLAVOR_Default; |
2395 | END_ENTRYPOINT_NOTHROW; |
2396 | |
2397 | return S_OK; |
2398 | } |
2399 | |
2400 | #ifdef FEATURE_WINDOWSPHONE |
2401 | HRESULT CopyStringWorker(_Out_ WCHAR** pTarget, WCHAR const* pSource) |
2402 | { |
2403 | LIMITED_METHOD_CONTRACT; |
2404 | |
2405 | if (pTarget == NULL || pSource == NULL) |
2406 | return E_INVALIDARG; |
2407 | |
2408 | if (*pTarget) |
2409 | delete[] (*pTarget); |
2410 | |
2411 | // allocate space for the data plus one wchar for NULL |
2412 | size_t sourceLen = wcslen(pSource); |
2413 | *pTarget = new (nothrow) WCHAR[sourceLen + 1]; |
2414 | |
2415 | if (!(*pTarget)) |
2416 | return E_OUTOFMEMORY; |
2417 | |
2418 | errno_t result = wcsncpy_s(*pTarget, sourceLen + 1, pSource, sourceLen); |
2419 | _ASSERTE(result == 0); |
2420 | |
2421 | if (result != 0) |
2422 | { |
2423 | delete[] (*pTarget); |
2424 | *pTarget = NULL; |
2425 | |
2426 | return E_FAIL; |
2427 | } |
2428 | |
2429 | return S_OK; |
2430 | } |
2431 | |
2432 | CCLRErrorReportingManager::BucketParamsCache::BucketParamsCache(DWORD maxNumParams) : m_pParams(NULL), m_cMaxParams(maxNumParams) |
2433 | { |
2434 | LIMITED_METHOD_CONTRACT; |
2435 | } |
2436 | |
2437 | CCLRErrorReportingManager::BucketParamsCache::~BucketParamsCache() |
2438 | { |
2439 | LIMITED_METHOD_CONTRACT; |
2440 | |
2441 | if (m_pParams) |
2442 | { |
2443 | for (DWORD i = 0; i < m_cMaxParams; ++i) |
2444 | if (m_pParams[i]) delete[] m_pParams[i]; |
2445 | } |
2446 | } |
2447 | |
2448 | WCHAR const* CCLRErrorReportingManager::BucketParamsCache::GetAt(BucketParameterIndex index) |
2449 | { |
2450 | LIMITED_METHOD_CONTRACT; |
2451 | |
2452 | if (index >= InvalidBucketParamIndex) |
2453 | { |
2454 | _ASSERTE(!"bad bucket parameter index" ); |
2455 | return NULL; |
2456 | } |
2457 | |
2458 | if (!m_pParams) |
2459 | return NULL; |
2460 | |
2461 | return m_pParams[index]; |
2462 | } |
2463 | |
2464 | HRESULT CCLRErrorReportingManager::BucketParamsCache::SetAt(BucketParameterIndex index, WCHAR const* val) |
2465 | { |
2466 | LIMITED_METHOD_CONTRACT; |
2467 | |
2468 | if (index < 0 || index >= InvalidBucketParamIndex) |
2469 | { |
2470 | _ASSERTE(!"bad bucket parameter index" ); |
2471 | return E_INVALIDARG; |
2472 | } |
2473 | |
2474 | if (!val) |
2475 | return E_INVALIDARG; |
2476 | |
2477 | if (!m_pParams) |
2478 | { |
2479 | m_pParams = new (nothrow) WCHAR*[m_cMaxParams]; |
2480 | if (!m_pParams) |
2481 | return E_OUTOFMEMORY; |
2482 | |
2483 | for (DWORD i = 0; i < m_cMaxParams; ++i) |
2484 | m_pParams[i] = NULL; |
2485 | } |
2486 | |
2487 | return CopyStringWorker(&m_pParams[index], val); |
2488 | } |
2489 | |
2490 | HRESULT CCLRErrorReportingManager::CopyToDataCache(_Out_ WCHAR** pTarget, WCHAR const* pSource) |
2491 | { |
2492 | LIMITED_METHOD_CONTRACT; |
2493 | |
2494 | return CopyStringWorker(pTarget, pSource); |
2495 | } |
2496 | |
2497 | HRESULT CCLRErrorReportingManager::SetApplicationData(ApplicationDataKey key, WCHAR const* pValue) |
2498 | { |
2499 | STATIC_CONTRACT_ENTRY_POINT; |
2500 | |
2501 | BEGIN_ENTRYPOINT_NOTHROW; |
2502 | |
2503 | if(g_fEEStarted) |
2504 | return HOST_E_INVALIDOPERATION; |
2505 | |
2506 | if (pValue == NULL || wcslen(pValue) > MAX_LONGPATH) |
2507 | return E_INVALIDARG; |
2508 | |
2509 | HRESULT hr = S_OK; |
2510 | |
2511 | switch (key) |
2512 | { |
2513 | case ApplicationID: |
2514 | hr = CopyToDataCache(&m_pApplicationId, pValue); |
2515 | break; |
2516 | |
2517 | case InstanceID: |
2518 | hr = CopyToDataCache(&m_pInstanceId, pValue); |
2519 | break; |
2520 | |
2521 | default: |
2522 | hr = E_INVALIDARG; |
2523 | } |
2524 | |
2525 | END_ENTRYPOINT_NOTHROW; |
2526 | |
2527 | return hr; |
2528 | } |
2529 | |
2530 | HRESULT CCLRErrorReportingManager::SetBucketParametersForUnhandledException(BucketParameters const* pBucketParams, DWORD* pCountParams) |
2531 | { |
2532 | STATIC_CONTRACT_ENTRY_POINT; |
2533 | |
2534 | BEGIN_ENTRYPOINT_NOTHROW; |
2535 | |
2536 | if(g_fEEStarted) |
2537 | return HOST_E_INVALIDOPERATION; |
2538 | |
2539 | if (pBucketParams == NULL || pCountParams == NULL || pBucketParams->fInited != TRUE) |
2540 | return E_INVALIDARG; |
2541 | |
2542 | *pCountParams = 0; |
2543 | |
2544 | if (!m_pBucketParamsCache) |
2545 | { |
2546 | m_pBucketParamsCache = new (nothrow) BucketParamsCache(InvalidBucketParamIndex); |
2547 | if (!m_pBucketParamsCache) |
2548 | return E_OUTOFMEMORY; |
2549 | } |
2550 | |
2551 | HRESULT hr = S_OK; |
2552 | bool hasOverride = false; |
2553 | |
2554 | for (DWORD i = 0; i < InvalidBucketParamIndex; ++i) |
2555 | { |
2556 | if (pBucketParams->pszParams[i][0] != W('\0')) |
2557 | { |
2558 | hasOverride = true; |
2559 | hr = m_pBucketParamsCache->SetAt(static_cast<BucketParameterIndex>(i), pBucketParams->pszParams[i]); |
2560 | if (SUCCEEDED(hr)) |
2561 | *pCountParams += 1; |
2562 | else |
2563 | break; |
2564 | } |
2565 | } |
2566 | |
2567 | if (!hasOverride) |
2568 | return E_INVALIDARG; |
2569 | |
2570 | END_ENTRYPOINT_NOTHROW; |
2571 | |
2572 | return hr; |
2573 | } |
2574 | |
2575 | WCHAR const* CCLRErrorReportingManager::GetApplicationData(ApplicationDataKey key) |
2576 | { |
2577 | LIMITED_METHOD_CONTRACT; |
2578 | |
2579 | WCHAR* pValue = NULL; |
2580 | |
2581 | switch (key) |
2582 | { |
2583 | case ApplicationID: |
2584 | pValue = m_pApplicationId; |
2585 | break; |
2586 | |
2587 | case InstanceID: |
2588 | pValue = m_pInstanceId; |
2589 | break; |
2590 | |
2591 | default: |
2592 | _ASSERTE(!"invalid key specified" ); |
2593 | } |
2594 | |
2595 | return pValue; |
2596 | } |
2597 | |
2598 | WCHAR const* CCLRErrorReportingManager::GetBucketParamOverride(BucketParameterIndex bucketParamId) |
2599 | { |
2600 | LIMITED_METHOD_CONTRACT; |
2601 | |
2602 | if (!m_pBucketParamsCache) |
2603 | return NULL; |
2604 | |
2605 | return m_pBucketParamsCache->GetAt(bucketParamId); |
2606 | } |
2607 | |
2608 | #endif // FEATURE_WINDOWSPHONE |
2609 | |
2610 | CCLRErrorReportingManager::CCLRErrorReportingManager() |
2611 | { |
2612 | LIMITED_METHOD_CONTRACT; |
2613 | #ifdef FEATURE_WINDOWSPHONE |
2614 | m_pApplicationId = NULL; |
2615 | m_pInstanceId = NULL; |
2616 | m_pBucketParamsCache = NULL; |
2617 | #endif |
2618 | } |
2619 | |
2620 | CCLRErrorReportingManager::~CCLRErrorReportingManager() |
2621 | { |
2622 | LIMITED_METHOD_CONTRACT; |
2623 | #ifdef FEATURE_WINDOWSPHONE |
2624 | if (m_pApplicationId) |
2625 | delete[] m_pApplicationId; |
2626 | |
2627 | if (m_pInstanceId) |
2628 | delete[] m_pInstanceId; |
2629 | |
2630 | if (m_pBucketParamsCache) |
2631 | delete m_pBucketParamsCache; |
2632 | #endif |
2633 | } |
2634 | |
2635 | #endif // defined(FEATURE_WINDOWSPHONE) |
2636 | |
2637 | void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX) |
2638 | { |
2639 | CONTRACTL |
2640 | { |
2641 | NOTHROW; |
2642 | GC_NOTRIGGER; |
2643 | } |
2644 | CONTRACTL_END; |
2645 | |
2646 | pMSEX->dwLength = sizeof(MEMORYSTATUSEX); |
2647 | BOOL fRet = GlobalMemoryStatusEx(pMSEX); |
2648 | _ASSERTE (fRet); |
2649 | } |
2650 | |
2651 | // This is the instance that exposes interfaces out to all the other DLLs of the CLR |
2652 | // so they can use our services for TLS, synchronization, memory allocation, etc. |
2653 | static BYTE g_CEEInstance[sizeof(CExecutionEngine)]; |
2654 | static Volatile<IExecutionEngine*> g_pCEE = NULL; |
2655 | |
2656 | PTLS_CALLBACK_FUNCTION CExecutionEngine::Callbacks[MAX_PREDEFINED_TLS_SLOT]; |
2657 | |
2658 | extern "C" IExecutionEngine * __stdcall IEE() |
2659 | { |
2660 | LIMITED_METHOD_CONTRACT; |
2661 | |
2662 | // Unfortunately,we can't probe here. The probing system requires the |
2663 | // use of TLS, and in order to initialize TLS we need to call IEE. |
2664 | |
2665 | //BEGIN_ENTRYPOINT_VOIDRET; |
2666 | |
2667 | |
2668 | // The following code does NOT contain a race condition. The following code is BY DESIGN. |
2669 | // The issue is that we can have two separate threads inside this if statement, both of which are |
2670 | // initializing the g_CEEInstance variable (and subsequently updating g_pCEE). This works fine, |
2671 | // and will not cause an inconsistent state due to the fact that CExecutionEngine has no |
2672 | // local variables. If multiple threads make it inside this if statement, it will copy the same |
2673 | // bytes over g_CEEInstance and there will not be a time when there is an inconsistent state. |
2674 | if ( !g_pCEE ) |
2675 | { |
2676 | // Create a local copy on the stack and then copy it over to the static instance. |
2677 | // This avoids race conditions caused by multiple initializations of vtable in the constructor |
2678 | CExecutionEngine local; |
2679 | memcpy(&g_CEEInstance, (void*)&local, sizeof(CExecutionEngine)); |
2680 | |
2681 | g_pCEE = (IExecutionEngine*)(CExecutionEngine*)&g_CEEInstance; |
2682 | } |
2683 | //END_ENTRYPOINT_VOIDRET; |
2684 | |
2685 | return g_pCEE; |
2686 | } |
2687 | |
2688 | |
2689 | HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface(REFIID id, void **pInterface) |
2690 | { |
2691 | LIMITED_METHOD_CONTRACT; |
2692 | STATIC_CONTRACT_SO_TOLERANT; |
2693 | |
2694 | if (!pInterface) |
2695 | return E_POINTER; |
2696 | |
2697 | *pInterface = NULL; |
2698 | |
2699 | //CANNOTTHROWCOMPLUSEXCEPTION(); |
2700 | if (id == IID_IExecutionEngine) |
2701 | *pInterface = (IExecutionEngine *)this; |
2702 | else if (id == IID_IEEMemoryManager) |
2703 | *pInterface = (IEEMemoryManager *)this; |
2704 | else if (id == IID_IUnknown) |
2705 | *pInterface = (IUnknown *)(IExecutionEngine *)this; |
2706 | else |
2707 | return E_NOINTERFACE; |
2708 | |
2709 | AddRef(); |
2710 | return S_OK; |
2711 | } // HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface() |
2712 | |
2713 | |
2714 | ULONG STDMETHODCALLTYPE CExecutionEngine::AddRef() |
2715 | { |
2716 | LIMITED_METHOD_CONTRACT; |
2717 | return 1; |
2718 | } |
2719 | |
2720 | ULONG STDMETHODCALLTYPE CExecutionEngine::Release() |
2721 | { |
2722 | LIMITED_METHOD_CONTRACT; |
2723 | return 1; |
2724 | } |
2725 | |
2726 | struct ClrTlsInfo |
2727 | { |
2728 | void* data[MAX_PREDEFINED_TLS_SLOT]; |
2729 | }; |
2730 | |
2731 | #define DataToClrTlsInfo(a) ((ClrTlsInfo*)a) |
2732 | |
2733 | void** CExecutionEngine::GetTlsData() |
2734 | { |
2735 | LIMITED_METHOD_CONTRACT; |
2736 | |
2737 | return gCurrentThreadInfo.m_EETlsData; |
2738 | } |
2739 | |
2740 | BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo) |
2741 | { |
2742 | LIMITED_METHOD_CONTRACT; |
2743 | |
2744 | gCurrentThreadInfo.m_EETlsData = ppTlsInfo; |
2745 | return TRUE; |
2746 | } |
2747 | |
2748 | //--------------------------------------------------------------------------------------- |
2749 | // |
2750 | // Returns the current logical thread's data block (ClrTlsInfo::data). |
2751 | // |
2752 | // Arguments: |
2753 | // slot - Index of the slot that is about to be requested |
2754 | // force - If the data block does not exist yet, create it as a side-effect |
2755 | // |
2756 | // Return Value: |
2757 | // NULL, if the data block did not exist yet for the current thread and force was FALSE. |
2758 | // A pointer to the data block, otherwise. |
2759 | // |
2760 | // Notes: |
2761 | // If the underlying OS does not support fiber mode, the data block is stored in TLS. |
2762 | // If the underlying OS does support fiber mode, it is primarily stored in FLS, |
2763 | // and cached in TLS so that we can use our generated optimized TLS accessors. |
2764 | // |
2765 | // TLS support for the other DLLs of the CLR operates quite differently in hosted |
2766 | // and unhosted scenarios. |
2767 | |
2768 | void **CExecutionEngine::CheckThreadState(DWORD slot, BOOL force) |
2769 | { |
2770 | STATIC_CONTRACT_GC_NOTRIGGER; |
2771 | STATIC_CONTRACT_THROWS; |
2772 | STATIC_CONTRACT_MODE_ANY; |
2773 | STATIC_CONTRACT_CANNOT_TAKE_LOCK; |
2774 | STATIC_CONTRACT_SO_TOLERANT; |
2775 | |
2776 | //<TODO> @TODO: Decide on an exception strategy for all the DLLs of the CLR, and then |
2777 | // enable all the exceptions out of this method.</TODO> |
2778 | |
2779 | // Treat as a runtime assertion, since the invariant spans many DLLs. |
2780 | _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT); |
2781 | // if (slot >= MAX_PREDEFINED_TLS_SLOT) |
2782 | // COMPlusThrow(kArgumentOutOfRangeException); |
2783 | |
2784 | void** pTlsData = CExecutionEngine::GetTlsData(); |
2785 | BOOL fInTls = (pTlsData != NULL); |
2786 | |
2787 | ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData); |
2788 | if (pTlsInfo == 0 && force) |
2789 | { |
2790 | #undef HeapAlloc |
2791 | #undef GetProcessHeap |
2792 | // !!! Contract uses our TLS support. Contract may be used before our host support is set up. |
2793 | // !!! To better support contract, we call into OS for memory allocation. |
2794 | pTlsInfo = (ClrTlsInfo*) ::HeapAlloc(GetProcessHeap(),0,sizeof(ClrTlsInfo)); |
2795 | #define GetProcessHeap() Dont_Use_GetProcessHeap() |
2796 | #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes) |
2797 | if (pTlsInfo == NULL) |
2798 | { |
2799 | goto LError; |
2800 | } |
2801 | memset (pTlsInfo, 0, sizeof(ClrTlsInfo)); |
2802 | // We save the last intolerant marker on stack in this slot. |
2803 | // -1 is the larget unsigned number, and therefore our marker is always smaller than it. |
2804 | pTlsInfo->data[TlsIdx_SOIntolerantTransitionHandler] = (void*)(-1); |
2805 | } |
2806 | |
2807 | if (!fInTls && pTlsInfo) |
2808 | { |
2809 | if (!CExecutionEngine::SetTlsData(pTlsInfo->data)) |
2810 | { |
2811 | goto LError; |
2812 | } |
2813 | } |
2814 | |
2815 | return pTlsInfo?pTlsInfo->data:NULL; |
2816 | |
2817 | LError: |
2818 | if (pTlsInfo) |
2819 | { |
2820 | #undef HeapFree |
2821 | #undef GetProcessHeap |
2822 | ::HeapFree(GetProcessHeap(), 0, pTlsInfo); |
2823 | #define GetProcessHeap() Dont_Use_GetProcessHeap() |
2824 | #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem) |
2825 | } |
2826 | // If this is for the stack probe, and we failed to allocate memory for it, we won't |
2827 | // put in a guard page. |
2828 | if (slot == TlsIdx_ClrDebugState || slot == TlsIdx_StackProbe) |
2829 | return NULL; |
2830 | |
2831 | ThrowOutOfMemory(); |
2832 | } |
2833 | |
2834 | |
2835 | void **CExecutionEngine::CheckThreadStateNoCreate(DWORD slot |
2836 | #ifdef _DEBUG |
2837 | , BOOL fForDestruction |
2838 | #endif // _DEBUG |
2839 | ) |
2840 | { |
2841 | STATIC_CONTRACT_GC_NOTRIGGER; |
2842 | STATIC_CONTRACT_NOTHROW; |
2843 | STATIC_CONTRACT_MODE_ANY; |
2844 | STATIC_CONTRACT_SO_TOLERANT; |
2845 | |
2846 | // !!! This function is called during Thread::SwitchIn and SwitchOut |
2847 | // !!! It is extremely important that while executing this function, we will not |
2848 | // !!! cause fiber switch. This means we can not allocate memory, lock, etc... |
2849 | |
2850 | |
2851 | // Treat as a runtime assertion, since the invariant spans many DLLs. |
2852 | _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT); |
2853 | |
2854 | void **pTlsData = CExecutionEngine::GetTlsData(); |
2855 | |
2856 | ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData); |
2857 | |
2858 | return pTlsInfo?pTlsInfo->data:NULL; |
2859 | } |
2860 | |
2861 | // Note: Sampling profilers also use this function to initialize TLS for a unmanaged |
2862 | // sampling thread so that initialization can be done in advance to avoid deadlocks. |
2863 | // See ProfToEEInterfaceImpl::InitializeCurrentThread for more details. |
2864 | void CExecutionEngine::SetupTLSForThread(Thread *pThread) |
2865 | { |
2866 | STATIC_CONTRACT_THROWS; |
2867 | STATIC_CONTRACT_GC_NOTRIGGER; |
2868 | STATIC_CONTRACT_SO_TOLERANT; |
2869 | STATIC_CONTRACT_MODE_ANY; |
2870 | |
2871 | #ifdef STRESS_LOG |
2872 | if (StressLog::StressLogOn(~0u, 0)) |
2873 | { |
2874 | StressLog::CreateThreadStressLog(); |
2875 | } |
2876 | #endif |
2877 | void **pTlsData; |
2878 | pTlsData = CheckThreadState(0); |
2879 | |
2880 | PREFIX_ASSUME(pTlsData != NULL); |
2881 | |
2882 | #ifdef ENABLE_CONTRACTS |
2883 | // Profilers need the side effect of GetClrDebugState() to perform initialization |
2884 | // in advance to avoid deadlocks. Refer to ProfToEEInterfaceImpl::InitializeCurrentThread |
2885 | ClrDebugState *pDebugState = ::GetClrDebugState(); |
2886 | |
2887 | if (pThread) |
2888 | pThread->m_pClrDebugState = pDebugState; |
2889 | #endif |
2890 | } |
2891 | |
2892 | static void ThreadDetachingHelper(PTLS_CALLBACK_FUNCTION callback, void* pData) |
2893 | { |
2894 | // Do not use contract. We are freeing TLS blocks. |
2895 | STATIC_CONTRACT_NOTHROW; |
2896 | STATIC_CONTRACT_GC_NOTRIGGER; |
2897 | STATIC_CONTRACT_MODE_ANY; |
2898 | |
2899 | callback(pData); |
2900 | } |
2901 | |
2902 | // Called here from a thread detach or from destruction of a Thread object. In |
2903 | // the detach case, we get our info from TLS. In the destruct case, it comes from |
2904 | // the object we are destructing. |
2905 | void CExecutionEngine::ThreadDetaching(void ** pTlsData) |
2906 | { |
2907 | // Can not cause memory allocation during thread detach, so no real contracts. |
2908 | STATIC_CONTRACT_NOTHROW; |
2909 | STATIC_CONTRACT_GC_NOTRIGGER; |
2910 | STATIC_CONTRACT_MODE_ANY; |
2911 | |
2912 | // This function may be called twice: |
2913 | // 1. When a physical thread dies, our DLL_THREAD_DETACH calls this function with pTlsData = NULL |
2914 | // 2. When a fiber is destroyed, or OS calls FlsCallback after DLL_THREAD_DETACH process. |
2915 | // We will null the FLS and TLS entry if it matches the deleted one. |
2916 | |
2917 | if (pTlsData) |
2918 | { |
2919 | DeleteTLS (pTlsData); |
2920 | } |
2921 | } |
2922 | |
2923 | void CExecutionEngine::DeleteTLS(void ** pTlsData) |
2924 | { |
2925 | // Can not cause memory allocation during thread detach, so no real contracts. |
2926 | STATIC_CONTRACT_NOTHROW; |
2927 | STATIC_CONTRACT_GC_NOTRIGGER; |
2928 | STATIC_CONTRACT_MODE_ANY; |
2929 | |
2930 | if (CExecutionEngine::GetTlsData() == NULL) |
2931 | { |
2932 | // We have not allocated TlsData yet. |
2933 | return; |
2934 | } |
2935 | |
2936 | PREFIX_ASSUME(pTlsData != NULL); |
2937 | |
2938 | ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData); |
2939 | BOOL fNeed; |
2940 | do |
2941 | { |
2942 | fNeed = FALSE; |
2943 | for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++) |
2944 | { |
2945 | if (i == TlsIdx_ClrDebugState || |
2946 | i == TlsIdx_StressLog) |
2947 | { |
2948 | // StressLog and DebugState may be needed during callback. |
2949 | continue; |
2950 | } |
2951 | // If we have some data and a callback, issue it. |
2952 | if (Callbacks[i] != 0 && pTlsInfo->data[i] != 0) |
2953 | { |
2954 | void* pData = pTlsInfo->data[i]; |
2955 | pTlsInfo->data[i] = 0; |
2956 | ThreadDetachingHelper(Callbacks[i], pData); |
2957 | fNeed = TRUE; |
2958 | } |
2959 | } |
2960 | } while (fNeed); |
2961 | |
2962 | if (pTlsInfo->data[TlsIdx_StressLog] != 0) |
2963 | { |
2964 | #ifdef STRESS_LOG |
2965 | StressLog::ThreadDetach((ThreadStressLog *)pTlsInfo->data[TlsIdx_StressLog]); |
2966 | #else |
2967 | _ASSERTE (!"should not have StressLog" ); |
2968 | #endif |
2969 | } |
2970 | |
2971 | if (Callbacks[TlsIdx_ClrDebugState] != 0 && pTlsInfo->data[TlsIdx_ClrDebugState] != 0) |
2972 | { |
2973 | void* pData = pTlsInfo->data[TlsIdx_ClrDebugState]; |
2974 | pTlsInfo->data[TlsIdx_ClrDebugState] = 0; |
2975 | ThreadDetachingHelper(Callbacks[TlsIdx_ClrDebugState], pData); |
2976 | } |
2977 | |
2978 | // NULL TLS and FLS entry so that we don't double free. |
2979 | // We may get two callback here on thread death |
2980 | // 1. From EEDllMain |
2981 | // 2. From OS callback on FLS destruction |
2982 | if (CExecutionEngine::GetTlsData() == pTlsData) |
2983 | { |
2984 | CExecutionEngine::SetTlsData(0); |
2985 | } |
2986 | |
2987 | #undef HeapFree |
2988 | #undef GetProcessHeap |
2989 | ::HeapFree (GetProcessHeap(),0,pTlsInfo); |
2990 | #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem) |
2991 | #define GetProcessHeap() Dont_Use_GetProcessHeap() |
2992 | |
2993 | } |
2994 | |
2995 | #ifdef ENABLE_CONTRACTS_IMPL |
2996 | // Fls callback to deallocate ClrDebugState when our FLS block goes away. |
2997 | void FreeClrDebugState(LPVOID pTlsData); |
2998 | #endif |
2999 | |
3000 | VOID STDMETHODCALLTYPE CExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback) |
3001 | { |
3002 | WRAPPER_NO_CONTRACT; |
3003 | STATIC_CONTRACT_SO_TOLERANT; |
3004 | |
3005 | CheckThreadState(slot); |
3006 | |
3007 | // They can toggle between a callback and no callback. But anything else looks like |
3008 | // confusion on their part. |
3009 | // |
3010 | // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But |
3011 | // all the callbacks are equally good.) |
3012 | _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0); |
3013 | if (slot == TlsIdx_ClrDebugState) |
3014 | { |
3015 | #ifdef ENABLE_CONTRACTS_IMPL |
3016 | // ClrDebugState is shared among many dlls. Some dll, like perfcounter.dll, may be unloaded. |
3017 | // We force the callback function to be in mscorwks.dll. |
3018 | Callbacks[slot] = FreeClrDebugState; |
3019 | #else |
3020 | _ASSERTE (!"should not get here" ); |
3021 | #endif |
3022 | } |
3023 | else |
3024 | Callbacks[slot] = callback; |
3025 | } |
3026 | |
3027 | LPVOID* STDMETHODCALLTYPE CExecutionEngine::TLS_GetDataBlock() |
3028 | { |
3029 | STATIC_CONTRACT_GC_NOTRIGGER; |
3030 | STATIC_CONTRACT_THROWS; |
3031 | STATIC_CONTRACT_MODE_ANY; |
3032 | STATIC_CONTRACT_CANNOT_TAKE_LOCK; |
3033 | STATIC_CONTRACT_SO_TOLERANT; |
3034 | |
3035 | return CExecutionEngine::GetTlsData(); |
3036 | } |
3037 | |
3038 | LPVOID STDMETHODCALLTYPE CExecutionEngine::TLS_GetValue(DWORD slot) |
3039 | { |
3040 | WRAPPER_NO_CONTRACT; |
3041 | STATIC_CONTRACT_SO_TOLERANT; |
3042 | return EETlsGetValue(slot); |
3043 | } |
3044 | |
3045 | BOOL STDMETHODCALLTYPE CExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue) |
3046 | { |
3047 | WRAPPER_NO_CONTRACT; |
3048 | STATIC_CONTRACT_SO_TOLERANT; |
3049 | return EETlsCheckValue(slot, pValue); |
3050 | } |
3051 | |
3052 | VOID STDMETHODCALLTYPE CExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData) |
3053 | { |
3054 | WRAPPER_NO_CONTRACT; |
3055 | STATIC_CONTRACT_SO_TOLERANT; |
3056 | EETlsSetValue(slot,pData); |
3057 | } |
3058 | |
3059 | |
3060 | VOID STDMETHODCALLTYPE CExecutionEngine::TLS_ThreadDetaching() |
3061 | { |
3062 | WRAPPER_NO_CONTRACT; |
3063 | STATIC_CONTRACT_SO_TOLERANT; |
3064 | CExecutionEngine::ThreadDetaching(NULL); |
3065 | } |
3066 | |
3067 | |
3068 | CRITSEC_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags) |
3069 | { |
3070 | CONTRACTL |
3071 | { |
3072 | NOTHROW; |
3073 | GC_NOTRIGGER; |
3074 | MODE_ANY; |
3075 | ENTRY_POINT; |
3076 | } |
3077 | CONTRACTL_END; |
3078 | |
3079 | CRITSEC_COOKIE cookie = NULL; |
3080 | BEGIN_ENTRYPOINT_VOIDRET; |
3081 | cookie = ::EECreateCriticalSection(*(CrstType*)&level, flags); |
3082 | END_ENTRYPOINT_VOIDRET; |
3083 | return cookie; |
3084 | } |
3085 | |
3086 | void STDMETHODCALLTYPE CExecutionEngine::DestroyLock(CRITSEC_COOKIE cookie) |
3087 | { |
3088 | WRAPPER_NO_CONTRACT; |
3089 | STATIC_CONTRACT_SO_TOLERANT; |
3090 | ::EEDeleteCriticalSection(cookie); |
3091 | } |
3092 | |
3093 | void STDMETHODCALLTYPE CExecutionEngine::AcquireLock(CRITSEC_COOKIE cookie) |
3094 | { |
3095 | WRAPPER_NO_CONTRACT; |
3096 | STATIC_CONTRACT_SO_TOLERANT; |
3097 | BEGIN_SO_INTOLERANT_CODE(GetThread()); |
3098 | ::EEEnterCriticalSection(cookie); |
3099 | END_SO_INTOLERANT_CODE; |
3100 | } |
3101 | |
3102 | void STDMETHODCALLTYPE CExecutionEngine::ReleaseLock(CRITSEC_COOKIE cookie) |
3103 | { |
3104 | WRAPPER_NO_CONTRACT; |
3105 | STATIC_CONTRACT_SO_TOLERANT; |
3106 | BEGIN_SO_INTOLERANT_CODE(GetThread()); |
3107 | ::EELeaveCriticalSection(cookie); |
3108 | END_SO_INTOLERANT_CODE; |
3109 | } |
3110 | |
3111 | // Locking routines supplied by the EE to the other DLLs of the CLR. In a _DEBUG |
3112 | // build of the EE, we poison the Crst as a poor man's attempt to do some argument |
3113 | // validation. |
3114 | #define POISON_BITS 3 |
3115 | |
3116 | static inline EVENT_COOKIE CLREventToCookie(CLREvent * pEvent) |
3117 | { |
3118 | LIMITED_METHOD_CONTRACT; |
3119 | _ASSERTE((((uintptr_t) pEvent) & POISON_BITS) == 0); |
3120 | #ifdef _DEBUG |
3121 | pEvent = (CLREvent *) (((uintptr_t) pEvent) | POISON_BITS); |
3122 | #endif |
3123 | return (EVENT_COOKIE) pEvent; |
3124 | } |
3125 | |
3126 | static inline CLREvent *CookieToCLREvent(EVENT_COOKIE cookie) |
3127 | { |
3128 | LIMITED_METHOD_CONTRACT; |
3129 | |
3130 | _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); |
3131 | #ifdef _DEBUG |
3132 | if (cookie) |
3133 | { |
3134 | cookie = (EVENT_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); |
3135 | } |
3136 | #endif |
3137 | return (CLREvent *) cookie; |
3138 | } |
3139 | |
3140 | |
3141 | EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateAutoEvent(BOOL bInitialState) |
3142 | { |
3143 | CONTRACTL |
3144 | { |
3145 | THROWS; |
3146 | MODE_ANY; |
3147 | GC_NOTRIGGER; |
3148 | ENTRY_POINT; |
3149 | } |
3150 | CONTRACTL_END; |
3151 | |
3152 | EVENT_COOKIE event = NULL; |
3153 | BEGIN_ENTRYPOINT_THROWS; |
3154 | NewHolder<CLREvent> pEvent(new CLREvent()); |
3155 | pEvent->CreateAutoEvent(bInitialState); |
3156 | event = CLREventToCookie(pEvent); |
3157 | pEvent.SuppressRelease(); |
3158 | END_ENTRYPOINT_THROWS; |
3159 | |
3160 | return event; |
3161 | } |
3162 | |
3163 | EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateManualEvent(BOOL bInitialState) |
3164 | { |
3165 | CONTRACTL |
3166 | { |
3167 | THROWS; |
3168 | MODE_ANY; |
3169 | GC_NOTRIGGER; |
3170 | ENTRY_POINT; |
3171 | } |
3172 | CONTRACTL_END; |
3173 | |
3174 | EVENT_COOKIE event = NULL; |
3175 | BEGIN_ENTRYPOINT_THROWS; |
3176 | |
3177 | NewHolder<CLREvent> pEvent(new CLREvent()); |
3178 | pEvent->CreateManualEvent(bInitialState); |
3179 | event = CLREventToCookie(pEvent); |
3180 | pEvent.SuppressRelease(); |
3181 | |
3182 | END_ENTRYPOINT_THROWS; |
3183 | |
3184 | return event; |
3185 | } |
3186 | |
3187 | void STDMETHODCALLTYPE CExecutionEngine::CloseEvent(EVENT_COOKIE event) |
3188 | { |
3189 | WRAPPER_NO_CONTRACT; |
3190 | STATIC_CONTRACT_SO_TOLERANT; |
3191 | if (event) { |
3192 | CLREvent *pEvent = CookieToCLREvent(event); |
3193 | pEvent->CloseEvent(); |
3194 | delete pEvent; |
3195 | } |
3196 | } |
3197 | |
3198 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrSetEvent(EVENT_COOKIE event) |
3199 | { |
3200 | CONTRACTL |
3201 | { |
3202 | NOTHROW; |
3203 | GC_NOTRIGGER; |
3204 | SO_TOLERANT; |
3205 | MODE_ANY; |
3206 | } |
3207 | CONTRACTL_END; |
3208 | if (event) { |
3209 | CLREvent *pEvent = CookieToCLREvent(event); |
3210 | return pEvent->Set(); |
3211 | } |
3212 | return FALSE; |
3213 | } |
3214 | |
3215 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrResetEvent(EVENT_COOKIE event) |
3216 | { |
3217 | CONTRACTL |
3218 | { |
3219 | NOTHROW; |
3220 | GC_NOTRIGGER; |
3221 | SO_TOLERANT; |
3222 | MODE_ANY; |
3223 | } |
3224 | CONTRACTL_END; |
3225 | if (event) { |
3226 | CLREvent *pEvent = CookieToCLREvent(event); |
3227 | return pEvent->Reset(); |
3228 | } |
3229 | return FALSE; |
3230 | } |
3231 | |
3232 | DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForEvent(EVENT_COOKIE event, |
3233 | DWORD dwMilliseconds, |
3234 | BOOL bAlertable) |
3235 | { |
3236 | WRAPPER_NO_CONTRACT; |
3237 | STATIC_CONTRACT_SO_TOLERANT; |
3238 | if (event) { |
3239 | CLREvent *pEvent = CookieToCLREvent(event); |
3240 | return pEvent->Wait(dwMilliseconds,bAlertable); |
3241 | } |
3242 | |
3243 | if (GetThread() && bAlertable) |
3244 | ThrowHR(E_INVALIDARG); |
3245 | return WAIT_FAILED; |
3246 | } |
3247 | |
3248 | DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForSingleObject(HANDLE handle, |
3249 | DWORD dwMilliseconds) |
3250 | { |
3251 | STATIC_CONTRACT_WRAPPER; |
3252 | STATIC_CONTRACT_SO_TOLERANT; |
3253 | return ::WaitForSingleObject(handle,dwMilliseconds); |
3254 | } |
3255 | |
3256 | static inline SEMAPHORE_COOKIE CLRSemaphoreToCookie(CLRSemaphore * pSemaphore) |
3257 | { |
3258 | LIMITED_METHOD_CONTRACT; |
3259 | STATIC_CONTRACT_SO_TOLERANT; |
3260 | |
3261 | _ASSERTE((((uintptr_t) pSemaphore) & POISON_BITS) == 0); |
3262 | #ifdef _DEBUG |
3263 | pSemaphore = (CLRSemaphore *) (((uintptr_t) pSemaphore) | POISON_BITS); |
3264 | #endif |
3265 | return (SEMAPHORE_COOKIE) pSemaphore; |
3266 | } |
3267 | |
3268 | static inline CLRSemaphore *CookieToCLRSemaphore(SEMAPHORE_COOKIE cookie) |
3269 | { |
3270 | LIMITED_METHOD_CONTRACT; |
3271 | _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); |
3272 | #ifdef _DEBUG |
3273 | if (cookie) |
3274 | { |
3275 | cookie = (SEMAPHORE_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); |
3276 | } |
3277 | #endif |
3278 | return (CLRSemaphore *) cookie; |
3279 | } |
3280 | |
3281 | |
3282 | SEMAPHORE_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateSemaphore(DWORD dwInitial, |
3283 | DWORD dwMax) |
3284 | { |
3285 | CONTRACTL |
3286 | { |
3287 | THROWS; |
3288 | MODE_ANY; |
3289 | GC_NOTRIGGER; |
3290 | SO_TOLERANT; |
3291 | } |
3292 | CONTRACTL_END; |
3293 | |
3294 | NewHolder<CLRSemaphore> pSemaphore(new CLRSemaphore()); |
3295 | pSemaphore->Create(dwInitial, dwMax); |
3296 | SEMAPHORE_COOKIE ret = CLRSemaphoreToCookie(pSemaphore);; |
3297 | pSemaphore.SuppressRelease(); |
3298 | return ret; |
3299 | } |
3300 | |
3301 | void STDMETHODCALLTYPE CExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore) |
3302 | { |
3303 | CONTRACTL |
3304 | { |
3305 | NOTHROW; |
3306 | GC_NOTRIGGER; |
3307 | SO_TOLERANT; |
3308 | MODE_ANY; |
3309 | } |
3310 | CONTRACTL_END; |
3311 | CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); |
3312 | pSemaphore->Close(); |
3313 | delete pSemaphore; |
3314 | } |
3315 | |
3316 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, |
3317 | LONG lReleaseCount, |
3318 | LONG *lpPreviousCount) |
3319 | { |
3320 | CONTRACTL |
3321 | { |
3322 | NOTHROW; |
3323 | GC_NOTRIGGER; |
3324 | SO_TOLERANT; |
3325 | MODE_ANY; |
3326 | } |
3327 | CONTRACTL_END; |
3328 | CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); |
3329 | return pSemaphore->Release(lReleaseCount,lpPreviousCount); |
3330 | } |
3331 | |
3332 | DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, |
3333 | DWORD dwMilliseconds, |
3334 | BOOL bAlertable) |
3335 | { |
3336 | WRAPPER_NO_CONTRACT; |
3337 | STATIC_CONTRACT_SO_TOLERANT; |
3338 | CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); |
3339 | return pSemaphore->Wait(dwMilliseconds,bAlertable); |
3340 | } |
3341 | |
3342 | static inline MUTEX_COOKIE CLRMutexToCookie(CLRMutex * pMutex) |
3343 | { |
3344 | LIMITED_METHOD_CONTRACT; |
3345 | _ASSERTE((((uintptr_t) pMutex) & POISON_BITS) == 0); |
3346 | #ifdef _DEBUG |
3347 | pMutex = (CLRMutex *) (((uintptr_t) pMutex) | POISON_BITS); |
3348 | #endif |
3349 | return (MUTEX_COOKIE) pMutex; |
3350 | } |
3351 | |
3352 | static inline CLRMutex *CookieToCLRMutex(MUTEX_COOKIE cookie) |
3353 | { |
3354 | LIMITED_METHOD_CONTRACT; |
3355 | _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); |
3356 | #ifdef _DEBUG |
3357 | if (cookie) |
3358 | { |
3359 | cookie = (MUTEX_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); |
3360 | } |
3361 | #endif |
3362 | return (CLRMutex *) cookie; |
3363 | } |
3364 | |
3365 | |
3366 | MUTEX_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, |
3367 | BOOL bInitialOwner, |
3368 | LPCTSTR lpName) |
3369 | { |
3370 | CONTRACTL |
3371 | { |
3372 | NOTHROW; |
3373 | MODE_ANY; |
3374 | GC_NOTRIGGER; |
3375 | SO_TOLERANT; // we catch any erros and free the allocated memory |
3376 | } |
3377 | CONTRACTL_END; |
3378 | |
3379 | |
3380 | MUTEX_COOKIE mutex = 0; |
3381 | CLRMutex *pMutex = new (nothrow) CLRMutex(); |
3382 | if (pMutex) |
3383 | { |
3384 | EX_TRY |
3385 | { |
3386 | pMutex->Create(lpMutexAttributes, bInitialOwner, lpName); |
3387 | mutex = CLRMutexToCookie(pMutex); |
3388 | } |
3389 | EX_CATCH |
3390 | { |
3391 | delete pMutex; |
3392 | } |
3393 | EX_END_CATCH(SwallowAllExceptions); |
3394 | } |
3395 | return mutex; |
3396 | } |
3397 | |
3398 | void STDMETHODCALLTYPE CExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex) |
3399 | { |
3400 | CONTRACTL |
3401 | { |
3402 | NOTHROW; |
3403 | GC_NOTRIGGER; |
3404 | SO_TOLERANT; |
3405 | MODE_ANY; |
3406 | } |
3407 | CONTRACTL_END; |
3408 | CLRMutex *pMutex = CookieToCLRMutex(mutex); |
3409 | pMutex->Close(); |
3410 | delete pMutex; |
3411 | } |
3412 | |
3413 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex) |
3414 | { |
3415 | CONTRACTL |
3416 | { |
3417 | NOTHROW; |
3418 | GC_NOTRIGGER; |
3419 | SO_TOLERANT; |
3420 | MODE_ANY; |
3421 | } |
3422 | CONTRACTL_END; |
3423 | CLRMutex *pMutex = CookieToCLRMutex(mutex); |
3424 | return pMutex->Release(); |
3425 | } |
3426 | |
3427 | DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex, |
3428 | DWORD dwMilliseconds, |
3429 | BOOL bAlertable) |
3430 | { |
3431 | CONTRACTL |
3432 | { |
3433 | NOTHROW; |
3434 | GC_NOTRIGGER; |
3435 | SO_INTOLERANT; |
3436 | MODE_ANY; |
3437 | } |
3438 | CONTRACTL_END; |
3439 | CLRMutex *pMutex = CookieToCLRMutex(mutex); |
3440 | return pMutex->Wait(dwMilliseconds,bAlertable); |
3441 | } |
3442 | |
3443 | #undef ClrSleepEx |
3444 | DWORD STDMETHODCALLTYPE CExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) |
3445 | { |
3446 | WRAPPER_NO_CONTRACT; |
3447 | STATIC_CONTRACT_SO_TOLERANT; |
3448 | |
3449 | return EESleepEx(dwMilliseconds,bAlertable); |
3450 | } |
3451 | #define ClrSleepEx EESleepEx |
3452 | |
3453 | #undef ClrAllocationDisallowed |
3454 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrAllocationDisallowed() |
3455 | { |
3456 | WRAPPER_NO_CONTRACT; |
3457 | STATIC_CONTRACT_SO_TOLERANT; |
3458 | return EEAllocationDisallowed(); |
3459 | } |
3460 | #define ClrAllocationDisallowed EEAllocationDisallowed |
3461 | |
3462 | #undef ClrVirtualAlloc |
3463 | LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress, |
3464 | SIZE_T dwSize, |
3465 | DWORD flAllocationType, |
3466 | DWORD flProtect) |
3467 | { |
3468 | WRAPPER_NO_CONTRACT; |
3469 | STATIC_CONTRACT_SO_TOLERANT; |
3470 | return EEVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); |
3471 | } |
3472 | #define ClrVirtualAlloc EEVirtualAlloc |
3473 | |
3474 | #undef ClrVirtualFree |
3475 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualFree(LPVOID lpAddress, |
3476 | SIZE_T dwSize, |
3477 | DWORD dwFreeType) |
3478 | { |
3479 | WRAPPER_NO_CONTRACT; |
3480 | STATIC_CONTRACT_SO_TOLERANT; |
3481 | return EEVirtualFree(lpAddress, dwSize, dwFreeType); |
3482 | } |
3483 | #define ClrVirtualFree EEVirtualFree |
3484 | |
3485 | #undef ClrVirtualQuery |
3486 | SIZE_T STDMETHODCALLTYPE CExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, |
3487 | PMEMORY_BASIC_INFORMATION lpBuffer, |
3488 | SIZE_T dwLength) |
3489 | { |
3490 | WRAPPER_NO_CONTRACT; |
3491 | STATIC_CONTRACT_SO_TOLERANT; |
3492 | return EEVirtualQuery(lpAddress, lpBuffer, dwLength); |
3493 | } |
3494 | #define ClrVirtualQuery EEVirtualQuery |
3495 | |
3496 | #if defined(_DEBUG) && !defined(FEATURE_PAL) |
3497 | static VolatilePtr<BYTE> s_pStartOfUEFSection = NULL; |
3498 | static VolatilePtr<BYTE> s_pEndOfUEFSectionBoundary = NULL; |
3499 | static Volatile<DWORD> s_dwProtection = 0; |
3500 | #endif // _DEBUG && !FEATURE_PAL |
3501 | |
3502 | #undef ClrVirtualProtect |
3503 | |
3504 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, |
3505 | SIZE_T dwSize, |
3506 | DWORD flNewProtect, |
3507 | PDWORD lpflOldProtect) |
3508 | { |
3509 | WRAPPER_NO_CONTRACT; |
3510 | STATIC_CONTRACT_SO_TOLERANT; |
3511 | |
3512 | // Get the UEF installation details - we will use these to validate |
3513 | // that the calls to ClrVirtualProtect are not going to affect the UEF. |
3514 | // |
3515 | // The OS UEF invocation mechanism was updated. When a UEF is setup,the OS captures |
3516 | // the following details about it: |
3517 | // 1) Protection of the pages in which the UEF lives |
3518 | // 2) The size of the region in which the UEF lives |
3519 | // 3) The region's Allocation Base |
3520 | // |
3521 | // The OS verifies details surrounding the UEF before invocation. For security reasons |
3522 | // the page protection cannot change between SetUnhandledExceptionFilter and invocation. |
3523 | // |
3524 | // Prior to this change, the UEF lived in a common section of code_Seg, along with |
3525 | // JIT_PatchedCode. Thus, their pages have the same protection, they live |
3526 | // in the same region (and thus, its size is the same). |
3527 | // |
3528 | // In EEStartupHelper, when we setup the UEF and then invoke InitJitHelpers1 and InitJitHelpers2, |
3529 | // they perform some optimizations that result in the memory page protection being changed. When |
3530 | // the UEF is to be invoked, the OS does the check on the UEF's cached details against the current |
3531 | // memory pages. This check used to fail when on 64bit retail builds when JIT_PatchedCode was |
3532 | // aligned after the UEF with a different memory page protection (post the optimizations by InitJitHelpers). |
3533 | // Thus, the UEF was never invoked. |
3534 | // |
3535 | // To circumvent this, we put the UEF in its own section in the code segment so that any modifications |
3536 | // to memory pages will not affect the UEF details that the OS cached. This is done in Excep.cpp |
3537 | // using the "#pragma code_seg" directives. |
3538 | // |
3539 | // Below, we double check that: |
3540 | // |
3541 | // 1) the address being protected does not lie in the region of of the UEF. |
3542 | // 2) the section after UEF is not having the same memory protection as UEF section. |
3543 | // |
3544 | // We assert if either of the two conditions above are true. |
3545 | |
3546 | #if defined(_DEBUG) && !defined(FEATURE_PAL) |
3547 | // We do this check in debug/checked builds only |
3548 | |
3549 | // Do we have the UEF details? |
3550 | if (s_pEndOfUEFSectionBoundary.Load() == NULL) |
3551 | { |
3552 | // Get reference to MSCORWKS image in memory... |
3553 | PEDecoder pe(g_pMSCorEE); |
3554 | |
3555 | // Find the UEF section from the image |
3556 | IMAGE_SECTION_HEADER* pUEFSection = pe.FindSection(CLR_UEF_SECTION_NAME); |
3557 | _ASSERTE(pUEFSection != NULL); |
3558 | if (pUEFSection) |
3559 | { |
3560 | // We got our section - get the start of the section |
3561 | BYTE* pStartOfUEFSection = static_cast<BYTE*>(pe.GetBase())+pUEFSection->VirtualAddress; |
3562 | s_pStartOfUEFSection = pStartOfUEFSection; |
3563 | |
3564 | // Now we need the protection attributes for the memory region in which the |
3565 | // UEF section is... |
3566 | MEMORY_BASIC_INFORMATION uefInfo; |
3567 | if (ClrVirtualQuery(pStartOfUEFSection, &uefInfo, sizeof(uefInfo)) != 0) |
3568 | { |
3569 | // Calculate how many pages does the UEF section take to get to the start of the |
3570 | // next section. We dont calculate this as |
3571 | // |
3572 | // pStartOfUEFSection + uefInfo.RegionSize |
3573 | // |
3574 | // because the section following UEF will also be included in the region size |
3575 | // if it has the same protection as the UEF section. |
3576 | DWORD dwUEFSectionPageCount = ((pUEFSection->Misc.VirtualSize + GetOsPageSize() - 1)/GetOsPageSize()); |
3577 | |
3578 | BYTE* pAddressOfFollowingSection = pStartOfUEFSection + (GetOsPageSize() * dwUEFSectionPageCount); |
3579 | |
3580 | // Ensure that the section following us is having different memory protection |
3581 | MEMORY_BASIC_INFORMATION nextSectionInfo; |
3582 | _ASSERTE(ClrVirtualQuery(pAddressOfFollowingSection, &nextSectionInfo, sizeof(nextSectionInfo)) != 0); |
3583 | _ASSERTE(nextSectionInfo.Protect != uefInfo.Protect); |
3584 | |
3585 | // save the memory protection details |
3586 | s_dwProtection = uefInfo.Protect; |
3587 | |
3588 | // Get the end of the UEF section |
3589 | BYTE* pEndOfUEFSectionBoundary = pAddressOfFollowingSection - 1; |
3590 | |
3591 | // Set the end of UEF section boundary |
3592 | FastInterlockExchangePointer(s_pEndOfUEFSectionBoundary.GetPointer(), pEndOfUEFSectionBoundary); |
3593 | } |
3594 | else |
3595 | { |
3596 | _ASSERTE(!"Unable to get UEF Details!" ); |
3597 | } |
3598 | } |
3599 | } |
3600 | |
3601 | if (s_pEndOfUEFSectionBoundary.Load() != NULL) |
3602 | { |
3603 | // Is the protection being changed? |
3604 | if (flNewProtect != s_dwProtection) |
3605 | { |
3606 | // Is the target address NOT affecting the UEF ? Possible cases: |
3607 | // 1) Starts and ends before the UEF start |
3608 | // 2) Starts after the UEF start |
3609 | |
3610 | void* pEndOfRangeAddr = static_cast<BYTE*>(lpAddress)+dwSize-1; |
3611 | |
3612 | _ASSERTE_MSG(((pEndOfRangeAddr < s_pStartOfUEFSection.Load()) || (lpAddress > s_pEndOfUEFSectionBoundary.Load())), |
3613 | "Do not virtual protect the section in which UEF lives!" ); |
3614 | } |
3615 | } |
3616 | #endif // _DEBUG && !FEATURE_PAL |
3617 | |
3618 | return EEVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); |
3619 | } |
3620 | #define ClrVirtualProtect EEVirtualProtect |
3621 | |
3622 | #undef ClrGetProcessHeap |
3623 | HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessHeap() |
3624 | { |
3625 | WRAPPER_NO_CONTRACT; |
3626 | STATIC_CONTRACT_SO_TOLERANT; |
3627 | return EEGetProcessHeap(); |
3628 | } |
3629 | #define ClrGetProcessHeap EEGetProcessHeap |
3630 | |
3631 | #undef ClrGetProcessExecutableHeap |
3632 | HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessExecutableHeap() |
3633 | { |
3634 | WRAPPER_NO_CONTRACT; |
3635 | STATIC_CONTRACT_SO_TOLERANT; |
3636 | return EEGetProcessExecutableHeap(); |
3637 | } |
3638 | #define ClrGetProcessExecutableHeap EEGetProcessExecutableHeap |
3639 | |
3640 | |
3641 | #undef ClrHeapCreate |
3642 | HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrHeapCreate(DWORD flOptions, |
3643 | SIZE_T dwInitialSize, |
3644 | SIZE_T dwMaximumSize) |
3645 | { |
3646 | WRAPPER_NO_CONTRACT; |
3647 | STATIC_CONTRACT_SO_TOLERANT; |
3648 | return EEHeapCreate(flOptions, dwInitialSize, dwMaximumSize); |
3649 | } |
3650 | #define ClrHeapCreate EEHeapCreate |
3651 | |
3652 | #undef ClrHeapDestroy |
3653 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapDestroy(HANDLE hHeap) |
3654 | { |
3655 | WRAPPER_NO_CONTRACT; |
3656 | STATIC_CONTRACT_SO_TOLERANT; |
3657 | return EEHeapDestroy(hHeap); |
3658 | } |
3659 | #define ClrHeapDestroy EEHeapDestroy |
3660 | |
3661 | #undef ClrHeapAlloc |
3662 | LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrHeapAlloc(HANDLE hHeap, |
3663 | DWORD dwFlags, |
3664 | SIZE_T dwBytes) |
3665 | { |
3666 | WRAPPER_NO_CONTRACT; |
3667 | STATIC_CONTRACT_SO_TOLERANT; |
3668 | |
3669 | // We need to guarentee a very small stack consumption in allocating. And we can't allow |
3670 | // an SO to happen while calling into the host. This will force a hard SO which is OK because |
3671 | // we shouldn't ever get this close inside the EE in SO-intolerant code, so this should |
3672 | // only fail if we call directly in from outside the EE, such as the JIT. |
3673 | MINIMAL_STACK_PROBE_CHECK_THREAD(GetThread()); |
3674 | |
3675 | return EEHeapAlloc(hHeap, dwFlags, dwBytes); |
3676 | } |
3677 | #define ClrHeapAlloc EEHeapAlloc |
3678 | |
3679 | #undef ClrHeapFree |
3680 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapFree(HANDLE hHeap, |
3681 | DWORD dwFlags, |
3682 | LPVOID lpMem) |
3683 | { |
3684 | WRAPPER_NO_CONTRACT; |
3685 | STATIC_CONTRACT_SO_TOLERANT; |
3686 | return EEHeapFree(hHeap, dwFlags, lpMem); |
3687 | } |
3688 | #define ClrHeapFree EEHeapFree |
3689 | |
3690 | #undef ClrHeapValidate |
3691 | BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapValidate(HANDLE hHeap, |
3692 | DWORD dwFlags, |
3693 | LPCVOID lpMem) |
3694 | { |
3695 | WRAPPER_NO_CONTRACT; |
3696 | STATIC_CONTRACT_SO_TOLERANT; |
3697 | return EEHeapValidate(hHeap, dwFlags, lpMem); |
3698 | } |
3699 | #define ClrHeapValidate EEHeapValidate |
3700 | |
3701 | //------------------------------------------------------------------------------ |
3702 | // Helper function to get an exception object from outside the exception. In |
3703 | // the CLR, it may be from the Thread object. Non-CLR users have no thread object, |
3704 | // and it will do nothing. |
3705 | |
3706 | void CExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException) |
3707 | { |
3708 | WRAPPER_NO_CONTRACT; |
3709 | STATIC_CONTRACT_SO_TOLERANT; |
3710 | |
3711 | // Cast to our real type. |
3712 | Exception **ppException = reinterpret_cast<Exception**>(ppvException); |
3713 | |
3714 | // Try to get a better message. |
3715 | GetLastThrownObjectExceptionFromThread_Internal(ppException); |
3716 | |
3717 | } // HRESULT CExecutionEngine::GetLastThrownObjectExceptionFromThread() |
3718 | |
3719 | |
3720 | LocaleID RuntimeGetFileSystemLocale() |
3721 | { |
3722 | return PEImage::GetFileSystemLocale(); |
3723 | }; |
3724 | |
3725 | HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName, IActivationFactory ** factory) |
3726 | { |
3727 | #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION |
3728 | // WinRT activation currently supported in default domain only |
3729 | if (appDomainID != DefaultADID) |
3730 | return HOST_E_INVALIDOPERATION; |
3731 | |
3732 | HRESULT hr = S_OK; |
3733 | |
3734 | Thread *pThread = GetThread(); |
3735 | if (pThread == NULL) |
3736 | { |
3737 | pThread = SetupThreadNoThrow(&hr); |
3738 | if (pThread == NULL) |
3739 | { |
3740 | return hr; |
3741 | } |
3742 | } |
3743 | |
3744 | if(SystemDomain::GetCurrentDomain()->GetId().m_dwId != DefaultADID) |
3745 | { |
3746 | return HOST_E_INVALIDOPERATION; |
3747 | } |
3748 | |
3749 | return DllGetActivationFactoryImpl(NULL, wszTypeName, NULL, factory); |
3750 | #else |
3751 | return E_NOTIMPL; |
3752 | #endif |
3753 | } |
3754 | |
3755 | |
3756 | #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION |
3757 | |
3758 | HRESULT STDMETHODCALLTYPE DllGetActivationFactoryImpl(LPCWSTR wszAssemblyName, |
3759 | LPCWSTR wszTypeName, |
3760 | LPCWSTR wszCodeBase, |
3761 | IActivationFactory ** factory) |
3762 | { |
3763 | CONTRACTL |
3764 | { |
3765 | DISABLED(NOTHROW); |
3766 | GC_TRIGGERS; |
3767 | MODE_ANY; |
3768 | ENTRY_POINT; |
3769 | } |
3770 | CONTRACTL_END; |
3771 | |
3772 | HRESULT hr = S_OK; |
3773 | |
3774 | BEGIN_ENTRYPOINT_NOTHROW; |
3775 | |
3776 | AppDomain* pDomain = SystemDomain::System()->DefaultDomain(); |
3777 | _ASSERTE(pDomain); |
3778 | |
3779 | BEGIN_EXTERNAL_ENTRYPOINT(&hr); |
3780 | { |
3781 | GCX_COOP(); |
3782 | |
3783 | bool bIsPrimitive; |
3784 | TypeHandle typeHandle = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(wszTypeName, &bIsPrimitive); |
3785 | if (!bIsPrimitive && !typeHandle.IsNull() && !typeHandle.IsTypeDesc() && typeHandle.AsMethodTable()->IsExportedToWinRT()) |
3786 | { |
3787 | struct _gc { |
3788 | OBJECTREF type; |
3789 | } gc; |
3790 | memset(&gc, 0, sizeof(gc)); |
3791 | |
3792 | |
3793 | IActivationFactory* activationFactory; |
3794 | GCPROTECT_BEGIN(gc); |
3795 | |
3796 | gc.type = typeHandle.GetManagedClassObject(); |
3797 | |
3798 | MethodDescCallSite mdcs(METHOD__WINDOWSRUNTIMEMARSHAL__GET_ACTIVATION_FACTORY_FOR_TYPE); |
3799 | ARG_SLOT args[1] = { |
3800 | ObjToArgSlot(gc.type) |
3801 | }; |
3802 | activationFactory = (IActivationFactory*)mdcs.Call_RetLPVOID(args); |
3803 | |
3804 | *factory = activationFactory; |
3805 | |
3806 | GCPROTECT_END(); |
3807 | } |
3808 | else |
3809 | { |
3810 | hr = COR_E_TYPELOAD; |
3811 | } |
3812 | } |
3813 | END_EXTERNAL_ENTRYPOINT; |
3814 | END_ENTRYPOINT_NOTHROW; |
3815 | |
3816 | return hr; |
3817 | } |
3818 | |
3819 | #endif // !FEATURE_COMINTEROP_MANAGED_ACTIVATION |
3820 | |
3821 | |
3822 | |
3823 | |
3824 | #endif // !DACCESS_COMPILE |
3825 | |