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// File: CEEMAIN.CPP
6// ===========================================================================
7//
8
9//
10//
11// The CLR code base uses a hyperlink feature of the HyperAddin plugin for Visual Studio. If you don't see
12// 'HyperAddin' in your Visual Studio menu bar you don't have this support. To get it type
13//
14// \\clrmain\tools\installCLRAddins
15//
16// After installing HyperAddin, your first run of VS should be as an administrator so HyperAddin can update
17// some registry information.
18//
19// At this point the code: prefixes become hyperlinks in Visual Studio and life is good. See
20// http://mswikis/clr/dev/Pages/CLR%20Team%20Commenting.aspx for more information
21//
22// There is a bug associated with Visual Studio where it does not recognise the hyperlink if there is a ::
23// preceeding it on the same line. Since C++ uses :: as a namespace separator, this can often mean that the
24// second hyperlink on a line does not work. To work around this it is better to use '.' instead of :: as
25// the namespace separators in code: hyperlinks.
26//
27// #StartHere
28// #TableOfContents The .NET Runtime Table of contents
29//
30// This comment is mean to be a nexus that allows you to jump quickly to various interesting parts of the
31// runtime.
32//
33// You can refer to product studio bugs using urls like the following
34// * http://bugcheck/bugs/DevDivBugs/2320.asp
35// * http://bugcheck/bugs/VSWhidbey/601210.asp
36//
37// Dev10 Bugs can be added with URLs like the following (for Dev10 bug 671409)
38// * http://tkbgitvstfat01:8090/wi.aspx?id=671409
39//
40//*************************************************************************************************
41//
42// * Introduction to the runtime file:../../Documentation/botr/botr-faq.md
43//
44// #MajorDataStructures. The major data structures associated with the runtime are
45// * code:Thread (see file:threads.h#ThreadClass) - the additional thread state the runtime needs.
46// * code:AppDomain - The managed version of a process
47// * code:Assembly - The unit of deployment and versioning (may be several DLLs but often is only one).
48// * code:Module - represents a Module (DLL or EXE).
49// * code:MethodTable - represents the 'hot' part of a type (needed during normal execution)
50// * code:EEClass - represents the 'cold' part of a type (used during compilation, interop, ...)
51// * code:MethodDesc - represents a Method
52// * code:FieldDesc - represents a Field.
53// * code:Object - represents a object on the GC heap allocated with code:Alloc
54//
55// * ECMA specifications
56// * Partition I Concepts
57// http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20I%20Architecture.doc
58// * Partition II Meta Data
59// http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20II%20Metadata.doc
60// * Partition III IL
61// http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20III%20CIL.doc
62//
63// * Serge Liden (worked on the CLR and owned ILASM / ILDASM for a long time wrote a good book on IL
64// * Expert .NET 2.0 IL Assembler http://www.amazon.com/Expert-NET-2-0-IL-Assembler/dp/1590596463
65//
66// * This is also a pretty nice overview of what the CLR is at
67// http://msdn2.microsoft.com/en-us/netframework/aa497266.aspx
68//
69// * code:EEStartup - This routine must be called before any interesting runtime services are used. It is
70// invoked as part of mscorwks's DllMain logic.
71// * code:#EEShutDown - Code called before we shut down the EE.
72//
73// * file:..\inc\corhdr.h#ManagedHeader - From a data structure point of view, this is the entry point into
74// the runtime. This is how all other data in the EXE are found.
75//
76// * code:ICorJitCompiler#EEToJitInterface - This is the interface from the the EE to the Just in time (JIT)
77// compiler. The interface to the JIT is relatively simple (compileMethod), however the EE provides a
78// rich set of callbacks so the JIT can get all the information it needs. See also
79// file:../../Documentation/botr/ryujit-overview.md for general information on the JIT.
80//
81// * code:VirtualCallStubManager - This is the main class that implements interface dispatch
82//
83// * Precode - Every method needs entry point for other code to call even if that native code does not
84// actually exist yet. To support this methods can have code:Precode that is an entry point that exists
85// and will call the JIT compiler if the code does not yet exist.
86//
87// * NGEN - NGen stands for Native code GENeration and it is the runtime way of precompiling IL and IL
88// Meta-data into native code and runtime data structures. At compilation time the most
89// fundamental data structures is the code:ZapNode which represents something that needs to go into the
90// NGEN image.
91//
92// * What is cooperative / preemtive mode ? file:threads.h#CooperativeMode and
93// file:threads.h#SuspendingTheRuntime and file:../../Documentation/botr/threading.md
94// * Garbage collection - file:gc.cpp#Overview and file:../../Documentation/botr/garbage-collection.md
95// * code:AppDomain - The managed version of a process.
96// * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/mscorlib.md
97// * Exceptions - file:../../Documentation/botr/exceptions.md. The most important routine to start
98// with is code:COMPlusFrameHandler which is the routine that we hook up to get called when an unmanaged
99// exception happens.
100// * Assembly Loading file:../../Documentation/botr/type-loader.md
101// * Profiling file:../../Documentation/botr/profiling.md and file:../../Documentation/botr/profilability.md
102// * FCALLS QCALLS (calling into the runtime from managed code)
103// file:../../Documentation/botr/mscorlib.md
104// * Event Tracing for Windows
105// * file:../inc/eventtrace.h#EventTracing -
106// * This is the main file dealing with event tracing in CLR
107// * The implementation of this class is available in file:eventtrace.cpp
108// * file:../inc/eventtrace.h#CEtwTracer - This is the main class dealing with event tracing in CLR.
109// Follow the link for more information on how this feature has been implemented
110// * http://mswikis/clr/dev/Pages/CLR%20ETW%20Events%20Wiki.aspx - Follow the link for more information on how to
111// use this instrumentation feature.
112
113// ----------------------------------------------------------------------------------------------------
114// Features in the runtime that have been given hyperlinks
115//
116// * code:Nullable#NullableFeature - the Nullable<T> type has special runtime semantics associated with
117// boxing this describes this feature.
118
119#include "common.h"
120
121#include "vars.hpp"
122#include "log.h"
123#include "ceemain.h"
124#include "clsload.hpp"
125#include "object.h"
126#include "hash.h"
127#include "ecall.h"
128#include "ceemain.h"
129#include "dllimport.h"
130#include "syncblk.h"
131#include "eeconfig.h"
132#include "stublink.h"
133#include "method.hpp"
134#include "codeman.h"
135#include "frames.h"
136#include "threads.h"
137#include "stackwalk.h"
138#include "gcheaputilities.h"
139#include "interoputil.h"
140#include "fieldmarshaler.h"
141#include "dbginterface.h"
142#include "eedbginterfaceimpl.h"
143#include "debugdebugger.h"
144#include "cordbpriv.h"
145#include "comdelegate.h"
146#include "appdomain.hpp"
147#include "perfcounters.h"
148#include "eventtrace.h"
149#include "corhost.h"
150#include "binder.h"
151#include "olevariant.h"
152#include "comcallablewrapper.h"
153#include "apithreadstress.h"
154#include "perflog.h"
155#include "../dlls/mscorrc/resource.h"
156#include "util.hpp"
157#include "shimload.h"
158#include "comthreadpool.h"
159#include "stackprobe.h"
160#include "posterror.h"
161#include "virtualcallstub.h"
162#include "strongnameinternal.h"
163#include "syncclean.hpp"
164#include "typeparse.h"
165#include "debuginfostore.h"
166#include "mdaassistants.h"
167#include "eemessagebox.h"
168#include "finalizerthread.h"
169#include "threadsuspend.h"
170#include "disassembler.h"
171#include "jithost.h"
172
173#ifndef FEATURE_PAL
174#include "dwreport.h"
175#endif // !FEATURE_PAL
176
177#include "stringarraylist.h"
178#include "stubhelpers.h"
179
180#ifdef FEATURE_STACK_SAMPLING
181#include "stacksampler.h"
182#endif
183
184#include <shlwapi.h>
185
186#include "bbsweep.h"
187
188
189#ifdef FEATURE_COMINTEROP
190#include "runtimecallablewrapper.h"
191#include "notifyexternals.h"
192#include "mngstdinterfaces.h"
193#include "rcwwalker.h"
194#endif // FEATURE_COMINTEROP
195
196#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
197#include "olecontexthelpers.h"
198#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
199
200#ifdef PROFILING_SUPPORTED
201#include "proftoeeinterfaceimpl.h"
202#include "profilinghelper.h"
203#endif // PROFILING_SUPPORTED
204
205#ifdef FEATURE_COMINTEROP
206#include "synchronizationcontextnative.h" // For SynchronizationContextNative::Cleanup
207#endif
208
209#ifdef FEATURE_INTERPRETER
210#include "interpreter.h"
211#endif // FEATURE_INTERPRETER
212
213#include "../binder/inc/coreclrbindercommon.h"
214
215
216#ifdef FEATURE_PERFMAP
217#include "perfmap.h"
218#endif
219
220#include "eventpipe.h"
221
222#ifndef FEATURE_PAL
223// Included for referencing __security_cookie
224#include "process.h"
225#endif // !FEATURE_PAL
226
227#ifdef FEATURE_GDBJIT
228#include "gdbjit.h"
229#endif // FEATURE_GDBJIT
230
231#ifndef CROSSGEN_COMPILE
232static int GetThreadUICultureId(__out LocaleIDValue* pLocale); // TODO: This shouldn't use the LCID. We should rely on name instead
233
234static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames);
235#endif // !CROSSGEN_COMPILE
236
237HRESULT EEStartup(COINITIEE fFlags);
238
239
240#ifndef CROSSGEN_COMPILE
241static void InitializeGarbageCollector();
242
243#ifdef DEBUGGING_SUPPORTED
244static void InitializeDebugger(void);
245static void TerminateDebugger(void);
246extern "C" HRESULT __cdecl CorDBGetInterface(DebugInterface** rcInterface);
247#endif // DEBUGGING_SUPPORTED
248#endif // !CROSSGEN_COMPILE
249
250
251
252
253// Remember how the last startup of EE went.
254HRESULT g_EEStartupStatus = S_OK;
255
256// Flag indicating if the EE has been started. This is set prior to initializing the default AppDomain, and so does not indicate that
257// the EE is fully able to execute arbitrary managed code. To ensure the EE is fully started, call EnsureEEStarted rather than just
258// checking this flag.
259Volatile<BOOL> g_fEEStarted = FALSE;
260
261// Flag indicating if the EE should be suspended on shutdown.
262BOOL g_fSuspendOnShutdown = FALSE;
263
264// Flag indicating if the finalizer thread should be suspended on shutdown.
265BOOL g_fSuspendFinalizerOnShutdown = FALSE;
266
267// Flag indicating if the EE was started up by COM.
268extern BOOL g_fEEComActivatedStartup;
269
270// flag indicating that EE was not started up by IJW, Hosted, COM or my managed exe.
271extern BOOL g_fEEOtherStartup;
272
273// The OS thread ID of the thread currently performing EE startup, or 0 if there is no such thread.
274DWORD g_dwStartupThreadId = 0;
275
276// Event to synchronize EE shutdown.
277static CLREvent * g_pEEShutDownEvent;
278
279static DangerousNonHostedSpinLock g_EEStartupLock;
280
281HRESULT InitializeEE(COINITIEE flags)
282{
283 WRAPPER_NO_CONTRACT;
284#ifdef FEATURE_EVENT_TRACE
285 if(!g_fEEComActivatedStartup)
286 g_fEEOtherStartup = TRUE;
287#endif // FEATURE_EVENT_TRACE
288 return EnsureEEStarted(flags);
289}
290
291// ---------------------------------------------------------------------------
292// %%Function: EnsureEEStarted()
293//
294// Description: Ensure the CLR is started.
295// ---------------------------------------------------------------------------
296HRESULT EnsureEEStarted(COINITIEE flags)
297{
298 CONTRACTL
299 {
300 NOTHROW;
301 GC_TRIGGERS;
302 MODE_PREEMPTIVE;
303 ENTRY_POINT;
304 }
305 CONTRACTL_END;
306
307 if (g_fEEShutDown)
308 return E_FAIL;
309
310 HRESULT hr = E_FAIL;
311
312 // On non x86 platforms, when we load mscorlib.dll during EEStartup, we will
313 // re-enter _CorDllMain with a DLL_PROCESS_ATTACH for mscorlib.dll. We are
314 // far enough in startup that this is allowed, however we don't want to
315 // re-start the startup code so we need to check to see if startup has
316 // been initiated or completed before we call EEStartup.
317 //
318 // We do however want to make sure other threads block until the EE is started,
319 // which we will do further down.
320 if (!g_fEEStarted)
321 {
322 BEGIN_ENTRYPOINT_NOTHROW;
323
324#if defined(FEATURE_APPX) && !defined(CROSSGEN_COMPILE)
325 STARTUP_FLAGS startupFlags = CorHost2::GetStartupFlags();
326 // On CoreCLR, the host is in charge of determining whether the process is AppX or not.
327 AppX::SetIsAppXProcess(!!(startupFlags & STARTUP_APPX_APP_MODEL));
328#endif
329
330#ifndef FEATURE_PAL
331 // The sooner we do this, the sooner we avoid probing registry entries.
332 // (Perf Optimization for VSWhidbey:113373.)
333 REGUTIL::InitOptionalConfigCache();
334#endif
335
336
337 BOOL bStarted=FALSE;
338
339 {
340 DangerousNonHostedSpinLockHolder lockHolder(&g_EEStartupLock);
341
342 // Now that we've acquired the lock, check again to make sure we aren't in
343 // the process of starting the CLR or that it hasn't already been fully started.
344 // At this point, if startup has been inited we don't have anything more to do.
345 // And if EEStartup already failed before, we don't do it again.
346 if (!g_fEEStarted && !g_fEEInit && SUCCEEDED (g_EEStartupStatus))
347 {
348 g_dwStartupThreadId = GetCurrentThreadId();
349
350 EEStartup(flags);
351 bStarted=g_fEEStarted;
352 hr = g_EEStartupStatus;
353
354 g_dwStartupThreadId = 0;
355 }
356 else
357 {
358 hr = g_EEStartupStatus;
359 if (SUCCEEDED(g_EEStartupStatus))
360 {
361 hr = S_FALSE;
362 }
363 }
364 }
365
366#ifdef FEATURE_TESTHOOKS
367 if(bStarted)
368 TESTHOOKCALL(RuntimeStarted(RTS_INITIALIZED));
369#endif
370 END_ENTRYPOINT_NOTHROW;
371 }
372 else
373 {
374 //
375 // g_fEEStarted is TRUE, but startup may not be complete since we initialize the default AppDomain
376 // *after* setting that flag. g_fEEStarted is set inside of g_EEStartupLock, and that lock is
377 // not released until the EE is really started - so we can quickly check whether the EE is definitely
378 // started by checking if that lock is currently held. If it is not, then we know the other thread
379 // (that is actually doing the startup) has finished startup. If it is currently held, then we
380 // need to wait for the other thread to release it, which we do by simply acquiring the lock ourselves.
381 //
382 // We do not want to do this blocking if we are the thread currently performing EE startup. So we check
383 // that first.
384 //
385 // Note that the call to IsHeld here is an "acquire" barrier, as is acquiring the lock. And the release of
386 // the lock by the other thread is a "release" barrier, due to the volatile semantics in the lock's
387 // implementation. This assures us that once we observe the lock having been released, we are guaranteed
388 // to observe a fully-initialized EE.
389 //
390 // A note about thread affinity here: we're using the OS thread ID of the current thread without
391 // asking the host to pin us to this thread, as we did above. We can get away with this, because we are
392 // only interested in a particular thread ID (that of the "startup" thread) and *that* particular thread
393 // is already affinitized by the code above. So if we get that particular OS thread ID, we know for sure
394 // we are really the startup thread.
395 //
396 if (g_EEStartupLock.IsHeld() && g_dwStartupThreadId != GetCurrentThreadId())
397 {
398 DangerousNonHostedSpinLockHolder lockHolder(&g_EEStartupLock);
399 }
400
401 hr = g_EEStartupStatus;
402 if (SUCCEEDED(g_EEStartupStatus))
403 {
404 hr = S_FALSE;
405 }
406 }
407
408 return hr;
409}
410
411
412#ifndef CROSSGEN_COMPILE
413
414#ifndef FEATURE_PAL
415// This is our Ctrl-C, Ctrl-Break, etc. handler.
416static BOOL WINAPI DbgCtrlCHandler(DWORD dwCtrlType)
417{
418 WRAPPER_NO_CONTRACT;
419 STATIC_CONTRACT_SO_TOLERANT;
420
421#if defined(DEBUGGING_SUPPORTED)
422 // Note that if a managed-debugger is attached, it's actually attached with the native
423 // debugging pipeline and it will get a control-c notifications via native debug events.
424 // However, if we let the native debugging pipeline handle the event and send the notification
425 // to the debugger, then we break pre-V4 behaviour because we intercept handlers registered
426 // in-process. See Dev10 Bug 846455 for more information.
427 if (CORDebuggerAttached() &&
428 (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT))
429 {
430 return g_pDebugInterface->SendCtrlCToDebugger(dwCtrlType);
431 }
432 else
433#endif // DEBUGGING_SUPPORTED
434 {
435 if (dwCtrlType == CTRL_CLOSE_EVENT)
436 {
437 // Initiate shutdown so the ProcessExit handlers run
438 ForceEEShutdown(SCA_ReturnWhenShutdownComplete);
439 }
440
441 g_fInControlC = true; // only for weakening assertions in checked build.
442 return FALSE; // keep looking for a real handler.
443 }
444}
445#endif
446
447// A host can specify that it only wants one version of hosting interface to be used.
448BOOL g_singleVersionHosting;
449
450
451
452void InitializeStartupFlags()
453{
454 CONTRACTL {
455 NOTHROW;
456 GC_TRIGGERS;
457 MODE_ANY;
458 } CONTRACTL_END;
459
460 STARTUP_FLAGS flags = CorHost2::GetStartupFlags();
461
462
463 if (flags & STARTUP_CONCURRENT_GC)
464 g_IGCconcurrent = 1;
465 else
466 g_IGCconcurrent = 0;
467
468
469 g_heap_type = (flags & STARTUP_SERVER_GC) == 0 ? GC_HEAP_WKS : GC_HEAP_SVR;
470 g_IGCHoardVM = (flags & STARTUP_HOARD_GC_VM) == 0 ? 0 : 1;
471}
472#endif // CROSSGEN_COMPILE
473
474
475#ifdef FEATURE_PREJIT
476// BBSweepStartFunction is the first function to execute in the BBT sweeper thread.
477// It calls WatchForSweepEvent where we wait until a sweep occurs.
478DWORD __stdcall BBSweepStartFunction(LPVOID lpArgs)
479{
480 CONTRACTL
481 {
482 THROWS;
483 GC_TRIGGERS;
484 MODE_PREEMPTIVE;
485 }
486 CONTRACTL_END;
487
488 class CLRBBSweepCallback : public ICLRBBSweepCallback
489 {
490 virtual HRESULT WriteProfileData()
491 {
492 BEGIN_ENTRYPOINT_NOTHROW
493 WRAPPER_NO_CONTRACT;
494 Module::WriteAllModuleProfileData(false);
495 END_ENTRYPOINT_NOTHROW;
496 return S_OK;
497 }
498 } clrCallback;
499
500 EX_TRY
501 {
502 g_BBSweep.WatchForSweepEvents(&clrCallback);
503 }
504 EX_CATCH
505 {
506 }
507 EX_END_CATCH(RethrowTerminalExceptions)
508
509 return 0;
510}
511#endif // FEATURE_PREJIT
512
513
514//-----------------------------------------------------------------------------
515
516void InitGSCookie()
517{
518 CONTRACTL
519 {
520 THROWS;
521 GC_NOTRIGGER;
522 SO_TOLERANT;
523 MODE_ANY;
524 }
525 CONTRACTL_END;
526
527 GSCookie * pGSCookiePtr = GetProcessGSCookiePtr();
528
529 DWORD oldProtection;
530 if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), PAGE_EXECUTE_READWRITE, &oldProtection))
531 {
532 ThrowLastError();
533 }
534
535#ifndef FEATURE_PAL
536 // The GSCookie cannot be in a writeable page
537 assert(((oldProtection & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|
538 PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOMBINE)) == 0));
539
540 // Forces VC cookie to be initialized.
541 void * pf = &__security_check_cookie;
542 pf = NULL;
543
544 GSCookie val = (GSCookie)(__security_cookie ^ GetTickCount());
545#else // !FEATURE_PAL
546 // REVIEW: Need something better for PAL...
547 GSCookie val = (GSCookie)GetTickCount();
548#endif // !FEATURE_PAL
549
550#ifdef _DEBUG
551 // In _DEBUG, always use the same value to make it easier to search for the cookie
552 val = (GSCookie) WIN64_ONLY(0x9ABCDEF012345678) NOT_WIN64(0x12345678);
553#endif
554
555 // To test if it is initialized. Also for ICorMethodInfo::getGSCookie()
556 if (val == 0)
557 val ++;
558 *pGSCookiePtr = val;
559
560 if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), oldProtection, &oldProtection))
561 {
562 ThrowLastError();
563 }
564}
565
566Volatile<BOOL> g_bIsGarbageCollectorFullyInitialized = FALSE;
567
568void SetGarbageCollectorFullyInitialized()
569{
570 LIMITED_METHOD_CONTRACT;
571
572 g_bIsGarbageCollectorFullyInitialized = TRUE;
573}
574
575// Tells whether the garbage collector is fully initialized
576// Stronger than IsGCHeapInitialized
577BOOL IsGarbageCollectorFullyInitialized()
578{
579 LIMITED_METHOD_CONTRACT;
580
581 return g_bIsGarbageCollectorFullyInitialized;
582}
583
584// ---------------------------------------------------------------------------
585// %%Function: EEStartupHelper
586//
587// Parameters:
588// fFlags - Initialization flags for the engine. See the
589// EEStartupFlags enumerator for valid values.
590//
591// Returns:
592// S_OK - On success
593//
594// Description:
595// Reserved to initialize the EE runtime engine explicitly.
596// ---------------------------------------------------------------------------
597
598#ifndef IfFailGotoLog
599#define IfFailGotoLog(EXPR, LABEL) \
600do { \
601 hr = (EXPR);\
602 if(FAILED(hr)) { \
603 STRESS_LOG2(LF_STARTUP, LL_ALWAYS, "%s failed with code %x", #EXPR, hr);\
604 goto LABEL; \
605 } \
606 else \
607 STRESS_LOG1(LF_STARTUP, LL_ALWAYS, "%s completed", #EXPR);\
608} while (0)
609#endif
610
611#ifndef IfFailGoLog
612#define IfFailGoLog(EXPR) IfFailGotoLog(EXPR, ErrExit)
613#endif
614
615void EEStartupHelper(COINITIEE fFlags)
616{
617 CONTRACTL
618 {
619 THROWS;
620 GC_TRIGGERS;
621 MODE_ANY;
622 } CONTRACTL_END;
623
624#ifdef ENABLE_CONTRACTS_IMPL
625 {
626 extern void ContractRegressionCheck();
627 ContractRegressionCheck();
628 }
629#endif
630
631 HRESULT hr = S_OK;
632 static ConfigDWORD breakOnEELoad;
633 EX_TRY
634 {
635 g_fEEInit = true;
636
637#ifndef CROSSGEN_COMPILE
638
639#ifdef _DEBUG
640 DisableGlobalAllocStore();
641#endif //_DEBUG
642
643#ifndef FEATURE_PAL
644 ::SetConsoleCtrlHandler(DbgCtrlCHandler, TRUE/*add*/);
645#endif
646
647#endif // CROSSGEN_COMPILE
648
649 // SString initialization
650 // This needs to be done before config because config uses SString::Empty()
651 SString::Startup();
652
653 // Initialize EEConfig
654 if (!g_pConfig)
655 {
656 IfFailGo(EEConfig::Setup());
657 }
658
659#ifndef CROSSGEN_COMPILE
660 // Initialize Numa and CPU group information
661 // Need to do this as early as possible. Used by creating object handle
662 // table inside Ref_Initialization() before GC is initialized.
663 NumaNodeInfo::InitNumaNodeInfo();
664 CPUGroupInfo::EnsureInitialized();
665
666
667 // Initialize global configuration settings based on startup flags
668 // This needs to be done before the EE has started
669 InitializeStartupFlags();
670
671 InitThreadManager();
672 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "Returned successfully from InitThreadManager");
673
674#ifdef FEATURE_PERFTRACING
675 // Initialize the event pipe.
676 EventPipe::Initialize();
677#endif // FEATURE_PERFTRACING
678
679#ifdef FEATURE_GDBJIT
680 // Initialize gdbjit
681 NotifyGdb::Initialize();
682#endif // FEATURE_GDBJIT
683
684#ifdef FEATURE_EVENT_TRACE
685 // Initialize event tracing early so we can trace CLR startup time events.
686 InitializeEventTracing();
687
688 // Fire the EE startup ETW event
689 ETWFireEvent(EEStartupStart_V1);
690#endif // FEATURE_EVENT_TRACE
691
692 InitGSCookie();
693
694 Frame::Init();
695
696#ifdef FEATURE_TESTHOOKS
697 IfFailGo(CLRTestHookManager::CheckConfig());
698#endif
699
700#endif // CROSSGEN_COMPILE
701
702
703#ifdef STRESS_LOG
704 if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, g_pConfig->StressLog ()) != 0) {
705 unsigned facilities = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LF_ALL);
706 unsigned level = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
707 unsigned bytesPerThread = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 4);
708 unsigned totalBytes = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
709 StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, GetModuleInst());
710 g_pStressLog = &StressLog::theLog;
711 }
712#endif
713
714#ifdef LOGGING
715 InitializeLogging();
716#endif
717
718#ifdef ENABLE_PERF_LOG
719 PerfLog::PerfLogInitialize();
720#endif //ENABLE_PERF_LOG
721
722#ifdef FEATURE_PERFMAP
723 PerfMap::Initialize();
724#endif
725
726 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Starting===================");
727
728#ifndef CROSSGEN_COMPILE
729#ifndef FEATURE_PAL
730 IfFailGoLog(EnsureRtlFunctions());
731#endif // !FEATURE_PAL
732 InitEventStore();
733#endif
734
735 // Fusion
736 // Initialize the general Assembly Binder infrastructure
737 IfFailGoLog(CCoreCLRBinderHelper::Init());
738
739 if (g_pConfig != NULL)
740 {
741 IfFailGoLog(g_pConfig->sync());
742 }
743
744 // Fire the runtime information ETW event
745 ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Normal);
746
747 if (breakOnEELoad.val(CLRConfig::UNSUPPORTED_BreakOnEELoad) == 1)
748 {
749#ifdef _DEBUG
750 _ASSERTE(!"Start loading EE!");
751#else
752 DebugBreak();
753#endif
754 }
755
756#ifdef ENABLE_STARTUP_DELAY
757 PREFIX_ASSUME(NULL != g_pConfig);
758 if (g_pConfig->StartupDelayMS())
759 {
760 ClrSleepEx(g_pConfig->StartupDelayMS(), FALSE);
761 }
762#endif
763
764#if USE_DISASSEMBLER
765 if ((g_pConfig->GetGCStressLevel() & (EEConfig::GCSTRESS_INSTR_JIT | EEConfig::GCSTRESS_INSTR_NGEN)) != 0)
766 {
767 Disassembler::StaticInitialize();
768 if (!Disassembler::IsAvailable())
769 {
770 fprintf(stderr, "External disassembler is not available.\n");
771 IfFailGo(E_FAIL);
772 }
773 }
774#endif // USE_DISASSEMBLER
775
776 // Monitors, Crsts, and SimpleRWLocks all use the same spin heuristics
777 // Cache the (potentially user-overridden) values now so they are accessible from asm routines
778 InitializeSpinConstants();
779
780#ifndef CROSSGEN_COMPILE
781
782
783#ifdef FEATURE_PREJIT
784 // Initialize the sweeper thread.
785 if (g_pConfig->GetZapBBInstr() != NULL)
786 {
787 DWORD threadID;
788 HANDLE hBBSweepThread = ::CreateThread(NULL,
789 0,
790 (LPTHREAD_START_ROUTINE) BBSweepStartFunction,
791 NULL,
792 0,
793 &threadID);
794 _ASSERTE(hBBSweepThread);
795 g_BBSweep.SetBBSweepThreadHandle(hBBSweepThread);
796 }
797#endif // FEATURE_PREJIT
798
799#ifdef ENABLE_PERF_COUNTERS
800 hr = PerfCounters::Init();
801 _ASSERTE(SUCCEEDED(hr));
802 IfFailGo(hr);
803#endif
804
805#ifdef FEATURE_INTERPRETER
806 Interpreter::Initialize();
807#endif // FEATURE_INTERPRETER
808
809 StubManager::InitializeStubManagers();
810
811#ifndef FEATURE_PAL
812 {
813 // Record mscorwks geometry
814 PEDecoder pe(g_pMSCorEE);
815
816 g_runtimeLoadedBaseAddress = (SIZE_T)pe.GetBase();
817 g_runtimeVirtualSize = (SIZE_T)pe.GetVirtualSize();
818 InitCodeAllocHint(g_runtimeLoadedBaseAddress, g_runtimeVirtualSize, GetRandomInt(64));
819 }
820#endif // !FEATURE_PAL
821
822#endif // CROSSGEN_COMPILE
823
824 // Set up the cor handle map. This map is used to load assemblies in
825 // memory instead of using the normal system load
826 PEImage::Startup();
827
828 AccessCheckOptions::Startup();
829
830 MscorlibBinder::Startup();
831
832 Stub::Init();
833 StubLinkerCPU::Init();
834
835#ifndef CROSSGEN_COMPILE
836
837 InitializeGarbageCollector();
838
839 // Initialize remoting
840
841 if (!GCHandleUtilities::GetGCHandleManager()->Initialize())
842 {
843 IfFailGo(E_OUTOFMEMORY);
844 }
845
846 g_pEEShutDownEvent = new CLREvent();
847 g_pEEShutDownEvent->CreateManualEvent(FALSE);
848
849 VirtualCallStubManager::InitStatic();
850
851 GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure);
852
853#endif // CROSSGEN_COMPILE
854
855 // Setup the domains. Threads are started in a default domain.
856
857 // Static initialization
858 PEAssembly::Attach();
859 BaseDomain::Attach();
860 SystemDomain::Attach();
861
862 // Start up the EE intializing all the global variables
863 ECall::Init();
864
865 COMDelegate::Init();
866
867 ExecutionManager::Init();
868
869 JitHost::Init();
870
871#ifndef CROSSGEN_COMPILE
872
873#ifndef FEATURE_PAL
874 if (!RegisterOutOfProcessWatsonCallbacks())
875 {
876 IfFailGo(E_FAIL);
877 }
878#endif // !FEATURE_PAL
879
880#ifdef DEBUGGING_SUPPORTED
881 if(!NingenEnabled())
882 {
883 // Initialize the debugging services. This must be done before any
884 // EE thread objects are created, and before any classes or
885 // modules are loaded.
886 InitializeDebugger(); // throws on error
887 }
888#endif // DEBUGGING_SUPPORTED
889
890#ifdef MDA_SUPPORTED
891 ManagedDebuggingAssistants::EEStartupActivation();
892#endif
893
894#ifdef PROFILING_SUPPORTED
895 // Initialize the profiling services.
896 hr = ProfilingAPIUtility::InitializeProfiling();
897
898 _ASSERTE(SUCCEEDED(hr));
899 IfFailGo(hr);
900#endif // PROFILING_SUPPORTED
901
902 InitializeExceptionHandling();
903
904 //
905 // Install our global exception filter
906 //
907 if (!InstallUnhandledExceptionFilter())
908 {
909 IfFailGo(E_FAIL);
910 }
911
912 // throws on error
913 SetupThread();
914
915#ifdef DEBUGGING_SUPPORTED
916 // Notify debugger once the first thread is created to finish initialization.
917 if (g_pDebugInterface != NULL)
918 {
919 g_pDebugInterface->StartupPhase2(GetThread());
920 }
921#endif
922
923 InitPreStubManager();
924
925#ifdef FEATURE_COMINTEROP
926 InitializeComInterop();
927#endif // FEATURE_COMINTEROP
928
929 StubHelpers::Init();
930 NDirect::Init();
931
932 // Before setting up the execution manager initialize the first part
933 // of the JIT helpers.
934 InitJITHelpers1();
935 InitJITHelpers2();
936
937 SyncBlockCache::Attach();
938
939 // Set up the sync block
940 SyncBlockCache::Start();
941
942 StackwalkCache::Init();
943
944 // In coreclr, clrjit is compiled into it, but SO work in clrjit has not been done.
945#ifdef FEATURE_STACK_PROBE
946 if (CLRHosted() && GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
947 {
948 InitStackProbes();
949 }
950#endif
951
952 // This isn't done as part of InitializeGarbageCollector() above because it
953 // requires write barriers to have been set up on x86, which happens as part
954 // of InitJITHelpers1.
955 hr = g_pGCHeap->Initialize();
956 IfFailGo(hr);
957
958 // This isn't done as part of InitializeGarbageCollector() above because thread
959 // creation requires AppDomains to have been set up.
960 FinalizerThread::FinalizerThreadCreate();
961
962 // Now we really have fully initialized the garbage collector
963 SetGarbageCollectorFullyInitialized();
964
965#ifdef DEBUGGING_SUPPORTED
966 // Make a call to publish the DefaultDomain for the debugger
967 // This should be done before assemblies/modules are loaded into it (i.e. SystemDomain::Init)
968 // and after its OK to switch GC modes and syncronize for sending events to the debugger.
969 // @dbgtodo synchronization: this can probably be simplified in V3
970 LOG((LF_CORDB | LF_SYNC | LF_STARTUP, LL_INFO1000, "EEStartup: adding default domain 0x%x\n",
971 SystemDomain::System()->DefaultDomain()));
972 SystemDomain::System()->PublishAppDomainAndInformDebugger(SystemDomain::System()->DefaultDomain());
973#endif
974
975#endif // CROSSGEN_COMPILE
976
977 SystemDomain::System()->Init();
978
979#ifdef PROFILING_SUPPORTED
980 // <TODO>This is to compensate for the DefaultDomain workaround contained in
981 // SystemDomain::Attach in which the first user domain is created before profiling
982 // services can be initialized. Profiling services cannot be moved to before the
983 // workaround because it needs SetupThread to be called.</TODO>
984
985 SystemDomain::NotifyProfilerStartup();
986#endif // PROFILING_SUPPORTED
987
988 g_fEEInit = false;
989
990 SystemDomain::System()->DefaultDomain()->LoadSystemAssemblies();
991
992 SystemDomain::System()->DefaultDomain()->SetupSharedStatics();
993
994#ifdef _DEBUG
995 APIThreadStress::SetThreadStressCount(g_pConfig->GetAPIThreadStressCount());
996#endif
997#ifdef FEATURE_STACK_SAMPLING
998 StackSampler::Init();
999#endif
1000
1001#ifndef CROSSGEN_COMPILE
1002 if (!NingenEnabled())
1003 {
1004 // Perform any once-only SafeHandle initialization.
1005 SafeHandle::Init();
1006 }
1007
1008#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1009 // retrieve configured max size for the mini-metadata buffer (defaults to 64KB)
1010 g_MiniMetaDataBuffMaxSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MiniMdBufferCapacity);
1011 // align up to GetOsPageSize(), with a maximum of 1 MB
1012 g_MiniMetaDataBuffMaxSize = (DWORD) min(ALIGN_UP(g_MiniMetaDataBuffMaxSize, GetOsPageSize()), 1024 * 1024);
1013 // allocate the buffer. this is never touched while the process is running, so it doesn't
1014 // contribute to the process' working set. it is needed only as a "shadow" for a mini-metadata
1015 // buffer that will be set up and reported / updated in the Watson process (the
1016 // DacStreamsManager class coordinates this)
1017 g_MiniMetaDataBuffAddress = (TADDR) ClrVirtualAlloc(NULL,
1018 g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE);
1019#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1020
1021#endif // CROSSGEN_COMPILE
1022
1023 g_fEEStarted = TRUE;
1024 g_EEStartupStatus = S_OK;
1025 hr = S_OK;
1026 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Completed===================");
1027
1028#ifndef CROSSGEN_COMPILE
1029
1030#ifdef _DEBUG
1031
1032 //if g_fEEStarted was false when we loaded the System Module, we did not run ExpandAll on it. In
1033 //this case, make sure we run ExpandAll here. The rationale is that if we Jit before g_fEEStarted
1034 //is true, we can't initialize Com, so we can't jit anything that uses Com types. Also, it's
1035 //probably not safe to Jit while g_fEEStarted is false.
1036 //
1037 //Also, if you run this it's possible we'll call CoInitialize, which defaults to MTA. This might
1038 //mess up an application that uses STA. However, this mode is only supported for certain limited
1039 //jit testing scenarios, so it can live with the limitation.
1040 if (g_pConfig->ExpandModulesOnLoad())
1041 {
1042 SystemDomain::SystemModule()->ExpandAll();
1043 }
1044
1045 // Perform mscorlib consistency check if requested
1046 g_Mscorlib.CheckExtended();
1047
1048#endif // _DEBUG
1049
1050#ifdef HAVE_GCCOVER
1051 MethodDesc::Init();
1052#endif
1053
1054#endif // !CROSSGEN_COMPILE
1055
1056ErrExit: ;
1057 }
1058 EX_CATCH
1059 {
1060#ifdef CROSSGEN_COMPILE
1061 // for minimal impact we won't update hr for regular builds
1062 hr = GET_EXCEPTION()->GetHR();
1063 _ASSERTE(FAILED(hr));
1064 StackSString exceptionMessage;
1065 GET_EXCEPTION()->GetMessage(exceptionMessage);
1066 fprintf(stderr, "%S\n", exceptionMessage.GetUnicode());
1067#endif // CROSSGEN_COMPILE
1068 }
1069 EX_END_CATCH(RethrowTerminalExceptionsWithInitCheck)
1070
1071 if (!g_fEEStarted) {
1072 if (g_fEEInit)
1073 g_fEEInit = false;
1074
1075 if (!FAILED(hr))
1076 hr = E_FAIL;
1077
1078 g_EEStartupStatus = hr;
1079 }
1080
1081 if (breakOnEELoad.val(CLRConfig::UNSUPPORTED_BreakOnEELoad) == 2)
1082 {
1083#ifdef _DEBUG
1084 _ASSERTE(!"Done loading EE!");
1085#else
1086 DebugBreak();
1087#endif
1088 }
1089
1090}
1091
1092LONG FilterStartupException(PEXCEPTION_POINTERS p, PVOID pv)
1093{
1094 CONTRACTL
1095 {
1096 NOTHROW;
1097 GC_NOTRIGGER;
1098 MODE_ANY;
1099 PRECONDITION(CheckPointer(p));
1100 PRECONDITION(CheckPointer(pv));
1101 } CONTRACTL_END;
1102
1103 g_EEStartupStatus = (HRESULT)p->ExceptionRecord->ExceptionInformation[0];
1104
1105 // Make sure we got a failure code in this case
1106 if (!FAILED(g_EEStartupStatus))
1107 g_EEStartupStatus = E_FAIL;
1108
1109 // Initializations has failed so reset the g_fEEInit flag.
1110 g_fEEInit = false;
1111
1112 if (p->ExceptionRecord->ExceptionCode == BOOTUP_EXCEPTION_COMPLUS)
1113 {
1114 // Don't ever handle the exception in a checked build
1115#ifndef _DEBUG
1116 return EXCEPTION_EXECUTE_HANDLER;
1117#endif
1118 }
1119
1120 return EXCEPTION_CONTINUE_SEARCH;
1121}
1122
1123// EEStartup is responcible for all the one time intialization of the runtime. Some of the highlights of
1124// what it does include
1125// * Creates the default and shared, appdomains.
1126// * Loads mscorlib.dll and loads up the fundamental types (System.Object ...)
1127//
1128// see code:EEStartup#TableOfContents for more on the runtime in general.
1129// see code:#EEShutdown for a analagous routine run during shutdown.
1130//
1131HRESULT EEStartup(COINITIEE fFlags)
1132{
1133 // Cannot use normal contracts here because of the PAL_TRY.
1134 STATIC_CONTRACT_NOTHROW;
1135
1136 _ASSERTE(!g_fEEStarted && !g_fEEInit && SUCCEEDED (g_EEStartupStatus));
1137
1138 PAL_TRY(COINITIEE *, pfFlags, &fFlags)
1139 {
1140#ifndef CROSSGEN_COMPILE
1141 InitializeClrNotifications();
1142#ifdef FEATURE_PAL
1143 InitializeJITNotificationTable();
1144 DacGlobals::Initialize();
1145#endif
1146#endif // CROSSGEN_COMPILE
1147
1148 EEStartupHelper(*pfFlags);
1149 }
1150 PAL_EXCEPT_FILTER (FilterStartupException)
1151 {
1152 // The filter should have set g_EEStartupStatus to a failure HRESULT.
1153 _ASSERTE(FAILED(g_EEStartupStatus));
1154 }
1155 PAL_ENDTRY
1156
1157 return g_EEStartupStatus;
1158}
1159
1160
1161#ifndef CROSSGEN_COMPILE
1162
1163#ifdef FEATURE_COMINTEROP
1164
1165void InnerCoEEShutDownCOM()
1166{
1167 CONTRACTL
1168 {
1169 THROWS;
1170 GC_TRIGGERS;
1171 MODE_ANY;
1172 } CONTRACTL_END;
1173
1174 static LONG AlreadyDone = -1;
1175
1176 if (g_fEEStarted != TRUE)
1177 return;
1178
1179 if (FastInterlockIncrement(&AlreadyDone) != 0)
1180 return;
1181
1182 g_fShutDownCOM = true;
1183
1184 // Release IJupiterGCMgr *
1185 RCWWalker::OnEEShutdown();
1186
1187 // Release all of the RCWs in all contexts in all caches.
1188 ReleaseRCWsInCaches(NULL);
1189
1190 // Release all marshaling data in all AppDomains
1191 AppDomainIterator i(TRUE);
1192 while (i.Next())
1193 i.GetDomain()->DeleteMarshalingData();
1194
1195#ifdef FEATURE_APPX
1196 // Cleanup cached factory pointer in SynchronizationContextNative
1197 SynchronizationContextNative::Cleanup();
1198#endif
1199}
1200
1201// ---------------------------------------------------------------------------
1202// %%Function: CoEEShutdownCOM()
1203//
1204// Parameters:
1205// none
1206//
1207// Returns:
1208// Nothing
1209//
1210// Description:
1211// COM Objects shutdown stuff should be done here
1212// ---------------------------------------------------------------------------
1213void STDMETHODCALLTYPE CoEEShutDownCOM()
1214{
1215
1216 CONTRACTL
1217 {
1218 NOTHROW;
1219 GC_TRIGGERS;
1220 MODE_PREEMPTIVE;
1221 ENTRY_POINT;
1222 } CONTRACTL_END;
1223
1224 if (g_fEEStarted != TRUE)
1225 return;
1226
1227 HRESULT hr;
1228 BEGIN_EXTERNAL_ENTRYPOINT(&hr)
1229
1230 InnerCoEEShutDownCOM();
1231
1232 END_EXTERNAL_ENTRYPOINT;
1233
1234 // API doesn't allow us to communicate a failure HRESULT. MDAs can
1235 // be enabled to catch failure inside CanRunManagedCode.
1236 // _ASSERTE(SUCCEEDED(hr));
1237}
1238
1239#endif // FEATURE_COMINTEROP
1240
1241// ---------------------------------------------------------------------------
1242// %%Function: ForceEEShutdown()
1243//
1244// Description: Force the EE to shutdown now.
1245//
1246// Note: returns when sca is SCA_ReturnWhenShutdownComplete.
1247// ---------------------------------------------------------------------------
1248void ForceEEShutdown(ShutdownCompleteAction sca)
1249{
1250 WRAPPER_NO_CONTRACT;
1251
1252 // Don't bother to take the lock for this case.
1253
1254 STRESS_LOG0(LF_STARTUP, INFO3, "EEShutdown invoked from ForceEEShutdown");
1255 EEPolicy::HandleExitProcess(sca);
1256}
1257
1258//---------------------------------------------------------------------------
1259// %%Function: ExternalShutdownHelper
1260//
1261// Parameters:
1262// int exitCode :: process exit code
1263// ShutdownCompleteAction sca :: indicates whether ::ExitProcess() is
1264// called or if the function returns.
1265//
1266// Returns:
1267// Nothing
1268//
1269// Description:
1270// This is a helper shared by CorExitProcess and ShutdownRuntimeWithoutExiting
1271// which causes the runtime to shutdown after the appropriate checks.
1272// ---------------------------------------------------------------------------
1273static void ExternalShutdownHelper(int exitCode, ShutdownCompleteAction sca)
1274{
1275 CONTRACTL {
1276 NOTHROW;
1277 GC_TRIGGERS;
1278 MODE_ANY;
1279 ENTRY_POINT;
1280 } CONTRACTL_END;
1281
1282 CONTRACT_VIOLATION(GCViolation | ModeViolation | SOToleranceViolation);
1283
1284 if (g_fEEShutDown || !g_fEEStarted)
1285 return;
1286
1287 if (HasIllegalReentrancy())
1288 {
1289 return;
1290 }
1291 else
1292 if (!CanRunManagedCode())
1293 {
1294 return;
1295 }
1296
1297 // The exit code for the process is communicated in one of two ways. If the
1298 // entrypoint returns an 'int' we take that. Otherwise we take a latched
1299 // process exit code. This can be modified by the app via System.SetExitCode().
1300 SetLatchedExitCode(exitCode);
1301
1302
1303 ForceEEShutdown(sca);
1304
1305 // @TODO: If we cannot run ManagedCode, BEGIN_EXTERNAL_ENTRYPOINT will skip
1306 // the shutdown. We could call ::ExitProcess in that failure case, but that
1307 // would violate our hosting agreement. We are supposed to go through EEPolicy::
1308 // HandleExitProcess(). Is this legal if !CanRunManagedCode()?
1309
1310}
1311
1312//---------------------------------------------------------------------------
1313// %%Function: void STDMETHODCALLTYPE CorExitProcess(int exitCode)
1314//
1315// Parameters:
1316// int exitCode :: process exit code
1317//
1318// Returns:
1319// Nothing
1320//
1321// Description:
1322// COM Objects shutdown stuff should be done here
1323// ---------------------------------------------------------------------------
1324extern "C" void STDMETHODCALLTYPE CorExitProcess(int exitCode)
1325{
1326 WRAPPER_NO_CONTRACT;
1327
1328 ExternalShutdownHelper(exitCode, SCA_ExitProcessWhenShutdownComplete);
1329}
1330
1331//---------------------------------------------------------------------------
1332// %%Function: ShutdownRuntimeWithoutExiting
1333//
1334// Parameters:
1335// int exitCode :: process exit code
1336//
1337// Returns:
1338// Nothing
1339//
1340// Description:
1341// This is a helper used only by the v4+ Shim to shutdown this runtime and
1342// and return when the work has completed. It is exposed to the Shim via
1343// GetCLRFunction.
1344// ---------------------------------------------------------------------------
1345void ShutdownRuntimeWithoutExiting(int exitCode)
1346{
1347 WRAPPER_NO_CONTRACT;
1348
1349 ExternalShutdownHelper(exitCode, SCA_ReturnWhenShutdownComplete);
1350}
1351
1352//---------------------------------------------------------------------------
1353// %%Function: IsRuntimeStarted
1354//
1355// Parameters:
1356// pdwStartupFlags: out parameter that is set to the startup flags if the
1357// runtime is started.
1358//
1359// Returns:
1360// TRUE if the runtime has been started, FALSE otherwise.
1361//
1362// Description:
1363// This is a helper used only by the v4+ Shim to determine if this runtime
1364// has ever been started. It is exposed ot the Shim via GetCLRFunction.
1365// ---------------------------------------------------------------------------
1366BOOL IsRuntimeStarted(DWORD *pdwStartupFlags)
1367{
1368 LIMITED_METHOD_CONTRACT;
1369
1370 if (pdwStartupFlags != NULL) // this parameter is optional
1371 {
1372 *pdwStartupFlags = 0;
1373 }
1374 return g_fEEStarted;
1375}
1376
1377static bool WaitForEndOfShutdown_OneIteration()
1378{
1379 CONTRACTL{
1380 NOTHROW;
1381 GC_NOTRIGGER;
1382 MODE_PREEMPTIVE;
1383 } CONTRACTL_END;
1384
1385 // We are shutting down. GC triggers does not have any effect now.
1386 CONTRACT_VIOLATION(GCViolation);
1387
1388 // If someone calls EEShutDown while holding OS loader lock, the thread we created for shutdown
1389 // won't start running. This is a deadlock we can not fix. Instead, we timeout and continue the
1390 // current thread.
1391 DWORD timeout = GetEEPolicy()->GetTimeout(OPR_ProcessExit);
1392 timeout *= 2;
1393 ULONGLONG endTime = CLRGetTickCount64() + timeout;
1394 bool done = false;
1395
1396 EX_TRY
1397 {
1398 ULONGLONG curTime = CLRGetTickCount64();
1399 if (curTime > endTime)
1400 {
1401 done = true;
1402 }
1403 else
1404 {
1405#ifdef PROFILING_SUPPORTED
1406 if (CORProfilerPresent())
1407 {
1408 // A profiler is loaded, so just wait without timeout. This allows
1409 // profilers to complete potentially lengthy post processing, without the
1410 // CLR killing them off first. The Office team's server memory profiler,
1411 // for example, does a lot of post-processing that can exceed the 80
1412 // second imit we normally impose here. The risk of waiting without
1413 // timeout is that, if there really is a deadlock, shutdown will hang.
1414 // Since that will only happen if a profiler is loaded, that is a
1415 // reasonable compromise
1416 timeout = INFINITE;
1417 }
1418 else
1419#endif //PROFILING_SUPPORTED
1420 {
1421 timeout = static_cast<DWORD>(endTime - curTime);
1422 }
1423 DWORD status = g_pEEShutDownEvent->Wait(timeout,TRUE);
1424 if (status == WAIT_OBJECT_0 || status == WAIT_TIMEOUT)
1425 {
1426 done = true;
1427 }
1428 else
1429 {
1430 done = false;
1431 }
1432 }
1433 }
1434 EX_CATCH
1435 {
1436 }
1437 EX_END_CATCH(SwallowAllExceptions);
1438 return done;
1439}
1440
1441void WaitForEndOfShutdown()
1442{
1443 CONTRACTL{
1444 NOTHROW;
1445 GC_NOTRIGGER;
1446 MODE_PREEMPTIVE;
1447 } CONTRACTL_END;
1448
1449 // We are shutting down. GC triggers does not have any effect now.
1450 CONTRACT_VIOLATION(GCViolation);
1451
1452 Thread *pThread = GetThread();
1453 // After a thread is blocked in WaitForEndOfShutdown, the thread should not enter runtime again,
1454 // and block at WaitForEndOfShutdown again.
1455 if (pThread)
1456 {
1457 _ASSERTE(!pThread->HasThreadStateNC(Thread::TSNC_BlockedForShutdown));
1458 pThread->SetThreadStateNC(Thread::TSNC_BlockedForShutdown);
1459 }
1460
1461 while (!WaitForEndOfShutdown_OneIteration());
1462}
1463
1464// ---------------------------------------------------------------------------
1465// Function: EEShutDownHelper(BOOL fIsDllUnloading)
1466//
1467// The real meat of shut down happens here. See code:#EEShutDown for details, including
1468// what fIsDllUnloading means.
1469//
1470void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
1471{
1472 CONTRACTL
1473 {
1474 NOTHROW;
1475 GC_TRIGGERS;
1476 MODE_ANY;
1477 } CONTRACTL_END;
1478
1479 // Used later for a callback.
1480 CEEInfo ceeInf;
1481
1482 if(fIsDllUnloading)
1483 {
1484 ETW::EnumerationLog::ProcessShutdown();
1485 }
1486
1487#ifdef FEATURE_PERFTRACING
1488 // Shutdown the event pipe.
1489 EventPipe::Shutdown();
1490#endif // FEATURE_PERFTRACING
1491
1492#if defined(FEATURE_COMINTEROP)
1493 // Get the current thread.
1494 Thread * pThisThread = GetThread();
1495#endif
1496
1497 // If the process is detaching then set the global state.
1498 // This is used to get around FreeLibrary problems.
1499 if(fIsDllUnloading)
1500 g_fProcessDetach = true;
1501
1502 if (IsDbgHelperSpecialThread())
1503 {
1504 // Our debugger helper thread does not allow Thread object to be set up.
1505 // We should not run shutdown code on debugger helper thread.
1506 _ASSERTE(fIsDllUnloading);
1507 return;
1508 }
1509
1510#ifdef _DEBUG
1511 // stop API thread stress
1512 APIThreadStress::SetThreadStressCount(0);
1513#endif
1514
1515 STRESS_LOG1(LF_STARTUP, LL_INFO10, "EEShutDown entered unloading = %d", fIsDllUnloading);
1516
1517#ifdef _DEBUG
1518 if (_DbgBreakCount)
1519 _ASSERTE(!"An assert was hit before EE Shutting down");
1520
1521 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnEEShutdown))
1522 _ASSERTE(!"Shutting down EE!");
1523#endif
1524
1525#ifdef DEBUGGING_SUPPORTED
1526 // This is a nasty, terrible, horrible thing. If we're being
1527 // called from our DLL main, then the odds are good that our DLL
1528 // main has been called as the result of some person calling
1529 // ExitProcess. That rips the debugger helper thread away very
1530 // ungracefully. This check is an attempt to recognize that case
1531 // and avoid the impending hang when attempting to get the helper
1532 // thread to do things for us.
1533 if ((g_pDebugInterface != NULL) && g_fProcessDetach)
1534 g_pDebugInterface->EarlyHelperThreadDeath();
1535#endif // DEBUGGING_SUPPORTED
1536
1537 BOOL fFinalizeOK = FALSE;
1538
1539 EX_TRY
1540 {
1541 ClrFlsSetThreadType(ThreadType_Shutdown);
1542
1543 if (!fIsDllUnloading)
1544 {
1545 ProcessEventForHost(Event_ClrDisabled, NULL);
1546 }
1547 else if (g_fEEShutDown)
1548 {
1549 // I'm in the final shutdown and the first part has already been run.
1550 goto part2;
1551 }
1552
1553 // Indicate the EE is the shut down phase.
1554 g_fEEShutDown |= ShutDown_Start;
1555
1556 fFinalizeOK = TRUE;
1557
1558 // Terminate the BBSweep thread
1559 g_BBSweep.ShutdownBBSweepThread();
1560
1561 // We perform the final GC only if the user has requested it through the GC class.
1562 // We should never do the final GC for a process detach
1563 if (!g_fProcessDetach && !g_fFastExitProcess)
1564 {
1565 g_fEEShutDown |= ShutDown_Finalize1;
1566 FinalizerThread::EnableFinalization();
1567 fFinalizeOK = FinalizerThread::FinalizerThreadWatchDog();
1568 }
1569
1570
1571 // Ok. Let's stop the EE.
1572 if (!g_fProcessDetach)
1573 {
1574 // Convert key locks into "shutdown" mode. A lock in shutdown mode means:
1575 // - Only the finalizer/helper/shutdown threads will be able to take the the lock.
1576 // - Any other thread that tries takes it will just get redirected to an endless WaitForEndOfShutdown().
1577 //
1578 // The only managed code that should run after this point is the finalizers for shutdown.
1579 // We convert locks needed for running + debugging such finalizers. Since such locks may need to be
1580 // juggled between multiple threads (finalizer/helper/shutdown), no single thread can take the
1581 // lock and not give it up.
1582 //
1583 // Each lock needs its own shutdown flag (they can't all be converted at once).
1584 // To avoid deadlocks, we need to convert locks in order of crst level (biggest first).
1585
1586 // Notify the debugger that we're going into shutdown to convert debugger-lock to shutdown.
1587 if (g_pDebugInterface != NULL)
1588 {
1589 g_pDebugInterface->LockDebuggerForShutdown();
1590 }
1591
1592 // This call will convert the ThreadStoreLock into "shutdown" mode, just like the debugger lock above.
1593 g_fEEShutDown |= ShutDown_Finalize2;
1594 if (fFinalizeOK)
1595 {
1596 fFinalizeOK = FinalizerThread::FinalizerThreadWatchDog();
1597 }
1598
1599 if (!fFinalizeOK)
1600 {
1601 // One of the calls to FinalizerThreadWatchDog failed due to timeout, so we need to prevent
1602 // any thread from running managed code, including the finalizer.
1603 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_SHUTDOWN);
1604 g_fSuspendOnShutdown = TRUE;
1605 g_fSuspendFinalizerOnShutdown = TRUE;
1606 ThreadStore::TrapReturningThreads(TRUE);
1607 ThreadSuspend::RestartEE(FALSE, TRUE);
1608 }
1609 }
1610
1611#ifdef FEATURE_EVENT_TRACE
1612 // Flush managed object allocation logging data.
1613 // We do this after finalization is complete and returning threads have been trapped, so that
1614 // no there will be no more managed allocations and no more GCs which will manipulate the
1615 // allocation sampling data structures.
1616 ETW::TypeSystemLog::FlushObjectAllocationEvents();
1617#endif // FEATURE_EVENT_TRACE
1618
1619#ifdef FEATURE_PERFMAP
1620 // Flush and close the perf map file.
1621 PerfMap::Destroy();
1622#endif
1623
1624#ifdef FEATURE_PREJIT
1625 {
1626 // If we're doing basic block profiling, we need to write the log files to disk.
1627
1628 static BOOL fIBCLoggingDone = FALSE;
1629 if (!fIBCLoggingDone)
1630 {
1631 if (g_IBCLogger.InstrEnabled())
1632 {
1633 Thread * pThread = GetThread();
1634 ThreadLocalIBCInfo* pInfo = pThread->GetIBCInfo();
1635
1636 // Acquire the Crst lock before creating the IBCLoggingDisabler object.
1637 // Only one thread at a time can be processing an IBC logging event.
1638 CrstHolder lock(IBCLogger::GetSync());
1639 {
1640 IBCLoggingDisabler disableLogging( pInfo ); // runs IBCLoggingDisabler::DisableLogging
1641
1642 CONTRACT_VIOLATION(GCViolation);
1643 Module::WriteAllModuleProfileData(true);
1644 }
1645 }
1646 fIBCLoggingDone = TRUE;
1647 }
1648 }
1649
1650#endif // FEATURE_PREJIT
1651
1652 ceeInf.JitProcessShutdownWork(); // Do anything JIT-related that needs to happen at shutdown.
1653
1654#ifdef FEATURE_INTERPRETER
1655 // This will check a flag and do nothing if not enabled.
1656 Interpreter::PrintPostMortemData();
1657#endif // FEATURE_INTERPRETER
1658
1659 FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
1660
1661 if (g_fProcessDetach)
1662 {
1663 ThreadStore::TrapReturningThreads(TRUE);
1664 }
1665
1666 if (!g_fProcessDetach && !fFinalizeOK)
1667 {
1668 goto lDone;
1669 }
1670
1671#ifdef PROFILING_SUPPORTED
1672 // If profiling is enabled, then notify of shutdown first so that the
1673 // profiler can make any last calls it needs to. Do this only if we
1674 // are not detaching
1675
1676 if (CORProfilerPresent())
1677 {
1678 // If EEShutdown is not being called due to a ProcessDetach event, so
1679 // the profiler should still be present
1680 if (!g_fProcessDetach)
1681 {
1682 BEGIN_PIN_PROFILER(CORProfilerPresent());
1683 GCX_PREEMP();
1684 g_profControlBlock.pProfInterface->Shutdown();
1685 END_PIN_PROFILER();
1686 }
1687
1688 g_fEEShutDown |= ShutDown_Profiler;
1689
1690 // Free the interface objects.
1691 ProfilingAPIUtility::TerminateProfiling();
1692 }
1693#endif // PROFILING_SUPPORTED
1694
1695
1696#ifdef _DEBUG
1697 g_fEEShutDown |= ShutDown_SyncBlock;
1698#endif
1699 {
1700 // From here on out we might call stuff that violates mode requirements, but we ignore these
1701 // because we are shutting down.
1702 CONTRACT_VIOLATION(ModeViolation);
1703
1704#ifdef FEATURE_COMINTEROP
1705 // We need to call CoUninitialize in part one to ensure orderly shutdown of COM dlls.
1706 if (!g_fFastExitProcess)
1707 {
1708 if (pThisThread!= NULL)
1709 {
1710 pThisThread->CoUninitialize();
1711 }
1712 }
1713#endif // FEATURE_COMINTEROP
1714 }
1715
1716 // This is the end of Part 1.
1717
1718part2:
1719 // If process shutdown is in progress and Crst locks to be used in shutdown phase 2
1720 // are already in use, then skip phase 2. This will happen only when those locks
1721 // are orphaned. In Vista, the penalty for attempting to enter such locks is
1722 // instant process termination.
1723 if (g_fProcessDetach)
1724 {
1725 // The assert below is a bit too aggresive and has generally brought cases that have been race conditions
1726 // and not easily reproed to validate a bug. A typical race scenario is when there are two threads,
1727 // T1 and T2, with T2 having taken a lock (e.g. SystemDomain lock), the OS terminates
1728 // T2 for some reason. Later, when we enter the shutdown thread, we would assert on such
1729 // a lock leak, but there is not much we can do since the OS wont notify us prior to thread
1730 // termination. And this is not even a user bug.
1731 //
1732 // Converting it to a STRESS LOG to reduce noise, yet keep things in radar if they need
1733 // to be investigated.
1734 //_ASSERTE_MSG(g_ShutdownCrstUsageCount == 0, "Some locks to be taken during shutdown may already be orphaned!");
1735 if (g_ShutdownCrstUsageCount > 0)
1736 {
1737 STRESS_LOG0(LF_STARTUP, LL_INFO10, "Some locks to be taken during shutdown may already be orphaned!");
1738 goto lDone;
1739 }
1740 }
1741
1742 {
1743 CONTRACT_VIOLATION(ModeViolation);
1744
1745 // On the new plan, we only do the tear-down under the protection of the loader
1746 // lock -- after the OS has stopped all other threads.
1747 if (fIsDllUnloading && (g_fEEShutDown & ShutDown_Phase2) == 0)
1748 {
1749 g_fEEShutDown |= ShutDown_Phase2;
1750
1751 // Shutdown finalizer before we suspend all background threads. Otherwise we
1752 // never get to finalize anything. Obviously.
1753
1754#ifdef _DEBUG
1755 if (_DbgBreakCount)
1756 _ASSERTE(!"An assert was hit After Finalizer run");
1757#endif
1758
1759 // No longer process exceptions
1760 g_fNoExceptions = true;
1761
1762 //
1763 // Remove our global exception filter. If it was NULL before, we want it to be null now.
1764 //
1765 UninstallUnhandledExceptionFilter();
1766
1767 // <TODO>@TODO: This does things which shouldn't occur in part 2. Namely,
1768 // calling managed dll main callbacks (AppDomain::SignalProcessDetach), and
1769 // RemoveAppDomainFromIPC.
1770 //
1771 // (If we move those things to earlier, this can be called only if fShouldWeCleanup.)</TODO>
1772 if (!g_fFastExitProcess)
1773 {
1774 SystemDomain::DetachBegin();
1775 }
1776
1777
1778#ifdef DEBUGGING_SUPPORTED
1779 // Terminate the debugging services.
1780 TerminateDebugger();
1781#endif // DEBUGGING_SUPPORTED
1782
1783 StubManager::TerminateStubManagers();
1784
1785#ifdef FEATURE_INTERPRETER
1786 Interpreter::Terminate();
1787#endif // FEATURE_INTERPRETER
1788
1789#ifdef SHOULD_WE_CLEANUP
1790 if (!g_fFastExitProcess)
1791 {
1792 GCHandleUtilities::GetGCHandleManager()->Shutdown();
1793 }
1794#endif /* SHOULD_WE_CLEANUP */
1795
1796#ifdef ENABLE_PERF_COUNTERS
1797 // Terminate Perf Counters as late as we can (to get the most data)
1798 PerfCounters::Terminate();
1799#endif // ENABLE_PERF_COUNTERS
1800
1801 //@TODO: find the right place for this
1802 VirtualCallStubManager::UninitStatic();
1803
1804#ifdef ENABLE_PERF_LOG
1805 PerfLog::PerfLogDone();
1806#endif //ENABLE_PERF_LOG
1807
1808 Frame::Term();
1809
1810 if (!g_fFastExitProcess)
1811 {
1812 SystemDomain::DetachEnd();
1813 }
1814
1815 TerminateStackProbes();
1816
1817 // Unregister our vectored exception and continue handlers from the OS.
1818 // This will ensure that if any other DLL unload (after ours) has an exception,
1819 // we wont attempt to process that exception (which could lead to various
1820 // issues including AV in the runtime).
1821 //
1822 // This should be done:
1823 //
1824 // 1) As the last action during the shutdown so that any unexpected AVs
1825 // in the runtime during shutdown do result in FailFast in VEH.
1826 //
1827 // 2) Only when the runtime is processing DLL_PROCESS_DETACH.
1828 CLRRemoveVectoredHandlers();
1829
1830#if USE_DISASSEMBLER
1831 Disassembler::StaticClose();
1832#endif // USE_DISASSEMBLER
1833
1834#ifdef _DEBUG
1835 if (_DbgBreakCount)
1836 _ASSERTE(!"EE Shutting down after an assert");
1837#endif
1838
1839
1840#ifdef LOGGING
1841 extern unsigned FcallTimeHist[11];
1842#endif
1843 LOG((LF_STUBS, LL_INFO10, "FcallHist %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
1844 FcallTimeHist[0], FcallTimeHist[1], FcallTimeHist[2], FcallTimeHist[3],
1845 FcallTimeHist[4], FcallTimeHist[5], FcallTimeHist[6], FcallTimeHist[7],
1846 FcallTimeHist[8], FcallTimeHist[9], FcallTimeHist[10]));
1847
1848 WriteJitHelperCountToSTRESSLOG();
1849
1850 STRESS_LOG0(LF_STARTUP, LL_INFO10, "EEShutdown shutting down logging");
1851
1852#if 0 // Dont clean up the stress log, so that even at process exit we have a log (after all the process is going away
1853 if (!g_fFastExitProcess)
1854 StressLog::Terminate(TRUE);
1855#endif
1856
1857 if (g_pConfig != NULL)
1858 g_pConfig->Cleanup();
1859
1860#ifdef LOGGING
1861 ShutdownLogging();
1862#endif
1863 }
1864 }
1865
1866 lDone: ;
1867 }
1868 EX_CATCH
1869 {
1870 }
1871 EX_END_CATCH(SwallowAllExceptions);
1872
1873 ClrFlsClearThreadType(ThreadType_Shutdown);
1874 if (!g_fProcessDetach)
1875 {
1876 g_pEEShutDownEvent->Set();
1877 }
1878}
1879
1880
1881#ifdef FEATURE_COMINTEROP
1882
1883BOOL IsThreadInSTA()
1884{
1885 CONTRACTL
1886 {
1887 NOTHROW;
1888 GC_TRIGGERS;
1889 MODE_ANY;
1890 }
1891 CONTRACTL_END;
1892
1893 // If ole32.dll is not loaded
1894 if (WszGetModuleHandle(W("ole32.dll")) == NULL)
1895 {
1896 return FALSE;
1897 }
1898
1899 BOOL fInSTA = TRUE;
1900 // To be conservative, check if finalizer thread is around
1901 EX_TRY
1902 {
1903 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
1904 if (!pFinalizerThread || pFinalizerThread->Join(0, FALSE) != WAIT_TIMEOUT)
1905 {
1906 fInSTA = FALSE;
1907 }
1908 }
1909 EX_CATCH
1910 {
1911 }
1912 EX_END_CATCH(SwallowAllExceptions);
1913
1914 if (!fInSTA)
1915 {
1916 return FALSE;
1917 }
1918
1919 THDTYPE type;
1920 HRESULT hr = S_OK;
1921
1922 hr = GetCurrentThreadTypeNT5(&type);
1923 if (hr == S_OK)
1924 {
1925 fInSTA = (type == THDTYPE_PROCESSMESSAGES) ? TRUE : FALSE;
1926
1927 // If we get back THDTYPE_PROCESSMESSAGES, we are guaranteed to
1928 // be an STA thread. If not, we are an MTA thread, however
1929 // we can't know if the thread has been explicitly set to MTA
1930 // (via a call to CoInitializeEx) or if it has been implicitly
1931 // made MTA (if it hasn't been CoInitializeEx'd but CoInitialize
1932 // has already been called on some other thread in the process.
1933 }
1934 else
1935 {
1936 // CoInitialize hasn't been called in the process yet so assume the current thread
1937 // is MTA.
1938 fInSTA = FALSE;
1939 }
1940
1941 return fInSTA;
1942}
1943#endif
1944
1945static LONG s_ActiveShutdownThreadCount = 0;
1946
1947// ---------------------------------------------------------------------------
1948// Function: EEShutDownProcForSTAThread(LPVOID lpParameter)
1949//
1950// Parameters:
1951// LPVOID lpParameter: unused
1952//
1953// Description:
1954// When EEShutDown decides that the shut down logic must occur on another thread,
1955// EEShutDown creates a new thread, and this function acts as the thread proc. See
1956// code:#STAShutDown for details.
1957//
1958DWORD WINAPI EEShutDownProcForSTAThread(LPVOID lpParameter)
1959{
1960 STATIC_CONTRACT_SO_INTOLERANT;;
1961
1962
1963 ClrFlsSetThreadType(ThreadType_ShutdownHelper);
1964
1965 EEShutDownHelper(FALSE);
1966 for (int i = 0; i < 10; i ++)
1967 {
1968 if (s_ActiveShutdownThreadCount)
1969 {
1970 return 0;
1971 }
1972 __SwitchToThread(20, CALLER_LIMITS_SPINNING);
1973 }
1974
1975 EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL);
1976 if (action < eRudeExitProcess)
1977 {
1978 action = eRudeExitProcess;
1979 }
1980
1981 UINT exitCode = GetLatchedExitCode();
1982 EEPolicy::HandleExitProcessFromEscalation(action, exitCode);
1983
1984 return 0;
1985}
1986
1987// ---------------------------------------------------------------------------
1988// #EEShutDown
1989//
1990// Function: EEShutDown(BOOL fIsDllUnloading)
1991//
1992// Parameters:
1993// BOOL fIsDllUnloading:
1994// * TRUE => Called from CLR's DllMain (DLL_PROCESS_DETACH). Not safe point for
1995// full cleanup
1996// * FALSE => Called some other way (e.g., end of the CLR's main). Safe to do
1997// full cleanup.
1998//
1999// Description:
2000//
2001// All ee shutdown stuff should be done here. EEShutDown is generally called in one
2002// of two ways:
2003// * 1. From code:EEPolicy::HandleExitProcess (via HandleExitProcessHelper), with
2004// fIsDllUnloading == FALSE. This code path is typically invoked by the CLR's
2005// main just falling through to the end. Full cleanup can be performed when
2006// EEShutDown is called this way.
2007// * 2. From CLR's DllMain (DLL_PROCESS_DETACH), with fIsDllUnloading == TRUE. When
2008// called this way, much cleanup code is unsafe to run, and is thus skipped.
2009//
2010// Actual shut down logic is factored out to EEShutDownHelper which may be called
2011// directly by EEShutDown, or indirectly on another thread (see code:#STAShutDown).
2012//
2013// In order that callees may also know the value of fIsDllUnloading, EEShutDownHelper
2014// sets g_fProcessDetach = fIsDllUnloading, and g_fProcessDetach may then be retrieved
2015// via code:IsAtProcessExit.
2016//
2017// NOTE 1: Actually, g_fProcessDetach is set to TRUE if fIsDllUnloading is TRUE. But
2018// g_fProcessDetach doesn't appear to be explicitly set to FALSE. (Apparently
2019// g_fProcessDetach is implicitly initialized to FALSE as clr.dll is loaded.)
2020//
2021// NOTE 2: EEDllMain(DLL_PROCESS_DETACH) already sets g_fProcessDetach to TRUE, so it
2022// appears EEShutDownHelper doesn't have to.
2023//
2024void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading)
2025{
2026 CONTRACTL {
2027 NOTHROW;
2028 GC_TRIGGERS;
2029 MODE_ANY;
2030 SO_TOLERANT; // we don't need to cleanup 'cus we're shutting down
2031 PRECONDITION(g_fEEStarted);
2032 } CONTRACTL_END;
2033
2034 // If we have not started runtime successfully, it is not safe to call EEShutDown.
2035 if (!g_fEEStarted || g_fFastExitProcess == 2)
2036 {
2037 return;
2038 }
2039
2040 // Stop stack probing and asserts right away. Once we're shutting down, we can do no more.
2041 // And we don't want to SO-protect anything at this point anyway. This really only has impact
2042 // on a debug build.
2043 TerminateStackProbes();
2044
2045 // The process is shutting down. No need to check SO contract.
2046 SO_NOT_MAINLINE_FUNCTION;
2047
2048 // We only do the first part of the shutdown once.
2049 static LONG OnlyOne = -1;
2050
2051 if (!fIsDllUnloading)
2052 {
2053 if (FastInterlockIncrement(&OnlyOne) != 0)
2054 {
2055 // I'm in a regular shutdown -- but another thread got here first.
2056 // It's a race if I return from here -- I'll call ExitProcess next, and
2057 // rip things down while the first thread is half-way through a
2058 // nice cleanup. Rather than do that, I should just wait until the
2059 // first thread calls ExitProcess(). I'll die a nice death when that
2060 // happens.
2061 GCX_PREEMP_NO_DTOR();
2062 WaitForEndOfShutdown();
2063 return;
2064 }
2065
2066#ifdef FEATURE_MULTICOREJIT
2067 if (!AppX::IsAppXProcess()) // When running as Appx, make the delayed timer driven writing be the only option
2068 {
2069 MulticoreJitManager::StopProfileAll();
2070 }
2071#endif
2072 }
2073
2074#ifdef FEATURE_COMINTEROP
2075 if (!fIsDllUnloading && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_FinalizeOnShutdown) && IsThreadInSTA())
2076 {
2077 // #STAShutDown
2078 //
2079 // During shutdown, we may need to release STA interface on the shutdown thread.
2080 // It is possible that the shutdown thread may deadlock. During shutdown, all
2081 // threads are blocked, except the shutdown thread and finalizer thread. If a
2082 // lock is held by one of these suspended threads, it can deadlock the process if
2083 // the shutdown thread tries to enter the lock. To mitigate this risk, create
2084 // another thread (B) to do shutdown activities (i.e., EEShutDownHelper), while
2085 // this thread (A) waits. If B deadlocks, A will time out and immediately return
2086 // from EEShutDown. A will then eventually call the OS's ExitProcess, which will
2087 // kill the deadlocked thread (and all other threads).
2088 //
2089 // Many Windows Forms-based apps will also execute the code below to shift shut
2090 // down logic to a separate thread, even if they don't use COM objects. Reason
2091 // being that they will typically use a main UI thread to pump all Windows
2092 // messages (including messages that facilitate cross-thread COM calls to STA COM
2093 // objects), and will set that thread up as an STA thread just in case there are
2094 // such cross-thread COM calls to contend with. In fact, when you use VS's
2095 // File.New.Project to make a new Windows Forms project, VS will mark Main() with
2096 // [STAThread]
2097 DWORD thread_id = 0;
2098 if (CreateThread(NULL,0,EEShutDownProcForSTAThread,NULL,0,&thread_id))
2099 {
2100 GCX_PREEMP_NO_DTOR();
2101
2102 ClrFlsSetThreadType(ThreadType_Shutdown);
2103 WaitForEndOfShutdown();
2104 FastInterlockIncrement(&s_ActiveShutdownThreadCount);
2105 ClrFlsClearThreadType(ThreadType_Shutdown);
2106 }
2107 }
2108 else
2109 // Otherwise, this thread calls EEShutDownHelper directly. First switch to
2110 // cooperative mode if this is a managed thread
2111#endif
2112 if (GetThread())
2113 {
2114 GCX_COOP();
2115 EEShutDownHelper(fIsDllUnloading);
2116 if (!fIsDllUnloading)
2117 {
2118 FastInterlockIncrement(&s_ActiveShutdownThreadCount);
2119 }
2120 }
2121 else
2122 {
2123 EEShutDownHelper(fIsDllUnloading);
2124 if (!fIsDllUnloading)
2125 {
2126 FastInterlockIncrement(&s_ActiveShutdownThreadCount);
2127 }
2128 }
2129}
2130
2131// ---------------------------------------------------------------------------
2132// %%Function: IsRuntimeActive()
2133//
2134// Parameters:
2135// none
2136//
2137// Returns:
2138// TRUE or FALSE
2139//
2140// Description: Indicates if the runtime is active or not. "Active" implies
2141// that the runtime has started and is in a position to run
2142// managed code. If either of these conditions are false, the
2143// function return FALSE.
2144//
2145// Why couldnt we add !g_fEEStarted check in CanRunManagedCode?
2146//
2147//
2148// ExecuteDLL in ceemain.cpp could start the runtime
2149// (due to DLL_PROCESS_ATTACH) after invoking CanRunManagedCode.
2150// If the function were to be modified, then this scenario could fail.
2151// Hence, I have built over CanRunManagedCode in IsRuntimeActive.
2152
2153// ---------------------------------------------------------------------------
2154BOOL IsRuntimeActive()
2155{
2156 // If the runtime has started AND we can run managed code,
2157 // then runtime is considered "active".
2158 BOOL fCanRunManagedCode = CanRunManagedCode();
2159 return (g_fEEStarted && fCanRunManagedCode);
2160}
2161
2162// ---------------------------------------------------------------------------
2163// %%Function: CanRunManagedCode()
2164//
2165// Parameters:
2166// none
2167//
2168// Returns:
2169// true or false
2170//
2171// Description: Indicates if one is currently allowed to run managed code.
2172// ---------------------------------------------------------------------------
2173NOINLINE BOOL CanRunManagedCodeRare(LoaderLockCheck::kind checkKind, HINSTANCE hInst /*= 0*/)
2174{
2175 CONTRACTL {
2176 NOTHROW;
2177 if (checkKind == LoaderLockCheck::ForMDA) { GC_TRIGGERS; } else { GC_NOTRIGGER; }; // because of the CustomerDebugProbe
2178 MODE_ANY;
2179 SO_TOLERANT;
2180 } CONTRACTL_END;
2181
2182 // If we are shutting down the runtime, then we cannot run code.
2183 if (g_fForbidEnterEE)
2184 return FALSE;
2185
2186 // If pre-loaded objects are not present, then no way.
2187 if (g_pPreallocatedOutOfMemoryException == NULL)
2188 return FALSE;
2189
2190 // If we are finaling live objects or processing ExitProcess event,
2191 // we can not allow managed method to run unless the current thread
2192 // is the finalizer thread
2193 if ((g_fEEShutDown & ShutDown_Finalize2) && !FinalizerThread::IsCurrentThreadFinalizer())
2194 return FALSE;
2195
2196#if defined(FEATURE_COMINTEROP) && defined(MDA_SUPPORTED)
2197 if ((checkKind == LoaderLockCheck::ForMDA) && (NULL == MDA_GET_ASSISTANT(LoaderLock)))
2198 return TRUE;
2199
2200 if (checkKind == LoaderLockCheck::None)
2201 return TRUE;
2202
2203 // If we are checking whether the OS loader lock is held by the current thread, then
2204 // it better not be. Note that ShouldCheckLoaderLock is a cached test for whether
2205 // we are checking this probe. So we can call AuxUlibIsDLLSynchronizationHeld before
2206 // verifying that the probe is still enabled.
2207 //
2208 // What's the difference between ignoreLoaderLock & ShouldCheckLoaderLock?
2209 // ShouldCheckLoaderLock is a process-wide flag. In a few places where we
2210 // *know* we are in the loader lock but haven't quite reached the dangerous
2211 // point, we call CanRunManagedCode suppressing/deferring this check.
2212 BOOL IsHeld;
2213
2214 if (ShouldCheckLoaderLock(FALSE) &&
2215 AuxUlibIsDLLSynchronizationHeld(&IsHeld) &&
2216 IsHeld)
2217 {
2218 if (checkKind == LoaderLockCheck::ForMDA)
2219 {
2220 MDA_TRIGGER_ASSISTANT(LoaderLock, ReportViolation(hInst));
2221 }
2222 else
2223 {
2224 return FALSE;
2225 }
2226 }
2227#endif // defined(FEATURE_COMINTEROP) && defined(MDA_SUPPORTED)
2228
2229 return TRUE;
2230}
2231
2232#include <optsmallperfcritical.h>
2233BOOL CanRunManagedCode(LoaderLockCheck::kind checkKind, HINSTANCE hInst /*= 0*/)
2234{
2235 CONTRACTL {
2236 NOTHROW;
2237 if (checkKind == LoaderLockCheck::ForMDA) { GC_TRIGGERS; } else { GC_NOTRIGGER; }; // because of the CustomerDebugProbe
2238 MODE_ANY;
2239 SO_TOLERANT;
2240 } CONTRACTL_END;
2241
2242 // Special-case the common success cases
2243 // (Try not to make any calls here so that we don't have to spill our incoming arg regs)
2244 if (!g_fForbidEnterEE
2245 && (g_pPreallocatedOutOfMemoryException != NULL)
2246 && !(g_fEEShutDown & ShutDown_Finalize2)
2247 && (((checkKind == LoaderLockCheck::ForMDA)
2248#ifdef MDA_SUPPORTED
2249 && (NULL == MDA_GET_ASSISTANT(LoaderLock))
2250#endif // MDA_SUPPORTED
2251 ) || (checkKind == LoaderLockCheck::None)))
2252 {
2253 return TRUE;
2254 }
2255
2256 // Then call a helper for everything else.
2257 return CanRunManagedCodeRare(checkKind, hInst);
2258}
2259#include <optdefault.h>
2260
2261
2262// ---------------------------------------------------------------------------
2263// %%Function: CoInitializeEE(DWORD fFlags)
2264//
2265// Parameters:
2266// fFlags - Initialization flags for the engine. See the
2267// COINITIEE enumerator for valid values.
2268//
2269// Returns:
2270// Nothing
2271//
2272// Description:
2273// Initializes the EE if it hasn't already been initialized. This function
2274// no longer maintains a ref count since the EE doesn't support being
2275// unloaded and re-loaded. It simply ensures the EE has been started.
2276// ---------------------------------------------------------------------------
2277HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags)
2278{
2279 CONTRACTL
2280 {
2281 NOTHROW;
2282 GC_TRIGGERS;
2283 MODE_PREEMPTIVE;
2284 SO_TOLERANT;
2285 }
2286 CONTRACTL_END;
2287
2288 HRESULT hr = S_OK;
2289 BEGIN_ENTRYPOINT_NOTHROW;
2290 hr = InitializeEE((COINITIEE)fFlags);
2291 END_ENTRYPOINT_NOTHROW;
2292
2293 return hr;
2294}
2295
2296// ---------------------------------------------------------------------------
2297// %%Function: CoUninitializeEE
2298//
2299// Parameters:
2300// BOOL fIsDllUnloading :: is it safe point for full cleanup
2301//
2302// Returns:
2303// Nothing
2304//
2305// Description:
2306// Must be called by client on shut down in order to free up the system.
2307// ---------------------------------------------------------------------------
2308void STDAPICALLTYPE CoUninitializeEE(BOOL fIsDllUnloading)
2309{
2310 LIMITED_METHOD_CONTRACT;
2311 //BEGIN_ENTRYPOINT_VOIDRET;
2312
2313 // This API is unfortunately publicly exported so we cannot get rid
2314 // of it. However since the EE doesn't currently support being unloaded
2315 // and re-loaded, it is useless to do any ref counting here or to pretend
2316 // to unload it. The proper way to shutdown the EE is to call CorExitProcess.
2317 //END_ENTRYPOINT_VOIDRET;
2318
2319}
2320
2321//*****************************************************************************
2322BOOL ExecuteDLL_ReturnOrThrow(HRESULT hr, BOOL fFromThunk)
2323{
2324 CONTRACTL {
2325 if (fFromThunk) THROWS; else NOTHROW;
2326 WRAPPER(GC_TRIGGERS);
2327 MODE_ANY;
2328 SO_TOLERANT;
2329 } CONTRACTL_END;
2330
2331 // If we have a failure result, and we're called from a thunk,
2332 // then we need to throw an exception to communicate the error.
2333 if (FAILED(hr) && fFromThunk)
2334 {
2335 COMPlusThrowHR(hr);
2336 }
2337 return SUCCEEDED(hr);
2338}
2339
2340//
2341// Initialize the Garbage Collector
2342//
2343
2344void InitializeGarbageCollector()
2345{
2346 CONTRACTL{
2347 THROWS;
2348 GC_TRIGGERS;
2349 MODE_ANY;
2350 } CONTRACTL_END;
2351
2352 HRESULT hr;
2353
2354 // Build the special Free Object used by the Generational GC
2355 _ASSERT(g_pFreeObjectMethodTable == NULL);
2356 g_pFreeObjectMethodTable = (MethodTable *) new BYTE[sizeof(MethodTable)];
2357 ZeroMemory(g_pFreeObjectMethodTable, sizeof(MethodTable));
2358
2359 // As the flags in the method table indicate there are no pointers
2360 // in the object, there is no gc descriptor, and thus no need to adjust
2361 // the pointer to skip the gc descriptor.
2362
2363 g_pFreeObjectMethodTable->SetBaseSize(ARRAYBASE_BASESIZE);
2364 g_pFreeObjectMethodTable->SetComponentSize(1);
2365
2366 hr = GCHeapUtilities::LoadAndInitialize();
2367 if (hr != S_OK)
2368 {
2369 ThrowHR(hr);
2370 }
2371
2372 // Apparently the Windows linker removes global variables if they are never
2373 // read from, which is a problem for g_gcDacGlobals since it's expected that
2374 // only the DAC will read from it. This forces the linker to include
2375 // g_gcDacGlobals.
2376 volatile void* _dummy = g_gcDacGlobals;
2377}
2378
2379/*****************************************************************************/
2380/* This is here only so that if we get an exception we stop before we catch it */
2381LONG DllMainFilter(PEXCEPTION_POINTERS p, PVOID pv)
2382{
2383 LIMITED_METHOD_CONTRACT;
2384 _ASSERTE(!"Exception happened in mscorwks!DllMain!");
2385 return EXCEPTION_EXECUTE_HANDLER;
2386}
2387
2388//*****************************************************************************
2389// This is the part of the old-style DllMain that initializes the
2390// stuff that the EE team works on. It's called from the real DllMain
2391// up in MSCOREE land. Separating the DllMain tasks is simply for
2392// convenience due to the dual build trees.
2393//*****************************************************************************
2394BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
2395 HINSTANCE hInst, // Instance handle of the loaded module.
2396 DWORD dwReason, // Reason for loading.
2397 LPVOID lpReserved) // Unused.
2398{
2399 STATIC_CONTRACT_NOTHROW;
2400 STATIC_CONTRACT_GC_TRIGGERS;
2401
2402 // this runs at the top of a thread, SO is not a concern here...
2403 STATIC_CONTRACT_SO_NOT_MAINLINE;
2404
2405
2406 // HRESULT hr;
2407 // BEGIN_EXTERNAL_ENTRYPOINT(&hr);
2408 // EE isn't spun up enough to use this macro
2409
2410 struct Param
2411 {
2412 HINSTANCE hInst;
2413 DWORD dwReason;
2414 LPVOID lpReserved;
2415 void **pTlsData;
2416 } param;
2417 param.hInst = hInst;
2418 param.dwReason = dwReason;
2419 param.lpReserved = lpReserved;
2420 param.pTlsData = NULL;
2421
2422 // Can't use PAL_TRY/EX_TRY here as they access the ClrDebugState which gets blown away as part of the
2423 // PROCESS_DETACH path. Must use special PAL_TRY_FOR_DLLMAIN, passing the reason were in the DllMain.
2424 PAL_TRY_FOR_DLLMAIN(Param *, pParam, &param, pParam->dwReason)
2425 {
2426
2427 switch (pParam->dwReason)
2428 {
2429 case DLL_PROCESS_ATTACH:
2430 {
2431 // We cache the SystemInfo for anyone to use throughout the
2432 // life of the DLL.
2433 GetSystemInfo(&g_SystemInfo);
2434
2435 // Remember module instance
2436 g_pMSCorEE = pParam->hInst;
2437
2438
2439 // Set callbacks so that LoadStringRC knows which language our
2440 // threads are in so that it can return the proper localized string.
2441 // TODO: This shouldn't rely on the LCID (id), but only the name
2442 SetResourceCultureCallbacks(GetThreadUICultureNames,
2443 GetThreadUICultureId);
2444
2445 InitEEPolicy();
2446
2447 break;
2448 }
2449
2450 case DLL_PROCESS_DETACH:
2451 {
2452 // lpReserved is NULL if we're here because someone called FreeLibrary
2453 // and non-null if we're here because the process is exiting.
2454 // Since nobody should ever be calling FreeLibrary on mscorwks.dll, lpReserved
2455 // should always be non NULL.
2456 _ASSERTE(pParam->lpReserved || !g_fEEStarted);
2457 g_fProcessDetach = TRUE;
2458
2459#if defined(ENABLE_CONTRACTS_IMPL) && defined(FEATURE_STACK_PROBE)
2460 // We are shutting down process. No need to check SO contract.
2461 // And it is impossible to enforce SO contract in global dtor, like ModIntPairList.
2462 g_EnableDefaultRWValidation = FALSE;
2463#endif
2464
2465 if (g_fEEStarted)
2466 {
2467 // GetThread() may be set to NULL for Win9x during shutdown.
2468 Thread *pThread = GetThread();
2469 if (GCHeapUtilities::IsGCInProgress() &&
2470 ( (pThread && (pThread != ThreadSuspend::GetSuspensionThread() ))
2471 || !g_fSuspendOnShutdown))
2472 {
2473 g_fEEShutDown |= ShutDown_Phase2;
2474 break;
2475 }
2476
2477 LOG((LF_STARTUP, INFO3, "EEShutDown invoked from EEDllMain"));
2478 EEShutDown(TRUE); // shut down EE if it was started up
2479 }
2480 else
2481 {
2482 CLRRemoveVectoredHandlers();
2483 }
2484 break;
2485 }
2486
2487 case DLL_THREAD_DETACH:
2488 {
2489 // Don't destroy threads here if we're in shutdown (shutdown will
2490 // clean up for us instead).
2491
2492 // Store the TLS data; we'll need it later and we might NULL the slot in DetachThread.
2493 // This would be problematic because we can't depend on the FLS still existing.
2494 pParam->pTlsData = CExecutionEngine::CheckThreadStateNoCreate(0
2495#ifdef _DEBUG
2496 // When we get here, OS has destroyed FLS, so FlsGetValue returns NULL now.
2497 // We have validation code in CExecutionEngine::CheckThreadStateNoCreate to ensure that
2498 // our TLS and FLS data are consistent, but since FLS has been destroyed, we need
2499 // to silent the check there. The extra arg for check build is for this purpose.
2500 , TRUE
2501#endif
2502 );
2503 Thread* thread = GetThread();
2504 if (thread)
2505 {
2506#ifdef FEATURE_COMINTEROP
2507 // reset the CoInitialize state
2508 // so we don't call CoUninitialize during thread detach
2509 thread->ResetCoInitialized();
2510#endif // FEATURE_COMINTEROP
2511 // For case where thread calls ExitThread directly, we need to reset the
2512 // frame pointer. Otherwise stackwalk would AV. We need to do it in cooperative mode.
2513 // We need to set m_GCOnTransitionsOK so this thread won't trigger GC when toggle GC mode
2514 if (thread->m_pFrame != FRAME_TOP)
2515 {
2516#ifdef _DEBUG
2517 thread->m_GCOnTransitionsOK = FALSE;
2518#endif
2519 GCX_COOP_NO_DTOR();
2520 thread->m_pFrame = FRAME_TOP;
2521 GCX_COOP_NO_DTOR_END();
2522 }
2523 thread->DetachThread(TRUE);
2524 }
2525 }
2526 }
2527
2528 }
2529 PAL_EXCEPT_FILTER(DllMainFilter)
2530 {
2531 }
2532 PAL_ENDTRY;
2533
2534 if (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH)
2535 {
2536 CExecutionEngine::ThreadDetaching(param.pTlsData);
2537 }
2538 return TRUE;
2539}
2540
2541#ifdef DEBUGGING_SUPPORTED
2542//
2543// InitializeDebugger initialized the Runtime-side COM+ Debugging Services
2544//
2545static void InitializeDebugger(void)
2546{
2547 CONTRACTL
2548 {
2549 THROWS;
2550 GC_TRIGGERS;
2551 MODE_ANY;
2552 }
2553 CONTRACTL_END;
2554
2555 // Ensure that if we throw, we'll call TerminateDebugger to cleanup.
2556 // This makes our Init more atomic by avoiding partially-init states.
2557 class EnsureCleanup {
2558 BOOL fNeedCleanup;
2559 public:
2560 EnsureCleanup()
2561 {
2562 fNeedCleanup = TRUE;
2563 }
2564
2565 void SuppressCleanup()
2566 {
2567 fNeedCleanup = FALSE;
2568 }
2569
2570 ~EnsureCleanup()
2571 {
2572 STATIC_CONTRACT_NOTHROW;
2573 STATIC_CONTRACT_GC_NOTRIGGER;
2574 STATIC_CONTRACT_MODE_ANY;
2575
2576 if (fNeedCleanup)
2577 {
2578 TerminateDebugger();
2579 }
2580 }
2581 } hCleanup;
2582
2583 HRESULT hr = S_OK;
2584
2585 LOG((LF_CORDB, LL_INFO10, "Initializing left-side debugging services.\n"));
2586
2587 FARPROC gi = (FARPROC) &CorDBGetInterface;
2588
2589 // Init the interface the EE provides to the debugger,
2590 // ask the debugger for its interface, and if all goes
2591 // well call Startup on the debugger.
2592 EEDbgInterfaceImpl::Init();
2593 _ASSERTE(g_pEEDbgInterfaceImpl != NULL); // throws on OOM
2594
2595 // This allocates the Debugger object.
2596 typedef HRESULT __cdecl CORDBGETINTERFACE(DebugInterface**);
2597 hr = ((CORDBGETINTERFACE*)gi)(&g_pDebugInterface);
2598 IfFailThrow(hr);
2599
2600 g_pDebugInterface->SetEEInterface(g_pEEDbgInterfaceImpl);
2601
2602 {
2603 hr = g_pDebugInterface->Startup(); // throw on error
2604 _ASSERTE(SUCCEEDED(hr));
2605
2606 //
2607 // If the debug pack is not installed, Startup will return S_FALSE
2608 // and we should cleanup and proceed without debugging support.
2609 //
2610 if (hr != S_OK)
2611 {
2612 return;
2613 }
2614 }
2615
2616
2617 LOG((LF_CORDB, LL_INFO10, "Left-side debugging services setup.\n"));
2618
2619 hCleanup.SuppressCleanup();
2620
2621 return;
2622}
2623
2624
2625//
2626// TerminateDebugger shuts down the Runtime-side COM+ Debugging Services
2627// InitializeDebugger will call this if it fails.
2628// This may be called even if the debugger is partially initialized.
2629// This can be called multiple times.
2630//
2631static void TerminateDebugger(void)
2632{
2633 CONTRACTL
2634 {
2635 NOTHROW;
2636 GC_NOTRIGGER;
2637 MODE_ANY;
2638 }
2639 CONTRACTL_END;
2640
2641 LOG((LF_CORDB, LL_INFO10, "Shutting down left-side debugger services.\n"));
2642
2643 // If initialized failed really early, then we didn't even get the Debugger object.
2644 if (g_pDebugInterface != NULL)
2645 {
2646 // Notify the out-of-process debugger that shutdown of the in-process debugging support has begun. This is only
2647 // really used in interop debugging scenarios.
2648 g_pDebugInterface->ShutdownBegun();
2649
2650 // This will kill the helper thread, delete the Debugger object, and free all resources.
2651 g_pDebugInterface->StopDebugger();
2652 }
2653
2654 g_CORDebuggerControlFlags = DBCF_NORMAL_OPERATION;
2655
2656}
2657
2658#endif // DEBUGGING_SUPPORTED
2659
2660#ifndef LOCALE_SPARENT
2661#define LOCALE_SPARENT 0x0000006d
2662#endif
2663
2664// ---------------------------------------------------------------------------
2665// Impl for UtilLoadStringRC Callback: In VM, we let the thread decide culture
2666// copy culture name into szBuffer and return length
2667// ---------------------------------------------------------------------------
2668extern BOOL g_fFatalErrorOccuredOnGCThread;
2669static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames)
2670{
2671 CONTRACTL
2672 {
2673 NOTHROW;
2674 GC_NOTRIGGER;
2675 MODE_ANY;
2676 PRECONDITION(CheckPointer(pCultureNames));
2677 SO_INTOLERANT;
2678 }
2679 CONTRACTL_END;
2680
2681 HRESULT hr = S_OK;
2682
2683 EX_TRY
2684 {
2685 InlineSString<LOCALE_NAME_MAX_LENGTH> sCulture;
2686 InlineSString<LOCALE_NAME_MAX_LENGTH> sParentCulture;
2687
2688#if 0 // Enable and test if/once the unmanaged runtime is localized
2689 Thread * pThread = GetThread();
2690
2691 // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
2692 // indefinately. We want to ensure a clean exit so rather than take the risk of hang we take a risk of the error resource not
2693 // getting localized with a non-default thread-specific culture.
2694 // A canonical stack trace that gets here is a fatal error in the GC that comes through:
2695 // coreclr.dll!GetThreadUICultureNames
2696 // coreclr.dll!CCompRC::LoadLibraryHelper
2697 // coreclr.dll!CCompRC::LoadLibrary
2698 // coreclr.dll!CCompRC::GetLibrary
2699 // coreclr.dll!CCompRC::LoadString
2700 // coreclr.dll!CCompRC::LoadString
2701 // coreclr.dll!SString::LoadResourceAndReturnHR
2702 // coreclr.dll!SString::LoadResourceAndReturnHR
2703 // coreclr.dll!SString::LoadResource
2704 // coreclr.dll!EventReporter::EventReporter
2705 // coreclr.dll!EEPolicy::LogFatalError
2706 // coreclr.dll!EEPolicy::HandleFatalError
2707 if (pThread != NULL && !g_fFatalErrorOccuredOnGCThread) {
2708
2709 // Switch to cooperative mode, since we'll be looking at managed objects
2710 // and we don't want them moving on us.
2711 GCX_COOP();
2712
2713 CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
2714
2715 if (pCurrentCulture != NULL)
2716 {
2717 STRINGREF cultureName = pCurrentCulture->GetName();
2718
2719 if (cultureName != NULL)
2720 {
2721 sCulture.Set(cultureName->GetBuffer(),cultureName->GetStringLength());
2722 }
2723
2724 CULTUREINFOBASEREF pParentCulture = pCurrentCulture->GetParent();
2725
2726 if (pParentCulture != NULL)
2727 {
2728 STRINGREF parentCultureName = pParentCulture->GetName();
2729
2730 if (parentCultureName != NULL)
2731 {
2732 sParentCulture.Set(parentCultureName->GetBuffer(),parentCultureName->GetStringLength());
2733 }
2734
2735 }
2736 }
2737 }
2738#endif
2739
2740 // If the lazily-initialized cultureinfo structures aren't initialized yet, we'll
2741 // need to do the lookup the hard way.
2742 if (sCulture.IsEmpty() || sParentCulture.IsEmpty())
2743 {
2744 LocaleIDValue id ;
2745 int tmp; tmp = GetThreadUICultureId(&id); // TODO: We should use the name instead
2746 _ASSERTE(tmp!=0 && id != UICULTUREID_DONTCARE);
2747 SIZE_T cchParentCultureName=LOCALE_NAME_MAX_LENGTH;
2748#ifdef FEATURE_USE_LCID
2749 SIZE_T cchCultureName=LOCALE_NAME_MAX_LENGTH;
2750 if (!::LCIDToLocaleName(id, sCulture.OpenUnicodeBuffer(static_cast<COUNT_T>(cchCultureName)), static_cast<int>(cchCultureName), 0))
2751 {
2752 hr = HRESULT_FROM_GetLastError();
2753 }
2754 sCulture.CloseBuffer();
2755#else
2756 sCulture.Set(id);
2757#endif
2758
2759#ifndef FEATURE_PAL
2760 if (!::GetLocaleInfoEx((LPCWSTR)sCulture, LOCALE_SPARENT, sParentCulture.OpenUnicodeBuffer(static_cast<COUNT_T>(cchParentCultureName)),static_cast<int>(cchParentCultureName)))
2761 {
2762 hr = HRESULT_FROM_GetLastError();
2763 }
2764 sParentCulture.CloseBuffer();
2765#else // !FEATURE_PAL
2766 sParentCulture = sCulture;
2767#endif // !FEATURE_PAL
2768 }
2769 // (LPCWSTR) to restrict the size to null terminated size
2770 pCultureNames->AppendIfNotThere((LPCWSTR)sCulture);
2771 // Disabling for Dev10 for consistency with managed resource lookup (see AppCompat bug notes in ResourceFallbackManager.cs)
2772 // Also, this is in the wrong order - put after the parent culture chain.
2773 //AddThreadPreferredUILanguages(pCultureNames);
2774 pCultureNames->AppendIfNotThere((LPCWSTR)sParentCulture);
2775 pCultureNames->Append(SString::Empty());
2776 }
2777 EX_CATCH
2778 {
2779 hr=E_OUTOFMEMORY;
2780 }
2781 EX_END_CATCH(SwallowAllExceptions);
2782
2783 return hr;
2784}
2785
2786// The exit code for the process is communicated in one of two ways. If the
2787// entrypoint returns an 'int' we take that. Otherwise we take a latched
2788// process exit code. This can be modified by the app via System.SetExitCode().
2789static INT32 LatchedExitCode;
2790
2791void SetLatchedExitCode (INT32 code)
2792{
2793 CONTRACTL
2794 {
2795 NOTHROW;
2796 GC_NOTRIGGER;
2797 SO_TOLERANT;
2798 MODE_ANY;
2799 }
2800 CONTRACTL_END;
2801
2802 STRESS_LOG1(LF_SYNC, LL_INFO10, "SetLatchedExitCode = %d\n", code);
2803 LatchedExitCode = code;
2804}
2805
2806INT32 GetLatchedExitCode (void)
2807{
2808 LIMITED_METHOD_CONTRACT;
2809 return LatchedExitCode;
2810}
2811
2812
2813// ---------------------------------------------------------------------------
2814// Impl for UtilLoadStringRC Callback: In VM, we let the thread decide culture
2815// Return an int uniquely describing which language this thread is using for ui.
2816// ---------------------------------------------------------------------------
2817// TODO: Callers should use names, not LCIDs
2818#ifdef FEATURE_USE_LCID
2819static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
2820{
2821 CONTRACTL{
2822 NOTHROW;
2823 GC_NOTRIGGER;
2824 MODE_ANY;
2825 SO_INTOLERANT;;
2826 } CONTRACTL_END;
2827
2828
2829
2830 int Result = UICULTUREID_DONTCARE;
2831
2832 Thread * pThread = GetThread();
2833
2834#if 0 // Enable and test if/once the unmanaged runtime is localized
2835 // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
2836 // indefinately. We want to ensure a clean exit so rather than take the risk of hang we take a risk of the error resource not
2837 // getting localized with a non-default thread-specific culture.
2838 // A canonical stack trace that gets here is a fatal error in the GC that comes through:
2839 // coreclr.dll!GetThreadUICultureNames
2840 // coreclr.dll!CCompRC::LoadLibraryHelper
2841 // coreclr.dll!CCompRC::LoadLibrary
2842 // coreclr.dll!CCompRC::GetLibrary
2843 // coreclr.dll!CCompRC::LoadString
2844 // coreclr.dll!CCompRC::LoadString
2845 // coreclr.dll!SString::LoadResourceAndReturnHR
2846 // coreclr.dll!SString::LoadResourceAndReturnHR
2847 // coreclr.dll!SString::LoadResource
2848 // coreclr.dll!EventReporter::EventReporter
2849 // coreclr.dll!EEPolicy::LogFatalError
2850 // coreclr.dll!EEPolicy::HandleFatalError
2851 if (pThread != NULL && !g_fFatalErrorOccuredOnGCThread)
2852 {
2853 // Switch to cooperative mode, since we'll be looking at managed objects
2854 // and we don't want them moving on us.
2855 GCX_COOP();
2856
2857 CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
2858
2859 if (pCurrentCulture != NULL)
2860 {
2861 STRINGREF cultureName = pCurrentCulture->GetName();
2862 _ASSERT(cultureName != NULL);
2863
2864 if ((Result = ::LocaleNameToLCID(cultureName->GetBuffer(), 0)) == 0)
2865 Result = (int)UICULTUREID_DONTCARE;
2866 }
2867 }
2868#endif
2869
2870 if (Result == (int)UICULTUREID_DONTCARE)
2871 {
2872 // This thread isn't set up to use a non-default culture. Let's grab the default
2873 // one and return that.
2874
2875 Result = COMNlsInfo::CallGetUserDefaultUILanguage();
2876
2877 if (Result == 0 || Result == (int)UICULTUREID_DONTCARE)
2878 Result = GetUserDefaultLangID();
2879
2880 _ASSERTE(Result != 0);
2881 if (Result == 0)
2882 {
2883 Result = (int)UICULTUREID_DONTCARE;
2884 }
2885
2886 }
2887 *pLocale=Result;
2888 return Result;
2889}
2890#else
2891// TODO: Callers should use names, not LCIDs
2892static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
2893{
2894 CONTRACTL{
2895 NOTHROW;
2896 GC_NOTRIGGER;
2897 MODE_ANY;
2898 SO_INTOLERANT;;
2899 } CONTRACTL_END;
2900
2901 _ASSERTE(sizeof(LocaleIDValue)/sizeof(WCHAR) >= LOCALE_NAME_MAX_LENGTH);
2902
2903 int Result = 0;
2904
2905 Thread * pThread = GetThread();
2906
2907#if 0 // Enable and test if/once the unmanaged runtime is localized
2908 // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
2909 // indefinately. We want to ensure a clean exit so rather than take the risk of hang we take a risk of the error resource not
2910 // getting localized with a non-default thread-specific culture.
2911 // A canonical stack trace that gets here is a fatal error in the GC that comes through:
2912 // coreclr.dll!GetThreadUICultureNames
2913 // coreclr.dll!CCompRC::LoadLibraryHelper
2914 // coreclr.dll!CCompRC::LoadLibrary
2915 // coreclr.dll!CCompRC::GetLibrary
2916 // coreclr.dll!CCompRC::LoadString
2917 // coreclr.dll!CCompRC::LoadString
2918 // coreclr.dll!SString::LoadResourceAndReturnHR
2919 // coreclr.dll!SString::LoadResourceAndReturnHR
2920 // coreclr.dll!SString::LoadResource
2921 // coreclr.dll!EventReporter::EventReporter
2922 // coreclr.dll!EEPolicy::LogFatalError
2923 // coreclr.dll!EEPolicy::HandleFatalError
2924 if (pThread != NULL && !g_fFatalErrorOccuredOnGCThread)
2925 {
2926
2927 // Switch to cooperative mode, since we'll be looking at managed objects
2928 // and we don't want them moving on us.
2929 GCX_COOP();
2930
2931 CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
2932
2933 if (pCurrentCulture != NULL)
2934 {
2935 STRINGREF currentCultureName = pCurrentCulture->GetName();
2936
2937 if (currentCultureName != NULL)
2938 {
2939 int cchCurrentCultureNameResult = currentCultureName->GetStringLength();
2940 if (cchCurrentCultureNameResult < LOCALE_NAME_MAX_LENGTH)
2941 {
2942 memcpy(*pLocale, currentCultureName->GetBuffer(), cchCurrentCultureNameResult*sizeof(WCHAR));
2943 (*pLocale)[cchCurrentCultureNameResult]='\0';
2944 Result=cchCurrentCultureNameResult;
2945 }
2946 }
2947 }
2948 }
2949#endif
2950 if (Result == 0)
2951 {
2952#ifndef FEATURE_PAL
2953 // This thread isn't set up to use a non-default culture. Let's grab the default
2954 // one and return that.
2955
2956 Result = ::GetUserDefaultLocaleName(*pLocale, LOCALE_NAME_MAX_LENGTH);
2957
2958 _ASSERTE(Result != 0);
2959#else // !FEATURE_PAL
2960 static const WCHAR enUS[] = W("en-US");
2961 memcpy(*pLocale, enUS, sizeof(enUS));
2962 Result = sizeof(enUS);
2963#endif // !FEATURE_PAL
2964 }
2965 return Result;
2966}
2967
2968#endif // FEATURE_USE_LCID
2969
2970
2971#ifdef ENABLE_CONTRACTS_IMPL
2972
2973// Returns TRUE if any contract violation suppressions are in effect.
2974BOOL AreAnyViolationBitsOn()
2975{
2976 CONTRACTL
2977 {
2978 NOTHROW;
2979 GC_NOTRIGGER;
2980 SO_TOLERANT;
2981 MODE_ANY;
2982 }
2983 CONTRACTL_END;
2984 UINT_PTR violationMask = GetClrDebugState()->ViolationMask();
2985 violationMask &= ~((UINT_PTR)CanFreeMe); //CanFreeMe is a borrowed bit and has nothing to do with violations
2986 if (violationMask & ((UINT_PTR)BadDebugState))
2987 {
2988 return FALSE;
2989 }
2990
2991 return violationMask != 0;
2992}
2993
2994
2995// This function is intentionally invoked inside a big CONTRACT_VIOLATION that turns on every violation
2996// bit on the map. The dynamic contract at the beginning *should* turn off those violation bits.
2997// The body of this function tests to see that it did exactly that. This is to prevent the VSWhidbey B#564831 fiasco
2998// from ever recurring.
2999void ContractRegressionCheckInner()
3000{
3001 // DO NOT TURN THIS CONTRACT INTO A STATIC CONTRACT!!! The very purpose of this function
3002 // is to ensure that dynamic contracts disable outstanding contract violation bits.
3003 // This code only runs once at process startup so it's not going pooch the checked build perf.
3004 CONTRACTL
3005 {
3006 NOTHROW;
3007 GC_NOTRIGGER;
3008 FORBID_FAULT;
3009 LOADS_TYPE(CLASS_LOAD_BEGIN);
3010 CANNOT_TAKE_LOCK;
3011 }
3012 CONTRACTL_END
3013
3014 if (AreAnyViolationBitsOn())
3015 {
3016 // If we got here, the contract above FAILED to turn off one or more violation bits. This is a
3017 // huge diagnostics hole and must be fixed immediately.
3018 _ASSERTE(!("WARNING: mscorwks has detected an internal error that may indicate contracts are"
3019 " being silently disabled across the runtime. Do not ignore this assert!"));
3020 }
3021}
3022
3023// This function executes once per process to ensure our CONTRACT_VIOLATION() mechanism
3024// is properly scope-limited by nested contracts.
3025void ContractRegressionCheck()
3026{
3027 CONTRACTL
3028 {
3029 NOTHROW;
3030 GC_NOTRIGGER;
3031 MODE_ANY;
3032 }
3033 CONTRACTL_END;
3034
3035 {
3036 // DO NOT "FIX" THIS CONTRACT_VIOLATION!!!
3037 // The existence of this CONTRACT_VIOLATION is not a bug. This is debug-only code specifically written
3038 // to test the CONTRACT_VIOLATION mechanism itself. This is needed to prevent a regression of
3039 // B#564831 (which left a huge swath of contracts silently disabled for over six months)
3040 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation
3041 | GCViolation
3042 | FaultViolation
3043 | LoadsTypeViolation
3044 | TakesLockViolation
3045 , ReasonContractInfrastructure
3046 );
3047 {
3048 FAULT_NOT_FATAL();
3049 ContractRegressionCheckInner();
3050 }
3051 }
3052
3053 if (AreAnyViolationBitsOn())
3054 {
3055 // If we got here, the CONTRACT_VIOLATION() holder left one or more violation bits turned ON
3056 // after we left its scope. This is a huge diagnostic hole and must be fixed immediately.
3057 _ASSERTE(!("WARNING: mscorwks has detected an internal error that may indicate contracts are"
3058 " being silently disabled across the runtime. Do not ignore this assert!"));
3059 }
3060
3061}
3062
3063#endif // ENABLE_CONTRACTS_IMPL
3064
3065#endif // CROSSGEN_COMPILE
3066