`ADTakeSnapShot` | Superseded by test hooks | `DWORD` | `INTERNAL` | `0` |
`EnableFullDebug` | Heavy-weight checking for AD boundary violations (AD leaks) | `DWORD` | `INTERNAL` | |
-#### ARM Configuration Knobs
-
-Name | Description | Type | Class | Default Value | Flags
------|-------------|------|-------|---------------|-------
-`ARMEnabled` | AppDomain Resource Monitoring. Set to 1 to enable it | `DWORD` | `UNSUPPORTED` | `(DWORD)0` |
-
#### Assembly Loader Configuration Knobs
Name | Description | Type | Class | Default Value | Flags
MethodDesc *pMD = pCF->GetFunction();
gcctx->sc->pMD = pMD;
- gcctx->sc->pCurrentDomain = pCF->GetAppDomain();
PREGDISPLAY pRD = pCF->GetRegisterSet();
dsc->sp = (TADDR)GetRegdisplaySP(pRD);;
{
DD_ENTER_MAY_THROW;
- OBJECTHANDLE handle = (OBJECTHANDLE) vmHandle.GetDacPtr();
- return HndGetHandleADIndex(handle).m_dwIndex;
+ return DefaultADID;
}
// Get the target address from a VMPTR_OBJECTHANDLE, i.e., the handle address
DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
if (data != NULL)
{
- data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
+ data->vmDomain.SetDacTargetPtr(AppDomain::GetCurrentDomain().GetAddr());
if (obj)
data->pObject = obj | 1;
else if (loc.targetPtr)
DacGcReference *data = dsc->pWalker->GetNextObject<DacGcReference>(dsc);
if (data != NULL)
{
- data->vmDomain.SetDacTargetPtr(dac_cast<PTR_AppDomain>(dsc->pCurrentDomain).GetAddr());
+ data->vmDomain.SetDacTargetPtr(AppDomain::GetCurrentDomain().GetAddr());
data->objHnd.SetDacTargetPtr(obj);
data->dwType = CorReferenceStack;
data->i64ExtraData = 0;
OBJECTREF HndFetchHandle(OBJECTHANDLE handle);
GC_DAC_VISIBLE
-struct ADIndex HndGetHandleADIndex(OBJECTHANDLE handle);
-
-GC_DAC_VISIBLE
uintptr_t HndGetHandleExtraInfo(OBJECTHANDLE handle);
#endif // DACCESS_COMPILE
# Local GC meta-issue: https://github.com/dotnet/coreclr/issues/11518
-# https://github.com/dotnet/coreclr/issues/11517
-remove_definitions(-DFEATURE_APPDOMAIN_RESOURCE_MONITORING)
-
# https://github.com/dotnet/coreclr/issues/11516
remove_definitions(-DSTRESS_HEAP)
#define FireEtwGCMarkHandles(HeapNum, ClrInstanceID) 0
#define FireEtwGCMarkOlderGenerationRoots(HeapNum, ClrInstanceID) 0
#define FireEtwFinalizeObject(TypeID, ObjectID, ClrInstanceID) 0
-#define FireEtwSetGCHandle(HandleID, ObjectID, Kind, Generation, AppDomainID, ClrInstanceID) 0
+#define FireEtwSetGCHandle(HandleID, ObjectID, Kind, Generation, ClrInstanceID) 0
#define FireEtwDestroyGCHandle(HandleID, ClrInstanceID) 0
#define FireEtwGCSampledObjectAllocationLow(Address, TypeID, ObjectCountForTypeSample, TotalSizeForTypeSample, ClrInstanceID) 0
#define FireEtwPinObjectAtGCTime(HandleID, ObjectID, ObjectSize, TypeName, ClrInstanceID) 0
#define FireEtwFailFast(FailFastUserMessage, FailedEIP, OSExitCode, ClrExitCode, ClrInstanceID) 0
#define FireEtwPrvFinalizeObject(TypeID, ObjectID, ClrInstanceID, TypeName) 0
#define FireEtwCCWRefCountChange(HandleID, ObjectID, COMInterfacePointer, NewRefCount, AppDomainID, ClassName, NameSpace, Operation, ClrInstanceID) 0
-#define FireEtwPrvSetGCHandle(HandleID, ObjectID, Kind, Generation, AppDomainID, ClrInstanceID) 0
+#define FireEtwPrvSetGCHandle(HandleID, ObjectID, Kind, Generation, ClrInstanceID) 0
#define FireEtwPrvDestroyGCHandle(HandleID, ClrInstanceID) 0
#define FireEtwFusionMessageEvent(ClrInstanceID, Prepend, Message) 0
#define FireEtwFusionErrorCodeEvent(ClrInstanceID, Category, ErrorCode) 0
return val == (uint64_t)(uint8_t)val;
}
-// -----------------------------------------------------------------------------------------------------------
-//
-// AppDomain emulation. The we don't have these in Redhawk so instead we emulate the bare minimum of the API
-// touched by the GC/HandleTable and pretend we have precisely one (default) appdomain.
-//
-
-#define RH_DEFAULT_DOMAIN_ID 1
-
-struct ADIndex
-{
- DWORD m_dwIndex;
-
- ADIndex () : m_dwIndex(RH_DEFAULT_DOMAIN_ID) {}
- explicit ADIndex (DWORD id) : m_dwIndex(id) {}
- BOOL operator==(const ADIndex& ad) const { return m_dwIndex == ad.m_dwIndex; }
- BOOL operator!=(const ADIndex& ad) const { return m_dwIndex != ad.m_dwIndex; }
-};
-
#endif // __GCENV_BASE_INCLUDED__
static void EnableFinalization(bool foundFinalizers);
static void HandleFatalError(unsigned int exitCode);
- static bool ShouldFinalizeObjectForUnload(void* pDomain, Object* obj);
static bool EagerFinalized(Object* obj);
static MethodTable* GetFreeObjectMethodTable();
static bool GetBooleanConfigValue(const char* key, bool* value);
static void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*));
static IGCToCLREventSink* EventSink();
- static uint32_t GetDefaultDomainIndex();
- static void *GetAppDomainAtIndex(uint32_t appDomainIndex);
- static bool AppDomainCanAccessHandleTable(uint32_t appDomainID);
- static uint32_t GetIndexOfAppDomainBeingUnloaded();
static uint32_t GetTotalNumSizedRefHandles();
- static bool AppDomainIsRudeUnload(void *appDomain);
static bool AnalyzeSurvivorsRequested(int condemnedGeneration);
static void AnalyzeSurvivorsFinished(int condemnedGeneration);
acontext->alloc_bytes += added_bytes;
total_alloc_bytes += added_bytes;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableAppDomainMonitoring)
- {
- GCToEEInterface::RecordAllocatedBytesForHeap(limit_size, heap_number);
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
-
uint8_t* saved_used = 0;
if (seg)
{
make_unused_array (alloc_start, size);
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableAppDomainMonitoring)
- {
- GCToEEInterface::RecordAllocatedBytesForHeap(size, heap_number);
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
size_t size_of_array_base = sizeof(ArrayBase);
bgc_alloc_lock->loh_alloc_done_with_index (lock_index);
pSC->thread_number = hn;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- pSC->pCurrentDomain = 0;
-#endif
-
BOOL relocate_p = (fn == &GCHeap::Relocate);
dprintf (3, ("Scanning background mark list"));
// scan for deleted entries in the syncblk cache
GCScan::GcWeakPtrScanBySingleThread (condemned_gen_number, max_generation, &sc);
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableAppDomainMonitoring)
- {
- size_t promoted_all_heaps = 0;
-#ifdef MULTIPLE_HEAPS
- for (int i = 0; i < n_heaps; i++)
- {
- promoted_all_heaps += promoted_bytes (i);
- }
-#else
- promoted_all_heaps = promoted_bytes (heap_number);
-#endif //MULTIPLE_HEAPS
- GCToEEInterface::RecordTotalSurvivedBytes(promoted_all_heaps);
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifdef MULTIPLE_HEAPS
#ifdef MARK_LIST
hp->pin_object (o, (uint8_t**) ppObject, hp->gc_low, hp->gc_high);
#endif //STRESS_PINNING
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- size_t promoted_size_begin = hp->promoted_bytes (thread);
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
if ((o >= hp->gc_low) && (o < hp->gc_high))
{
hpt->mark_object_simple (&o THREAD_NUMBER_ARG);
}
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- size_t promoted_size_end = hp->promoted_bytes (thread);
- if (g_fEnableAppDomainMonitoring)
- {
- if (sc->pCurrentDomain)
- {
- GCToEEInterface::RecordSurvivedBytesForHeap((promoted_size_end - promoted_size_begin), thread, sc->pCurrentDomain);
- }
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
STRESS_LOG_ROOT_PROMOTE(ppObject, o, o ? header(o)->GetMethodTable() : NULL);
}
#endif //BACKGROUND_GC
}
}
-
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableAppDomainMonitoring)
- {
- GCToEEInterface::ResetTotalSurvivedBytes();
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
}
#ifdef GC_CONFIG_DRIVEN
}
GCHeap::UpdatePostGCCounters();
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- //if (g_fEnableARM)
- //{
- // SystemDomain::GetADSurvivedBytes();
- //}
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifdef STRESS_LOG
STRESS_LOG_GC_END(VolatileLoad(&settings.gc_index),
(uint32_t)settings.condemned_generation,
#endif //MULTIPLE_HEAPS
}
-bool GCHeap::FinalizeAppDomain(void *pDomain, bool fRunFinalizers)
-{
-#ifdef MULTIPLE_HEAPS
- bool foundp = false;
- for (int hn = 0; hn < gc_heap::n_heaps; hn++)
- {
- gc_heap* hp = gc_heap::g_heaps [hn];
- if (hp->finalize_queue->FinalizeAppDomain (pDomain, fRunFinalizers))
- foundp = true;
- }
- return foundp;
-
-#else //MULTIPLE_HEAPS
- return pGenGCHeap->finalize_queue->FinalizeAppDomain (pDomain, fRunFinalizers);
-#endif //MULTIPLE_HEAPS
-}
-
bool GCHeap::ShouldRestartFinalizerWatchDog()
{
// This condition was historically used as part of the condition to detect finalizer thread timeouts
(g_fFinalizerRunOnShutDown ? m_Array : SegQueue(FinalizerListSeg));
}
-BOOL
-CFinalize::FinalizeSegForAppDomain (void *pDomain,
- BOOL fRunFinalizers,
- unsigned int Seg)
-{
- BOOL finalizedFound = FALSE;
- Object** endIndex = SegQueue (Seg);
- for (Object** i = SegQueueLimit (Seg)-1; i >= endIndex ;i--)
- {
- CObjectHeader* obj = (CObjectHeader*)*i;
-
- // Objects are put into the finalization queue before they are complete (ie their methodtable
- // may be null) so we must check that the object we found has a method table before checking
- // if it has the index we are looking for. If the methodtable is null, it can't be from the
- // unloading domain, so skip it.
- if (method_table(obj) == NULL)
- {
- continue;
- }
-
- // does the EE actually want us to finalize this object?
- if (!GCToEEInterface::ShouldFinalizeObjectForUnload(pDomain, obj))
- {
- continue;
- }
-
- if (!fRunFinalizers || (obj->GetHeader()->GetBits()) & BIT_SBLK_FINALIZER_RUN)
- {
- //remove the object because we don't want to
- //run the finalizer
- MoveItem (i, Seg, FreeList);
- //Reset the bit so it will be put back on the queue
- //if resurrected and re-registered.
- obj->GetHeader()->ClrBit (BIT_SBLK_FINALIZER_RUN);
- }
- else
- {
- if (method_table(obj)->HasCriticalFinalizer())
- {
- finalizedFound = TRUE;
- MoveItem (i, Seg, CriticalFinalizerListSeg);
- }
- else
- {
- if (GCToEEInterface::AppDomainIsRudeUnload(pDomain))
- {
- MoveItem (i, Seg, FreeList);
- }
- else
- {
- finalizedFound = TRUE;
- MoveItem (i, Seg, FinalizerListSeg);
- }
- }
- }
- }
-
- return finalizedFound;
-}
-
-bool
-CFinalize::FinalizeAppDomain (void *pDomain, bool fRunFinalizers)
-{
- bool finalizedFound = false;
-
- unsigned int startSeg = gen_segment (max_generation);
-
- EnterFinalizeLock();
-
- for (unsigned int Seg = startSeg; Seg <= gen_segment (0); Seg++)
- {
- if (FinalizeSegForAppDomain (pDomain, fRunFinalizers, Seg))
- {
- finalizedFound = true;
- }
- }
-
- LeaveFinalizeLock();
-
- return finalizedFound;
-}
-
void
CFinalize::MoveItem (Object** fromIndex,
unsigned int fromSeg,
Object* o = *po;
//dprintf (3, ("scan freacheable %Ix", (size_t)o));
dprintf (3, ("scan f %Ix", (size_t)o));
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableAppDomainMonitoring)
- {
- pSC->pCurrentDomain = GCToEEInterface::GetAppDomainForObject(o);
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
(*fn)(po, pSC, 0);
}
g_theGCToCLR->HandleFatalError(exitCode);
}
-inline bool GCToEEInterface::ShouldFinalizeObjectForUnload(void* pDomain, Object* obj)
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->ShouldFinalizeObjectForUnload(pDomain, obj);
-}
-
inline bool GCToEEInterface::EagerFinalized(Object* obj)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->EventSink();
}
-inline uint32_t GCToEEInterface::GetDefaultDomainIndex()
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->GetDefaultDomainIndex();
-}
-
-inline void *GCToEEInterface::GetAppDomainAtIndex(uint32_t appDomainIndex)
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->GetAppDomainAtIndex(appDomainIndex);
-}
-
-inline bool GCToEEInterface::AppDomainCanAccessHandleTable(uint32_t appDomainID)
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->AppDomainCanAccessHandleTable(appDomainID);
-}
-
-inline uint32_t GCToEEInterface::GetIndexOfAppDomainBeingUnloaded()
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->GetIndexOfAppDomainBeingUnloaded();
-}
-
inline uint32_t GCToEEInterface::GetTotalNumSizedRefHandles()
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->GetTotalNumSizedRefHandles();
}
-inline bool GCToEEInterface::AppDomainIsRudeUnload(void *appDomain)
-{
- assert(g_theGCToCLR != nullptr);
- return g_theGCToCLR->AppDomainIsRudeUnload(appDomain);
-}
-
inline bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration)
{
assert(g_theGCToCLR != nullptr);
return handle;
}
-void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE))
-{
- // assumption - the IGCHandleStore is an instance of GCHandleStore
- GCHandleStore* other = static_cast<GCHandleStore*>(pTarget);
- ::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket, clearIfComplete, setHandle);
-}
-
-bool GCHandleStore::EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context)
-{
- return !!::Ref_HandleAsyncPinHandles(callback, context);
-}
-
GCHandleStore::~GCHandleStore()
{
::Ref_DestroyHandleTableBucket(&_underlyingBucket);
return g_gcGlobalHandleStore;
}
-IGCHandleStore* GCHandleManager::CreateHandleStore(void* context)
+IGCHandleStore* GCHandleManager::CreateHandleStore()
{
#ifndef FEATURE_REDHAWK
GCHandleStore* store = new (nothrow) GCHandleStore();
return nullptr;
}
- bool success = ::Ref_InitializeHandleTableBucket(&store->_underlyingBucket, context);
+ bool success = ::Ref_InitializeHandleTableBucket(&store->_underlyingBucket);
if (!success)
{
delete store;
delete store;
}
-void* GCHandleManager::GetHandleContext(OBJECTHANDLE handle)
-{
- return (void*)((uintptr_t)::HndGetHandleTableADIndex(::HndGetHandleTable(handle)).m_dwIndex);
-}
-
OBJECTHANDLE GCHandleManager::CreateGlobalHandleOfType(Object* object, HandleType type)
{
return ::HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], type, ObjectToOBJECTREF(object));
virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary);
- virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfCompleteCallback)(Object* object), void (*setHandle)(Object* object, OBJECTHANDLE handle));
-
- virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context);
-
virtual ~GCHandleStore();
HandleTableBucket _underlyingBucket;
virtual void Shutdown();
- virtual void* GetHandleContext(OBJECTHANDLE handle);
-
virtual IGCHandleStore* GetGlobalHandleStore();
- virtual IGCHandleStore* CreateHandleStore(void* context);
+ virtual IGCHandleStore* CreateHandleStore();
virtual void DestroyHandleStore(IGCHandleStore* store);
PER_HEAP_ISOLATED size_t GetFinalizablePromotedCount();
void SetFinalizeQueueForShutdown(bool fHasLock);
- bool FinalizeAppDomain(void *pDomain, bool fRunFinalizers);
bool ShouldRestartFinalizerWatchDog();
void DiagWalkObject (Object* obj, walk_fn fn, void* context);
class dac_handle_table {
public:
- // On the handle table side, this is an ADIndex. They should still have
- // the same layout.
- //
// We do try to keep everything that the DAC knows about as close to the
// start of the struct as possible to avoid having padding members. However,
// HandleTable has rgTypeFlags at offset 0 for performance reasons and
// we don't want to disrupt that.
uint32_t padding[HANDLE_MAX_INTERNAL_TYPES];
- DWORD uADIndex;
};
class dac_handle_table_bucket {
virtual
void FireGCFullNotify_V1(uint32_t genNumber, uint32_t isAlloc) = 0;
virtual
- void FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID) = 0;
+ void FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation) = 0;
virtual
- void FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID) = 0;
+ void FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation) = 0;
virtual
void FireDestroyGCHandle(void *handleID) = 0;
virtual
virtual
void HandleFatalError(unsigned int exitCode) = 0;
- // Asks the EE if it wants a particular object to be finalized when unloading
- // an app domain.
- virtual
- bool ShouldFinalizeObjectForUnload(void* pDomain, Object* obj) = 0;
-
// Offers the EE the option to finalize the given object eagerly, i.e.
// not on the finalizer thread but on the current thread. The
// EE returns true if it finalized the object eagerly and the GC does not
IGCToCLREventSink* EventSink() = 0;
virtual
- uint32_t GetDefaultDomainIndex() = 0;
-
- virtual
- void *GetAppDomainAtIndex(uint32_t appDomainIndex) = 0;
-
- virtual
- uint32_t GetIndexOfAppDomainBeingUnloaded() = 0;
-
- virtual
- bool AppDomainCanAccessHandleTable(uint32_t appDomainID) = 0;
-
- virtual
uint32_t GetTotalNumSizedRefHandles() = 0;
virtual
- bool AppDomainIsRudeUnload(void *appDomain) = 0;
-
- virtual
bool AnalyzeSurvivorsRequested(int condemnedGeneration) = 0;
virtual
virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0;
- // Relocates async pinned handles from a condemned handle store to the default domain's handle store.
- //
- // The two callbacks are called when:
- // 1. clearIfComplete is called whenever the handle table observes an async pin that is still live.
- // The callback gives a chance for the EE to unpin the referents if the overlapped operation is complete.
- // 2. setHandle is called whenever the GC has relocated the async pin to a new handle table. The passed-in
- // handle is the newly-allocated handle in the default domain that should be assigned to the overlapped object.
- virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)) = 0;
-
- virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) = 0;
-
virtual ~IGCHandleStore() {};
};
virtual void Shutdown() = 0;
- virtual void* GetHandleContext(OBJECTHANDLE handle) = 0;
-
virtual IGCHandleStore* GetGlobalHandleStore() = 0;
- virtual IGCHandleStore* CreateHandleStore(void* context) = 0;
+ virtual IGCHandleStore* CreateHandleStore() = 0;
virtual void DestroyHandleStore(IGCHandleStore* store) = 0;
to synchronize with the GC, when the VM wants to update something that
the GC is potentially using, if it's doing a background GC.
- Concrete examples of this are moving async pinned handles across appdomains
- and profiling/ETW scenarios.
+ Concrete examples of this are profiling/ETW scenarios.
===========================================================================
*/
===========================================================================
*/
- // Finalizes an app domain by finalizing objects within that app domain.
- virtual bool FinalizeAppDomain(void* pDomain, bool fRunFinalizers) = 0;
-
// Finalizes all registered objects for shutdown, even if they are still reachable.
virtual void SetFinalizeQueueForShutdown(bool fHasLock) = 0;
// Returns the number of GCs that have transpired in the given generation
// since the beginning of the life of the process. Also used by the VM
- // for debug code and app domains.
+ // for debug code.
virtual int CollectionCount(int generation, int get_bgc_fgc_coutn = 0) = 0;
// Begins a no-GC region, returning a code indicating whether entering the no-GC
#define GC_CALL_INTERIOR 0x1
#define GC_CALL_PINNED 0x2
-#define GC_CALL_CHECK_APP_DOMAIN 0x4
//flags for IGCHeapAlloc(...)
enum GC_ALLOC_FLAGS
uintptr_t stack_limit; // Lowest point on the thread stack that the scanning logic is permitted to read
bool promotion; //TRUE: Promotion, FALSE: Relocation.
bool concurrent; //TRUE: concurrent scanning
-#if defined (FEATURE_APPDOMAIN_RESOURCE_MONITORING) || defined (DACCESS_COMPILE)
- AppDomain *pCurrentDomain;
-#else
void* _unused1;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING || DACCESS_COMPILE
void* pMD;
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
EtwGCRootKind dwEtwRootKind;
}
- BOOL FinalizeSegForAppDomain (void *pDomain,
- BOOL fRunFinalizers,
- unsigned int Seg);
-
public:
~CFinalize();
bool Initialize();
size_t GetNumberFinalizableObjects();
void DiscardNonCriticalObjects();
- //Methods used by the app domain unloading call to finalize objects in an app domain
- bool FinalizeAppDomain (void *pDomain, bool fRunFinalizers);
-
void CheckFinalizerObjects();
};
* Allocates and initializes a handle table.
*
*/
-HHANDLETABLE HndCreateHandleTable(const uint32_t *pTypeFlags, uint32_t uTypeCount, ADIndex uADIndex)
+HHANDLETABLE HndCreateHandleTable(const uint32_t *pTypeFlags, uint32_t uTypeCount)
{
CONTRACTL
{
// Store user data
pTable->uTableIndex = (uint32_t) -1;
- pTable->uADIndex = uADIndex;
// loop over various arrays an initialize them
uint32_t u;
return pTable->uTableIndex;
}
-/*
- * HndGetHandleTableIndex
- *
- * Retrieves the AppDomain index associated with a handle table at creation
- */
-ADIndex HndGetHandleTableADIndex(HHANDLETABLE hTable)
-{
- WRAPPER_NO_CONTRACT;
-
- // fetch the handle table pointer
- HandleTable *pTable = Table(hTable);
-
- return pTable->uADIndex;
-}
-
-/*
- * HndGetHandleTableIndex
- *
- * Retrieves the AppDomain index associated with a handle table at creation
- */
-GC_DAC_VISIBLE
-ADIndex HndGetHandleADIndex(OBJECTHANDLE handle)
-{
- WRAPPER_NO_CONTRACT;
- SUPPORTS_DAC;
-
- // fetch the handle table pointer
- HandleTable *pTable = Table(HndGetHandleTable(handle));
-
- return pTable->uADIndex;
-}
-
#ifndef DACCESS_COMPILE
/*
* HndCreateHandle
#endif // !DACCESS_COMPILE
#ifdef _DEBUG
-void ValidateFetchObjrefForHandle(OBJECTREF objref, ADIndex appDomainIndex)
+void ValidateFetchObjrefForHandle(OBJECTREF objref)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
BEGIN_DEBUG_ONLY_CODE;
VALIDATEOBJECTREF (objref);
-
-#ifndef DACCESS_COMPILE
- _ASSERTE(GCToEEInterface::AppDomainCanAccessHandleTable(appDomainIndex.m_dwIndex));
-#endif // DACCESS_COMPILE
-
END_DEBUG_ONLY_CODE;
}
-void ValidateAssignObjrefForHandle(OBJECTREF objref, ADIndex appDomainIndex)
+void ValidateAssignObjrefForHandle(OBJECTREF objref)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_DEBUG_ONLY;
BEGIN_DEBUG_ONLY_CODE;
-
VALIDATEOBJECTREF (objref);
-
-#ifndef DACCESS_COMPILE
- _ASSERTE(GCToEEInterface::AppDomainCanAccessHandleTable(appDomainIndex.m_dwIndex));
-#endif // DACCESS_COMPILE
- END_DEBUG_ONLY_CODE;
-}
-
-void ValidateAppDomainForHandle(OBJECTHANDLE handle)
-{
- STATIC_CONTRACT_DEBUG_ONLY;
- STATIC_CONTRACT_NOTHROW;
-
-#ifdef DEBUG_DestroyedHandleValue
- // Verify that we are not trying to access freed handle.
- _ASSERTE("Attempt to access destroyed handle." && *(_UNCHECKED_OBJECTREF *)handle != DEBUG_DestroyedHandleValue);
-#endif
-#ifdef DACCESS_COMPILE
- UNREFERENCED_PARAMETER(handle);
-#else
- BEGIN_DEBUG_ONLY_CODE;
- ADIndex id = HndGetHandleADIndex(handle);
- ADIndex unloadingDomain(GCToEEInterface::GetIndexOfAppDomainBeingUnloaded());
- if (unloadingDomain != id)
- {
- return;
- }
- if (GCToEEInterface::AppDomainCanAccessHandleTable(unloadingDomain.m_dwIndex))
- {
- return;
- }
- _ASSERTE (!"Access to a handle in unloaded domain is not allowed");
END_DEBUG_ONLY_CODE;
-#endif // !DACCESS_COMPILE
}
#endif
// sanity check handle we are being asked to free
_ASSERTE(handle);
-#ifdef _DEBUG
- ValidateAppDomainForHandle(handle);
-#endif
-
// fetch the handle table pointer
HandleTable *pTable = Table(hTable);
if (EVENT_ENABLED(SetGCHandle) || EVENT_ENABLED(PrvSetGCHandle))
{
uint32_t hndType = HandleFetchType(handle);
- ADIndex appDomainIndex = HndGetHandleADIndex(handle);
- void* pAppDomain = GCToEEInterface::GetAppDomainAtIndex(appDomainIndex.m_dwIndex);
uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0;
- FIRE_EVENT(SetGCHandle, (void *)handle, (void *)value, hndType, generation, (uint64_t)pAppDomain);
- FIRE_EVENT(PrvSetGCHandle, (void *) handle, (void *)value, hndType, generation, (uint64_t)pAppDomain);
+ FIRE_EVENT(SetGCHandle, (void *)handle, (void *)value, hndType, generation);
+ FIRE_EVENT(PrvSetGCHandle, (void *) handle, (void *)value, hndType, generation);
// Also fire the things pinned by Async pinned handles
if (hndType == HNDTYPE_ASYNCPINNED)
{
- // the closure passed to "WalkOverlappedObject" is not permitted to implicitly
- // capture any variables in this scope, since WalkForOverlappedObject takes a bare
- // function pointer and context pointer as arguments. We can still /explicitly/
- // close over values in this scope by doing what the compiler would do and introduce
- // a structure that contains all of the things we closed over, while passing a pointer
- // to this structure as our closure's context pointer.
- struct ClosureCapture
+ GCToEEInterface::WalkAsyncPinned(value, value, [](Object*, Object* to, void* ctx)
{
- void* pAppDomain;
- Object* overlapped;
- };
-
- ClosureCapture captured;
- captured.pAppDomain = pAppDomain;
- captured.overlapped = value;
- GCToEEInterface::WalkAsyncPinned(value, &captured, [](Object*, Object* to, void* ctx)
- {
- ClosureCapture* captured = reinterpret_cast<ClosureCapture*>(ctx);
+ Object* overlapped = reinterpret_cast<Object*>(ctx);
uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0;
- FIRE_EVENT(SetGCHandle, (void *)captured->overlapped, (void *)to, HNDTYPE_PINNED, generation, (uint64_t)captured->pAppDomain);
+ FIRE_EVENT(SetGCHandle, (void *)overlapped, (void *)to, HNDTYPE_PINNED, generation);
});
}
}
return uCount;
}
-BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- AsyncPinCallbackContext callbackCtx(asyncPinCallback, context);
- HandleTableBucket *pBucket = g_HandleTableMap.pBuckets[0];
- BOOL result = FALSE;
- int limit = getNumberOfSlots();
- for (int n = 0; n < limit; n ++ )
- {
- if (TableHandleAsyncPinHandles(Table(pBucket->pTable[n]), callbackCtx))
- {
- result = TRUE;
- }
- }
-
- return result;
-}
-
-void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource,
- HandleTableBucket *pTarget,
- void (*clearIfComplete)(Object* object),
- void (*setHandle)(Object* object, OBJECTHANDLE handle))
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- int limit = getNumberOfSlots();
- for (int n = 0; n < limit; n ++ )
- {
- TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]), clearIfComplete, setHandle);
- }
-}
-
/*--------------------------------------------------------------------------*/
/*
* handle manager init and shutdown routines
*/
-HHANDLETABLE HndCreateHandleTable(const uint32_t *pTypeFlags, uint32_t uTypeCount, ADIndex uADIndex);
+HHANDLETABLE HndCreateHandleTable(const uint32_t *pTypeFlags, uint32_t uTypeCount);
void HndDestroyHandleTable(HHANDLETABLE hTable);
#endif // !DACCESS_COMPILE
*/
void HndSetHandleTableIndex(HHANDLETABLE hTable, uint32_t uTableIndex);
uint32_t HndGetHandleTableIndex(HHANDLETABLE hTable);
-ADIndex HndGetHandleTableADIndex(HHANDLETABLE hTable);
-
-GC_DAC_VISIBLE
-ADIndex HndGetHandleADIndex(OBJECTHANDLE handle);
#ifndef DACCESS_COMPILE
/*
#ifdef _DEBUG_IMPL
-void ValidateAssignObjrefForHandle(OBJECTREF, ADIndex appDomainIndex);
-void ValidateFetchObjrefForHandle(OBJECTREF, ADIndex appDomainIndex);
-void ValidateAppDomainForHandle(OBJECTHANDLE handle);
+void ValidateAssignObjrefForHandle(OBJECTREF);
+void ValidateFetchObjrefForHandle(OBJECTREF);
#endif
/*
_ASSERTE("Attempt to access destroyed handle." && *(_UNCHECKED_OBJECTREF *)handle != DEBUG_DestroyedHandleValue);
// Make sure the objref for handle is valid
- ValidateFetchObjrefForHandle(ObjectToOBJECTREF(*(Object **)handle),
- HndGetHandleTableADIndex(HndGetHandleTable(handle)));
+ ValidateFetchObjrefForHandle(ObjectToOBJECTREF(*(Object **)handle));
#endif // _DEBUG_IMPL
// wrap the raw objectref and return it
return pSegment;
}
-// Mark a handle being free.
-__inline void SegmentMarkFreeMask(TableSegment *pSegment, _UNCHECKED_OBJECTREF* h)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- uint32_t uMask = (uint32_t)(h - pSegment->rgValue);
- uint32_t uBit = uMask % HANDLE_HANDLES_PER_MASK;
- uMask = uMask / HANDLE_HANDLES_PER_MASK;
- pSegment->rgFreeMask[uMask] |= (1<<uBit);
-}
-
-// Mark a handle being used.
-__inline void SegmentUnMarkFreeMask(TableSegment *pSegment, _UNCHECKED_OBJECTREF* h)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- uint32_t uMask = (uint32_t)(h - pSegment->rgValue);
- uint32_t uBit = uMask % HANDLE_HANDLES_PER_MASK;
- uMask = uMask / HANDLE_HANDLES_PER_MASK;
- pSegment->rgFreeMask[uMask] &= ~(1<<uBit);
-}
-
-// Prepare a segment to be moved to default domain.
-// Remove all non-async pin handles.
-void SegmentPreCompactAsyncPinHandles(TableSegment *pSegment, void (*clearIfComplete)(Object*))
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- pSegment->fResortChains = true;
- pSegment->fNeedsScavenging = true;
-
- // Zero out all non-async pin handles
- uint32_t uBlock;
- for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
- {
- if (pSegment->rgBlockType[uBlock] == TYPE_INVALID)
- {
- continue;
- }
- else if (pSegment->rgBlockType[uBlock] != HNDTYPE_ASYNCPINNED)
- {
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
- do
- {
- *pValue = NULL;
- pValue ++;
- } while (pValue < pLast);
-
- ((uint32_t*)pSegment->rgGeneration)[uBlock] = (uint32_t)-1;
-
- uint32_t *pdwMask = pSegment->rgFreeMask + (uBlock * HANDLE_MASKS_PER_BLOCK);
- uint32_t *pdwMaskLast = pdwMask + HANDLE_MASKS_PER_BLOCK;
- do
- {
- *pdwMask = MASK_EMPTY;
- pdwMask ++;
- } while (pdwMask < pdwMaskLast);
-
- pSegment->rgBlockType[uBlock] = TYPE_INVALID;
- pSegment->rgUserData[uBlock] = BLOCK_INVALID;
- pSegment->rgLocks[uBlock] = 0;
- }
- }
-
- // Return all non-async pin handles to free list
- uint32_t uType;
- for (uType = 0; uType < HANDLE_MAX_INTERNAL_TYPES; uType ++)
- {
- if (uType == HNDTYPE_ASYNCPINNED)
- {
- continue;
- }
- pSegment->rgFreeCount[uType] = 0;
- if (pSegment->rgHint[uType] != BLOCK_INVALID)
- {
- uint32_t uLast = pSegment->rgHint[uType];
- uint8_t uFirst = pSegment->rgAllocation[uLast];
- pSegment->rgAllocation[uLast] = pSegment->bFreeList;
- pSegment->bFreeList = uFirst;
- pSegment->rgHint[uType] = BLOCK_INVALID;
- pSegment->rgTail[uType] = BLOCK_INVALID;
- }
- }
-
- // make sure the remaining async handle has MethodTable that exists in default domain
- uBlock = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- if (uBlock == BLOCK_INVALID)
- {
- return;
- }
- uint32_t freeCount = 0;
- for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
- {
- if (pSegment->rgBlockType[uBlock] != HNDTYPE_ASYNCPINNED)
- {
- continue;
- }
- if (pSegment->rgFreeMask[uBlock*2] == (uint32_t)-1 && pSegment->rgFreeMask[uBlock*2+1] == (uint32_t)-1)
- {
- continue;
- }
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
-
- do
- {
- _UNCHECKED_OBJECTREF value = *pValue;
- if (!HndIsNullOrDestroyedHandle(value))
- {
- clearIfComplete((Object*)value);
- }
- else
- {
- // reset free mask
- SegmentMarkFreeMask(pSegment, pValue);
- freeCount ++;
- }
- pValue ++;
- } while (pValue != pLast);
- }
-
- pSegment->rgFreeCount[HNDTYPE_ASYNCPINNED] = freeCount;
-}
-
-// Copy a handle to a different segment in the same HandleTable
-BOOL SegmentCopyAsyncPinHandle(TableSegment *pSegment, _UNCHECKED_OBJECTREF *h)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- _ASSERTE (HandleFetchSegmentPointer((OBJECTHANDLE)h) != pSegment);
-
- if (pSegment->rgFreeCount[HNDTYPE_ASYNCPINNED] == 0)
- {
- uint8_t uBlock = pSegment->bFreeList;
- if (uBlock == BLOCK_INVALID)
- {
- // All slots are used up.
- return FALSE;
- }
- pSegment->bFreeList = pSegment->rgAllocation[uBlock];
- pSegment->rgBlockType[uBlock] = HNDTYPE_ASYNCPINNED;
- pSegment->rgAllocation[uBlock] = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- pSegment->rgHint[HNDTYPE_ASYNCPINNED] = uBlock;
- pSegment->rgFreeCount[HNDTYPE_ASYNCPINNED] += HANDLE_HANDLES_PER_BLOCK;
- }
- uint8_t uBlock = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- uint8_t uLast = uBlock;
- do
- {
- uint32_t n = uBlock * (HANDLE_HANDLES_PER_BLOCK/HANDLE_HANDLES_PER_MASK);
- uint32_t* pMask = pSegment->rgFreeMask + n;
- if (pMask[0] != 0 || pMask[1] != 0)
- {
- break;
- }
- uBlock = pSegment->rgAllocation[uBlock];
- } while (uBlock != uLast);
- _ASSERTE (uBlock != uLast);
- pSegment->rgHint[HNDTYPE_ASYNCPINNED] = uBlock;
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
- do
- {
- if (*pValue == NULL)
- {
- SegmentUnMarkFreeMask(pSegment,pValue);
- *pValue = *h;
- *h = NULL;
- break;
- }
- pValue ++;
- } while (pValue != pLast);
- _ASSERTE (pValue != pLast);
- pSegment->rgFreeCount[HNDTYPE_ASYNCPINNED] --;
- return TRUE;
-}
-
-void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWorkerSegment, void (*clearIfComplete)(Object*))
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- uint32_t uBlock = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- if (uBlock == BLOCK_INVALID)
- {
- return;
- }
- for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
- {
- if (pSegment->rgBlockType[uBlock] != HNDTYPE_ASYNCPINNED)
- {
- continue;
- }
- if (pSegment->rgFreeMask[uBlock*2] == (uint32_t)-1 && pSegment->rgFreeMask[uBlock*2+1] == (uint32_t)-1)
- {
- continue;
- }
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
-
- do
- {
- BOOL fNeedNewSegment = FALSE;
- _UNCHECKED_OBJECTREF value = *pValue;
- if (!HndIsNullOrDestroyedHandle(value))
- {
- clearIfComplete((Object*)value);
- fNeedNewSegment = !SegmentCopyAsyncPinHandle(*ppWorkerSegment,pValue);
- }
- if (fNeedNewSegment)
- {
- _ASSERTE ((*ppWorkerSegment)->rgFreeCount[HNDTYPE_ASYNCPINNED] == 0 &&
- (*ppWorkerSegment)->bFreeList == BLOCK_INVALID);
- TableSegment *pNextSegment = (*ppWorkerSegment)->pNextSegment;
- SegmentPreCompactAsyncPinHandles(pNextSegment, clearIfComplete);
- *ppWorkerSegment = pNextSegment;
- if (pNextSegment == pSegment)
- {
- // The current segment will be moved to default domain.
- return;
- }
- }
- else
- {
- pValue ++;
- }
- } while (pValue != pLast);
- }
-}
-
-
-// Mark AsyncPinHandles ready to be cleaned when the marker job is processed
-BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment, const AsyncPinCallbackContext &callbackCtx)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- NOTHROW;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- uint32_t uBlock = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- if (uBlock == BLOCK_INVALID)
- {
- // There is no pinning handles.
- return FALSE;
- }
-
- BOOL result = FALSE;
-
- for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
- {
- if (pSegment->rgBlockType[uBlock] != HNDTYPE_ASYNCPINNED)
- {
- continue;
- }
- if (pSegment->rgFreeMask[uBlock*2] == (uint32_t)-1 && pSegment->rgFreeMask[uBlock*2+1] == (uint32_t)-1)
- {
- continue;
- }
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
-
- do
- {
- _UNCHECKED_OBJECTREF value = *pValue;
- if (!HndIsNullOrDestroyedHandle(value))
- {
- // calls back into the VM using the callback given to
- // Ref_HandleAsyncPinHandles
- if (callbackCtx.Invoke((Object*)value))
- {
- result = TRUE;
- }
- }
- pValue ++;
- } while (pValue != pLast);
- }
-
- return result;
-}
-
-// Replace an async pin handle with one from default domain
-bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment,
- HandleTable *pTargetTable,
- void (*clearIfComplete)(Object*),
- void (*setHandle)(Object*, OBJECTHANDLE))
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- NOTHROW;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- uint32_t uBlock = pSegment->rgHint[HNDTYPE_ASYNCPINNED];
- if (uBlock == BLOCK_INVALID)
- {
- // There is no pinning handles.
- return true;
- }
- for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
- {
- if (pSegment->rgBlockType[uBlock] != HNDTYPE_ASYNCPINNED)
- {
- continue;
- }
- if (pSegment->rgFreeMask[uBlock*2] == (uint32_t)-1 && pSegment->rgFreeMask[uBlock*2+1] == (uint32_t)-1)
- {
- continue;
- }
- _UNCHECKED_OBJECTREF *pValue = pSegment->rgValue + (uBlock * HANDLE_HANDLES_PER_BLOCK);
- _UNCHECKED_OBJECTREF *pLast = pValue + HANDLE_HANDLES_PER_BLOCK;
-
- do
- {
- _UNCHECKED_OBJECTREF value = *pValue;
- if (!HndIsNullOrDestroyedHandle(value))
- {
- clearIfComplete((Object*)value);
- OBJECTHANDLE selfHandle = HndCreateHandle((HHANDLETABLE)pTargetTable, HNDTYPE_ASYNCPINNED, ObjectToOBJECTREF(value));
- if (!selfHandle)
- {
- // failed to allocate a new handle - callers have to handle this.
- return false;
- }
-
- setHandle((Object*)value, selfHandle);
- *pValue = NULL;
- }
- pValue ++;
- } while (pValue != pLast);
- }
-
- return true;
-}
-
-// Mark all non-pending AsyncPinHandle ready for cleanup.
-// We will queue a marker Overlapped to io completion port. We use the marker
-// to make sure that all iocompletion jobs before this marker have been processed.
-// After that we can free the async pinned handles.
-BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackContext &callbackCtx)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- NOTHROW;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- BOOL result = FALSE;
- TableSegment *pSegment = pTable->pSegmentList;
-
- CrstHolder ch(&pTable->Lock);
-
- while (pSegment)
- {
- if (SegmentHandleAsyncPinHandles (pSegment, callbackCtx))
- {
- result = TRUE;
- }
- pSegment = pSegment->pNextSegment;
- }
-
- return result;
-}
-
-// Keep needed async Pin Handle by moving them to default domain.
-// Strategy:
-// 1. Try to create pin handles in default domain to replace it.
-// 2. If 1 failed due to OOM, we will relocate segments from this HandleTable to default domain.
-// a. Clean the segment so that only saved pin handles exist. This segment becomes the worker segment.
-// b. Copy pin handles from remaining segments to the worker segment. If worker segment is full, start
-// from a again.
-// c. After copying all handles to worker segments, move the segments to default domain.
-// It is very important that in step 2, we should not fail for OOM, which means no memory allocation.
-void TableRelocateAsyncPinHandles(HandleTable *pTable,
- HandleTable *pTargetTable,
- void (*clearIfComplete)(Object*),
- void (*setHandle)(Object*, OBJECTHANDLE))
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- NOTHROW;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- _ASSERTE (pTargetTable->uADIndex == ADIndex(GCToEEInterface::GetDefaultDomainIndex())); // must be for default domain
-
- BOOL fGotException = FALSE;
- TableSegment *pSegment = pTable->pSegmentList;
- bool wasSuccessful = true;
-
-#ifdef _DEBUG
- // on debug builds, execute the OOM path 10% of the time.
- if (GetRandomInt(100) < 10)
- goto SLOW_PATH;
-#endif
-
- // Step 1: replace pinning handles with ones from default domain
- while (pSegment)
- {
- wasSuccessful = wasSuccessful && SegmentRelocateAsyncPinHandles (pSegment, pTargetTable, clearIfComplete, setHandle);
- if (!wasSuccessful)
- {
- break;
- }
-
- pSegment = pSegment->pNextSegment;
- }
-
- if (wasSuccessful)
- {
- return;
- }
-
-#ifdef _DEBUG
-SLOW_PATH:
-#endif
-
- // step 2: default domain runs out of space
- // compact all remaining pinning handles and move the segments to default domain
-
- while (true)
- {
- CrstHolderWithState ch(&pTable->Lock);
-
- // We cannot move segments to a different table if we're asynchronously scanning the current table as
- // part of a concurrent GC. That's because the async table scanning code does most of its work without
- // the table lock held. So we'll take the table lock and then look to see if we're in a concurrent GC.
- // If we are we'll back out and try again. This doesn't prevent a concurrent GC from initiating while
- // we have the lock held but the part we care about (the async table scan) takes the table lock during
- // a preparation step so we'll be able to complete our segment moves before the async scan has a
- // chance to interfere with us (or vice versa).
- if (g_theGCHeap->IsConcurrentGCInProgress())
- {
- // A concurrent GC is in progress so someone might be scanning our segments asynchronously.
- // Release the lock, wait for the GC to complete and try again. The order is important; if we wait
- // before releasing the table lock we can deadlock with an async table scan.
- ch.Release();
- g_theGCHeap->WaitUntilConcurrentGCComplete();
- continue;
- }
-
- // If we get here then we managed to acquire the table lock and observe that no concurrent GC was in
- // progress. A concurrent GC could start at any time so that state may have changed, but since we took
- // the table lock first we know that the GC could only have gotten as far as attempting to initiate an
- // async handle table scan (which attempts to acquire the table lock). So as long as we complete our
- // segment compaction and moves without releasing the table lock we're guaranteed to complete before
- // the async scan can get in and observe any of the segments.
-
- // Compact async pinning handles into the smallest number of leading segments we can (the worker
- // segments).
- TableSegment *pWorkerSegment = pTable->pSegmentList;
- SegmentPreCompactAsyncPinHandles (pWorkerSegment, clearIfComplete);
-
- pSegment = pWorkerSegment->pNextSegment;
- while (pSegment)
- {
- SegmentCompactAsyncPinHandles (pSegment, &pWorkerSegment, clearIfComplete);
- pSegment= pSegment->pNextSegment;
- }
-
- // Empty the remaining segments.
- pSegment = pWorkerSegment->pNextSegment;
- while (pSegment)
- {
- memset(pSegment->rgValue, 0, (uint32_t)pSegment->bCommitLine * HANDLE_BYTES_PER_BLOCK);
- pSegment = pSegment->pNextSegment;
- }
-
- // Move the worker segments over to the tail end of the default domain's segment list.
- {
- CrstHolder ch1(&pTargetTable->Lock);
-
- // Locate the segment currently at the tail of the default domain's segment list.
- TableSegment *pTargetSegment = pTargetTable->pSegmentList;
- while (pTargetSegment->pNextSegment)
- {
- pTargetSegment = pTargetSegment->pNextSegment;
- }
-
- // Take the worker segments and point them to their new handle table and recalculate their
- // sequence numbers to be consistent with the queue they're moving to.
- uint8_t bLastSequence = pTargetSegment->bSequence;
- pSegment = pTable->pSegmentList;
- while (pSegment != pWorkerSegment->pNextSegment)
- {
- pSegment->pHandleTable = pTargetTable;
- pSegment->bSequence = (uint8_t)(((uint32_t)bLastSequence + 1) % 0x100);
- bLastSequence = pSegment->bSequence;
- pSegment = pSegment->pNextSegment;
- }
-
- // Join the worker segments to the tail of the default domain segment list.
- pTargetSegment->pNextSegment = pTable->pSegmentList;
-
- // Reset the current handle table segment list to omit the removed worker segments and start at
- // the first non-worker.
- pTable->pSegmentList = pWorkerSegment->pNextSegment;
-
- // The last worker segment is now the end of the default domain's segment list.
- pWorkerSegment->pNextSegment = NULL;
- }
-
- break;
- }
-}
-
/*
* Check if a handle is part of a HandleTable
*/
int32_t lFreeIndex;
};
-/*
- * Async pin EE callback context, used to call back tot he EE when enumerating
- * over async pinned handles.
- */
-class AsyncPinCallbackContext
-{
-private:
- async_pin_enum_fn m_callback;
- void* m_context;
-
-public:
- /*
- * Constructs a new AsyncPinCallbackContext from a callback and a context,
- * which will be passed to the callback as its second parameter every time
- * it is invoked.
- */
- AsyncPinCallbackContext(async_pin_enum_fn callback, void* context)
- : m_callback(callback), m_context(context)
- {}
-
- /*
- * Invokes the callback with the given argument, returning the callback's
- * result.'
- */
- bool Invoke(Object* argument) const
- {
- assert(m_callback != nullptr);
- return m_callback(argument, m_context);
- }
-};
-
-
/*---------------------------------------------------------------------------*/
uint32_t rgTypeFlags[HANDLE_MAX_INTERNAL_TYPES];
/*
- * per-table AppDomain info
- */
- ADIndex uADIndex;
-
- /*
* lock for this table
*/
CrstStatic Lock;
void SegmentFree(TableSegment *pSegment);
/*
- * TableHandleAsyncPinHandles
- *
- * Mark ready for all non-pending OverlappedData that get moved to default domain.
- *
- */
-BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackContext& callbackCtx);
-
-/*
- * TableRelocateAsyncPinHandles
- *
- * Replaces async pin handles with ones in default domain.
- *
- */
-void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE));
-
-/*
* Check if a handle is part of a HandleTable
*/
BOOL TableContainHandle(HandleTable *pTable, OBJECTHANDLE handle);
n_slots * sizeof(HHANDLETABLE));
for (int uCPUindex = 0; uCPUindex < n_slots; uCPUindex++)
{
- pBucket->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), ADIndex(1));
+ pBucket->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags));
if (pBucket->pTable[uCPUindex] == NULL)
goto CleanupAndFail;
}
#ifndef FEATURE_REDHAWK
-bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context)
+bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket)
{
CONTRACTL
{
ZeroMemory(result->pTable, n_slots * sizeof(HHANDLETABLE));
for (int uCPUindex=0; uCPUindex < n_slots; uCPUindex++) {
- result->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), ADIndex((DWORD)(uintptr_t)context));
+ result->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags));
if (!result->pTable[uCPUindex])
return false;
}
_ASSERTE(handle);
#ifdef _DEBUG
- // handle should not be in unloaded domain
- ValidateAppDomainForHandle(handle);
-
// Make sure the objref is valid before it is assigned to a handle
- ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
+ ValidateAssignObjrefForHandle(objref);
#endif
// unwrap the objectref we were given
_UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
HHANDLETABLE hTable = walk->pBuckets[i]->pTable[getSlotNumber((ScanContext*) lp1)];
if (hTable)
{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- ScanContext* sc = (ScanContext *)lp1;
- sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(HndGetHandleTableADIndex(hTable));
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
HndScanHandlesForGC(hTable, VariableTraceDispatcher,
lp1, (uintptr_t)&info, &type, 1, condemned, maxgen, HNDGCF_EXTRAINFO | flags);
}
HHANDLETABLE hTable = walk->pBuckets[i]->pTable[getSlotNumber((ScanContext*) sc)];
if (hTable)
{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(HndGetHandleTableADIndex(hTable));
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
// Pinned handles and async pinned handles are scanned in separate passes, since async pinned
// handles may require a callback into the EE in order to fully trace an async pinned
// object's object graph.
HHANDLETABLE hTable = walk->pBuckets[i]->pTable[getSlotNumber(sc)];
if (hTable)
{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(HndGetHandleTableADIndex(hTable));
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
HndScanHandlesForGC(hTable, PromoteObject, uintptr_t(sc), uintptr_t(fn), types, uTypeCount, condemned, maxgen, flags);
}
}
}
}
-// We scan handle tables by their buckets (ie, AD index). We could get into the situation where
-// the AD indices are not very compacted (for example if we have just unloaded ADs and their
-// indices haven't been reused yet) and we could be scanning them in an unbalanced fashion.
-// Consider using an array to represent the compacted form of all AD indices exist for the
-// sized ref handles.
-void ScanSizedRefByAD(uint32_t maxgen, HANDLESCANPROC scanProc, ScanContext* sc, Ref_promote_func* fn, uint32_t flags)
-{
- HandleTableMap *walk = &g_HandleTableMap;
- uint32_t type = HNDTYPE_SIZEDREF;
- int uCPUindex = getSlotNumber(sc);
- int n_slots = g_theGCHeap->GetNumberOfHeaps();
-
- while (walk)
- {
- for (uint32_t i = 0; i < INITIAL_HANDLE_TABLE_ARRAY_SIZE; i ++)
- {
- if (walk->pBuckets[i] != NULL)
- {
- ADIndex adIndex = HndGetHandleTableADIndex(walk->pBuckets[i]->pTable[0]);
- if ((adIndex.m_dwIndex % n_slots) == (uint32_t)uCPUindex)
- {
- for (int index = 0; index < n_slots; index++)
- {
- HHANDLETABLE hTable = walk->pBuckets[i]->pTable[index];
- if (hTable)
- {
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(adIndex);
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
- HndScanHandlesForGC(hTable, scanProc, uintptr_t(sc), uintptr_t(fn), &type, 1, maxgen, maxgen, flags);
- }
- }
- }
- }
- }
- walk = walk->pNext;
- }
-}
-
void ScanSizedRefByCPU(uint32_t maxgen, HANDLESCANPROC scanProc, ScanContext* sc, Ref_promote_func* fn, uint32_t flags)
{
HandleTableMap *walk = &g_HandleTableMap;
HHANDLETABLE hTable = walk->pBuckets[i]->pTable[uCPUindex];
if (hTable)
{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(HndGetHandleTableADIndex(hTable));
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
HndScanHandlesForGC(hTable, scanProc, uintptr_t(sc), uintptr_t(fn), &type, 1, maxgen, maxgen, flags);
}
}
static_assert(offsetof(HandleTableMap, dwMaxIndex) == offsetof(dac_handle_table_map, dwMaxIndex), "handle table map DAC layout mismatch");
static_assert(offsetof(HandleTableBucket, pTable) == offsetof(dac_handle_table_bucket, pTable), "handle table bucket DAC layout mismatch");
static_assert(offsetof(HandleTableBucket, HandleTableIndex) == offsetof(dac_handle_table_bucket, HandleTableIndex), "handle table bucket DAC layout mismatch");
- static_assert(offsetof(HandleTable, uADIndex) == offsetof(dac_handle_table, uADIndex), "handle table DAC layout mismatch");
#ifndef DACCESS_COMPILE
gcDacVars->handle_table_map = reinterpret_cast<dac_handle_table_map*>(&g_HandleTableMap);
*/
bool Ref_Initialize();
void Ref_Shutdown();
-bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context);
-BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn callback, void* context);
-void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE));
+bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket);
void Ref_RemoveHandleTableBucket(HandleTableBucket *pBucket);
void Ref_DestroyHandleTableBucket(HandleTableBucket *pBucket);
abort();
}
-bool GCToEEInterface::ShouldFinalizeObjectForUnload(void* pDomain, Object* obj)
-{
- return true;
-}
-
bool GCToEEInterface::EagerFinalized(Object* obj)
{
// The sample does not finalize anything eagerly.
{
}
-uint32_t GCToEEInterface::GetDefaultDomainIndex()
-{
- return -1;
-}
-
-void *GCToEEInterface::GetAppDomainAtIndex(uint32_t appDomainIndex)
-{
- return nullptr;
-}
-
-bool GCToEEInterface::AppDomainCanAccessHandleTable(uint32_t appDomainID)
-{
- return true;
-}
-
-uint32_t GCToEEInterface::GetIndexOfAppDomainBeingUnloaded()
-{
- return -1;
-}
-
uint32_t GCToEEInterface::GetTotalNumSizedRefHandles()
{
return -1;
}
-bool GCToEEInterface::AppDomainIsRudeUnload(void *appDomain)
-{
- return false;
-}
-
inline bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration)
{
return false;
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_EnableFullDebug, W("EnableFullDebug"), "Heavy-weight checking for AD boundary violations (AD leaks)")
///
-/// ARM
-///
-RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ARMEnabled, W("ARMEnabled"), (DWORD)0, "AppDomain Resource Monitoring. Set to 1 to enable it")
-
-///
/// Jit Pitching
///
RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitPitchEnabled, W("JitPitchEnabled"), (DWORD)0, "Set it to 1 to enable Jit Pitching")
DECLSPEC_ALIGN(16)
static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
-size_t SystemDomain::m_totalSurvivedBytes = 0;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
CrstStatic SystemDomain::m_SystemDomainCrst;
CrstStatic SystemDomain::m_DelayedUnloadCrst;
AppDomain* pAppDomain = ::GetAppDomain();
if (pAppDomain && pAppDomain->IsActive())
{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- sc->pCurrentDomain = pAppDomain;
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
pAppDomain->EnumStaticGCRefs(fn, sc);
}
}
RETURN;
}
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
-void SystemDomain::ResetADSurvivedBytes()
-{
- CONTRACT_VOID
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-
- _ASSERTE(GCHeapUtilities::IsGCInProgress());
-
- SystemDomain* sysDomain = SystemDomain::System();
- if (sysDomain)
- {
- AppDomain* pAppDomain = ::GetAppDomain();
- if (pAppDomain && pAppDomain->IsUserActive())
- {
- pAppDomain->ResetSurvivedBytes();
- }
- }
-
- RETURN;
-}
-
-ULONGLONG SystemDomain::GetADSurvivedBytes()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SystemDomain* sysDomain = SystemDomain::System();
- ULONGLONG ullTotalADSurvived = 0;
- if (sysDomain)
- {
- AppDomain* pAppDomain = ::GetAppDomain();
- if (pAppDomain && pAppDomain->IsUserActive())
- {
- ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
- ullTotalADSurvived += ullSurvived;
- }
- }
-
- return ullTotalADSurvived;
-}
-
-void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
-{
- CONTRACT_VOID
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-
- m_totalSurvivedBytes = totalSurvivedBytes;
-
- SystemDomain* sysDomain = SystemDomain::System();
- if (sysDomain)
- {
- AppDomain* pAppDomain = ::GetAppDomain();
- if (pAppDomain && pAppDomain->IsUserActive())
- {
- FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
- }
- }
-
- RETURN;
-}
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
// Only called when EE is suspended.
DWORD SystemDomain::GetTotalNumSizedRefHandles()
{
m_dwCreationHolders=0;
#endif
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- m_ullTotalProcessorUsage = 0;
- m_pullAllocBytes = NULL;
- m_pullSurvivedBytes = NULL;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifdef FEATURE_TYPEEQUIVALENCE
m_pTypeEquivalenceTable = NULL;
#endif // FEATURE_TYPEEQUIVALENCE
#ifndef CROSSGEN_COMPILE
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- // NOTE: it's important that we initialize ARM data structures before calling
- // IGCHandleManager::CreateHandleStore, this is because AD::Init() can race with GC
- // and once we add ourselves to the handle table map the GC can start walking
- // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
- if (GCHeapUtilities::IsServerHeap())
- m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
- CPUGroupInfo::GetNumActiveProcessors() :
- GetCurrentProcessCpuCount();
- else
- m_dwNumHeaps = 1;
- m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
- m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
- for (DWORD i = 0; i < m_dwNumHeaps; i++)
- {
- m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
- m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
- }
- m_ullLastEtwAllocBytes = 0;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
// Default domain reuses the handletablemap that was created during EEStartup
m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
}
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
-#ifndef CROSSGEN_COMPILE
-// Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
-// result is in 100ns units.
-ULONGLONG AppDomain::QueryProcessorUsage()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- Thread *pThread = NULL;
-
- // Need to update our accumulated processor time count with current values from each thread that is
- // currently executing in this domain.
-
- // Take the thread store lock while we enumerate threads.
- ThreadStoreLockHolder tsl;
- while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
- {
- // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
- if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
- continue;
-
- // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
- // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
- UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
- }
-#endif // !DACCESS_COMPILE
-
- // Return the updated total.
- return m_ullTotalProcessorUsage;
-}
-
-// Add to the current count of processor time used by threads within this AppDomain. This API is called by
-// threads transitioning between AppDomains.
-void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
-{
- LIMITED_METHOD_CONTRACT;
-
- // Need to be careful to synchronize here, multiple threads could be racing to update this count.
- ULONGLONG ullOldValue;
- ULONGLONG ullNewValue;
- do
- {
- ullOldValue = m_ullTotalProcessorUsage;
- ullNewValue = ullOldValue + ullAdditionalUsage;
- } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
- (LONGLONG)ullNewValue,
- (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
-}
-#endif // CROSSGEN_COMPILE
-
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#if defined(FEATURE_TYPEEQUIVALENCE)
#ifndef DACCESS_COMPILE
PTR_LoaderHeap GetLowFrequencyHeap();
PTR_LoaderHeap GetHighFrequencyHeap();
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- #define ARM_ETW_ALLOC_THRESHOLD (4 * 1024 * 1024)
- // cache line size in ULONGLONG - 128 bytes which are 16 ULONGLONG's
- #define ARM_CACHE_LINE_SIZE_ULL 16
-
- inline ULONGLONG GetAllocBytes()
- {
- LIMITED_METHOD_CONTRACT;
- ULONGLONG ullTotalAllocBytes = 0;
-
- // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
- // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
- if(NULL != m_pullAllocBytes)
- {
- for (DWORD i = 0; i < m_dwNumHeaps; i++)
- {
- ullTotalAllocBytes += m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL];
- }
- }
- return ullTotalAllocBytes;
- }
-
- void RecordAllocBytes(size_t allocatedBytes, DWORD dwHeapNumber)
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(dwHeapNumber < m_dwNumHeaps);
-
- // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
- // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
- if(NULL != m_pullAllocBytes)
- {
- m_pullAllocBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += allocatedBytes;
- }
-
- ULONGLONG ullTotalAllocBytes = GetAllocBytes();
-
- if ((ullTotalAllocBytes - m_ullLastEtwAllocBytes) >= ARM_ETW_ALLOC_THRESHOLD)
- {
- m_ullLastEtwAllocBytes = ullTotalAllocBytes;
- FireEtwAppDomainMemAllocated((ULONGLONG)this, ullTotalAllocBytes, GetClrInstanceId());
- }
- }
-
- inline ULONGLONG GetSurvivedBytes()
- {
- LIMITED_METHOD_CONTRACT;
- ULONGLONG ullTotalSurvivedBytes = 0;
-
- // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
- // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
- if(NULL != m_pullSurvivedBytes)
- {
- for (DWORD i = 0; i < m_dwNumHeaps; i++)
- {
- ullTotalSurvivedBytes += m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL];
- }
- }
- return ullTotalSurvivedBytes;
- }
-
- void RecordSurvivedBytes(size_t promotedBytes, DWORD dwHeapNumber)
- {
- WRAPPER_NO_CONTRACT;
- _ASSERTE(dwHeapNumber < m_dwNumHeaps);
-
- // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
- // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
- if(NULL != m_pullSurvivedBytes)
- {
- m_pullSurvivedBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += promotedBytes;
- }
- }
-
- inline void ResetSurvivedBytes()
- {
- LIMITED_METHOD_CONTRACT;
-
- // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
- // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
- if(NULL != m_pullSurvivedBytes)
- {
- for (DWORD i = 0; i < m_dwNumHeaps; i++)
- {
- m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
- }
- }
- }
-
- // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far.
- // The result is in 100ns units.
- ULONGLONG QueryProcessorUsage();
-
- // Add to the current count of processor time used by threads within this AppDomain. This API is called by
- // threads transitioning between AppDomains.
- void UpdateProcessorUsage(ULONGLONG ullAdditionalUsage);
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
private:
size_t EstimateSize();
EEClassFactoryInfoHashTable* SetupClassFactHash();
// The thread-pool index of this app domain among existing app domains (starting from 1)
TPIndex m_tpIndex;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- ULONGLONG* m_pullAllocBytes;
- ULONGLONG* m_pullSurvivedBytes;
- DWORD m_dwNumHeaps;
- ULONGLONG m_ullLastEtwAllocBytes;
- // Total processor time (user and kernel) utilized by threads running in this AppDomain so far. May not
- // account for threads currently executing in the AppDomain until a call to QueryProcessorUsage() is
- // made.
- Volatile<ULONGLONG> m_ullTotalProcessorUsage;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
Volatile<Stage> m_Stage;
ArrayList m_failedAssemblies;
#endif // DACCESS_COMPILE
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- // The *AD* methods are what we got from tracing through EE roots.
- // RecordTotalSurvivedBytes is the total promoted from a GC.
- static void ResetADSurvivedBytes();
- static ULONGLONG GetADSurvivedBytes();
- static void RecordTotalSurvivedBytes(size_t totalSurvivedBytes);
- static ULONGLONG GetTotalSurvivedBytes()
- {
- LIMITED_METHOD_CONTRACT;
- return m_totalSurvivedBytes;
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
//****************************************************************************************
// Routines to deal with the base library (currently mscorlib.dll)
LPCWSTR BaseLibrary()
LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- // This is what gets promoted for the whole GC heap.
- static size_t m_totalSurvivedBytes;
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifndef DACCESS_COMPILE
static CrstStatic m_DelayedUnloadCrst;
static CrstStatic m_SystemDomainCrst;
iGCLatencyMode = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GCLatencyMode, iGCLatencyMode);
#endif
- if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ARMEnabled))
- {
- g_fEnableARM = TRUE;
- }
-
bool gcConcurrentWasForced = false;
// The CLRConfig value for UNSUPPORTED_gcConcurrent defaults to -1, and treats any
// positive value as 'forcing' concurrent GC to be on. Because the standard logic
// GetActionOnFailure will notify the host for us.
EPolicyAction action = pPolicy->GetActionOnFailure(FAIL_CodeContract);
Thread* pThread = GetThread();
- AppDomain* pCurrentDomain = ::GetAppDomain();
switch(action) {
case eThrowException:
EX_TRY
{
- BOOL bIsArmRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
- TRACE_LEVEL_INFORMATION,
- CLR_RUNDOWNAPPDOMAINRESOURCEMANAGEMENT_KEYWORD);
BOOL bIsPerfTrackRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
TRACE_LEVEL_INFORMATION,
CLR_RUNDOWNPERFTRACK_KEYWORD);
TRACE_LEVEL_INFORMATION,
CLR_RUNDOWNJITTEDMETHODILTONATIVEMAP_KEYWORD)
||
- bIsArmRundownEnabled
- ||
bIsPerfTrackRundownEnabled
||
bIsThreadingRundownEnabled)
ETW::EnumerationLog::EnumerationHelper(NULL, NULL, enumerationOptions);
- if (bIsArmRundownEnabled)
- {
- // When an ETW event consumer asks for ARM rundown, that not only enables
- // the ETW events, but also causes some minor behavioral changes in the
- // CLR, such as gathering CPU usage baselines for each thread right now,
- // and also gathering resource usage information later on (keyed off of
- // g_fEnableARM, which we'll set right now).
- EnableARM();
- }
-
- if (bIsArmRundownEnabled || bIsThreadingRundownEnabled)
+ if (bIsThreadingRundownEnabled)
{
SendThreadRundownEvent();
}
case RT_ByRef:
LOG((LF_GC, INFO3, "Hijack Frame Carefully Promoting pointer" FMT_ADDR "to",
DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr))));
- PromoteCarefully(fn, objPtr, sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN);
+ PromoteCarefully(fn, objPtr, sc, GC_CALL_INTERIOR);
LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr))));
break;
fn(dac_cast<PTR_PTR_Object>(ppObj), sc, CHECK_APP_DOMAIN);
break;
case GCREFMAP_INTERIOR:
- PromoteCarefully(fn, dac_cast<PTR_PTR_Object>(ppObj), sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN);
+ PromoteCarefully(fn, dac_cast<PTR_PTR_Object>(ppObj), sc, GC_CALL_INTERIOR);
break;
case GCREFMAP_METHOD_PARAM:
if (sc->promotion)
//
// Sanity check that the flags contain only these three values
//
- assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
+ assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED)) == 0);
// for interior pointers, we optimize the case in which
// it points into the current threads stack area
GCCONTEXT *gcctx = (GCCONTEXT*) pData;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- gcctx->sc->pCurrentDomain = pCF->GetAppDomain();
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
MethodDesc *pMD = pCF->GetFunction();
#ifdef GC_PROFILING
EEPOLICY_HANDLE_FATAL_ERROR(exitCode);
}
-bool GCToEEInterface::ShouldFinalizeObjectForUnload(void* pDomain, Object* obj)
-{
- // CoreCLR does not have appdomains, so this code path is dead. Other runtimes may
- // choose to inspect the object being finalized here.
- // [DESKTOP TODO] Desktop looks for "agile and finalizable" objects and may choose
- // to move them to a new app domain instead of finalizing them here.
- return true;
-}
-
bool GCToEEInterface::EagerFinalized(Object* obj)
{
MethodTable* pMT = obj->GetGCSafeMethodTable();
return &g_gcToClrEventSink;
}
-uint32_t GCToEEInterface::GetDefaultDomainIndex()
-{
- LIMITED_METHOD_CONTRACT;
-
- return DefaultADID;
-}
-
-void *GCToEEInterface::GetAppDomainAtIndex(uint32_t appDomainIndex)
-{
- LIMITED_METHOD_CONTRACT;
-
- return ::GetAppDomain();
-}
-
-bool GCToEEInterface::AppDomainCanAccessHandleTable(uint32_t appDomainID)
-{
- LIMITED_METHOD_CONTRACT;
-
- return appDomainID == DefaultADID;
-}
-
-uint32_t GCToEEInterface::GetIndexOfAppDomainBeingUnloaded()
-{
- LIMITED_METHOD_CONTRACT;
-
- return 0xFFFFFFFF;
-}
-
uint32_t GCToEEInterface::GetTotalNumSizedRefHandles()
{
LIMITED_METHOD_CONTRACT;
}
-bool GCToEEInterface::AppDomainIsRudeUnload(void *appDomain)
-{
- LIMITED_METHOD_CONTRACT;
-
- return false;
-}
-
bool GCToEEInterface::AnalyzeSurvivorsRequested(int condemnedGeneration)
{
LIMITED_METHOD_CONTRACT;
void EnableFinalization(bool foundFinalizers);
void HandleFatalError(unsigned int exitCode);
- bool ShouldFinalizeObjectForUnload(void* pDomain, Object* obj);
bool EagerFinalized(Object* obj);
MethodTable* GetFreeObjectMethodTable();
bool GetBooleanConfigValue(const char* key, bool* value);
void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*));
IGCToCLREventSink* EventSink();
- uint32_t GetDefaultDomainIndex();
- void *GetAppDomainAtIndex(uint32_t appDomainIndex);
- bool AppDomainCanAccessHandleTable(uint32_t appDomainID);
- uint32_t GetIndexOfAppDomainBeingUnloaded();
uint32_t GetTotalNumSizedRefHandles();
- bool AppDomainIsRudeUnload(void *appDomain);
bool AnalyzeSurvivorsRequested(int condemnedGeneration);
void AnalyzeSurvivorsFinished(int condemnedGeneration);
#define _tfopen _wfopen
#endif
-// -----------------------------------------------------------------------------------------------------------
-//
-// AppDomain emulation. We don't have these in the CLR anymore so instead we emulate the bare minimum of the API
-// touched by the GC/HandleTable and pretend we have precisely one (default) appdomain.
-//
-
-#define RH_DEFAULT_DOMAIN_ID 1
-
-struct ADIndex
-{
- DWORD m_dwIndex;
-
- ADIndex () : m_dwIndex(RH_DEFAULT_DOMAIN_ID) {}
- explicit ADIndex (DWORD id) : m_dwIndex(id) {}
- BOOL operator==(const ADIndex& ad) const { return m_dwIndex == ad.m_dwIndex; }
- BOOL operator!=(const ADIndex& ad) const { return m_dwIndex != ad.m_dwIndex; }
-};
-
#endif // GCENV_H_
FireEtwGCFullNotify_V1(genNumber, isAlloc, GetClrInstanceId());
}
-void GCToCLREventSink::FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID)
+void GCToCLREventSink::FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation)
{
- FireEtwSetGCHandle(handleID, objectID, kind, generation, appDomainID, GetClrInstanceId());
+ FireEtwSetGCHandle(handleID, objectID, kind, generation, (uint64_t)dac_cast<TADDR>(AppDomain::GetCurrentDomain()), GetClrInstanceId());
}
-void GCToCLREventSink::FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID)
+void GCToCLREventSink::FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation)
{
- FireEtwPrvSetGCHandle(handleID, objectID, kind, generation, appDomainID, GetClrInstanceId());
+ FireEtwPrvSetGCHandle(handleID, objectID, kind, generation, (uint64_t)dac_cast<TADDR>(AppDomain::GetCurrentDomain()), GetClrInstanceId());
}
void GCToCLREventSink::FireDestroyGCHandle(void *handleID)
void FireBGCAllocWaitBegin(uint32_t reason);
void FireBGCAllocWaitEnd(uint32_t reason);
void FireGCFullNotify_V1(uint32_t genNumber, uint32_t isAlloc);
- void FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID);
- void FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID);
+ void FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation);
+ void FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation);
void FireDestroyGCHandle(void *handleID);
void FirePrvDestroyGCHandle(void *handleID);
};
//
// Sanity check that the flags contain only these three values
//
- assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
+ assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED)) == 0);
//
// Sanity check that GC_CALL_INTERIOR FLAG is set
#ifdef _DEBUG
pOldLocation = *pArgPtr;
#endif
- (*fn)(pArgPtr, sc, GC_CALL_CHECK_APP_DOMAIN );
+ (*fn)(pArgPtr, sc, 0 );
// !!! Do not cast to (OBJECTREF*)
// !!! If we are in the relocate phase, we may have updated root,
pOldLocation = *pArgPtr;
#endif
- (*fnc)(fn, pArgPtr, sc, GC_CALL_INTERIOR|GC_CALL_CHECK_APP_DOMAIN);
+ (*fnc)(fn, pArgPtr, sc, GC_CALL_INTERIOR);
// !!! Do not cast to (OBJECTREF*)
// !!! If we are in the relocate phase, we may have updated root,
FastInterlockOr((ULONG *) &pThread->m_State, Thread::TS_TPWorkerThread);
}
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- pThread->QueryThreadProcessorUsage();
- }
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifdef FEATURE_EVENT_TRACE
ETW::ThreadLog::FireThreadCreated(pThread);
#endif // FEATURE_EVENT_TRACE
_ASSERTE(g_fEEShutDown || th->m_dwLockCount == 0 || th->m_fRudeAborted);
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- AppDomain* pDomain = th->GetDomain();
- pDomain->UpdateProcessorUsage(th->QueryThreadProcessorUsage());
- FireEtwThreadTerminated((ULONGLONG)th, (ULONGLONG)pDomain, GetClrInstanceId());
- }
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
th->FinishSOWork();
GCX_PREEMP_NO_DTOR();
_ASSERTE (this == GetThread());
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM && m_pDomain)
- {
- m_pDomain->UpdateProcessorUsage(QueryThreadProcessorUsage());
- FireEtwThreadTerminated((ULONGLONG)this, (ULONGLONG)m_pDomain, GetClrInstanceId());
- }
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
FinishSOWork();
FastInterlockIncrement(&Thread::m_DetachCount);
contextHolder.SuppressRelease();
savedRedirectContextHolder.SuppressRelease();
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- m_ullProcessorUsageBaseline = 0;
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
#ifdef FEATURE_COMINTEROP
m_uliInitializeSpyCookie.QuadPart = 0ul;
m_fInitializeSpyRegistered = false;
ThreadStore::TransferStartedThread(this, bRequiresTSL);
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- QueryThreadProcessorUsage();
- }
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
#ifdef FEATURE_EVENT_TRACE
ETW::ThreadLog::FireThreadCreated(this);
#endif // FEATURE_EVENT_TRACE
#endif // #ifdef DACCESS_COMPILE
-
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
-// For the purposes of tracking resource usage we implement a simple cpu resource usage counter on each
-// thread. Every time QueryThreadProcessorUsage() is invoked it returns the amount of cpu time (a combination
-// of user and kernel mode time) used since the last call to QueryThreadProcessorUsage(). The result is in 100
-// nanosecond units.
-ULONGLONG Thread::QueryThreadProcessorUsage()
-{
- LIMITED_METHOD_CONTRACT;
-
- // Get current values for the amount of kernel and user time used by this thread over its entire lifetime.
- FILETIME sCreationTime, sExitTime, sKernelTime, sUserTime;
- HANDLE hThread = GetThreadHandle();
- BOOL fResult = GetThreadTimes(hThread,
- &sCreationTime,
- &sExitTime,
- &sKernelTime,
- &sUserTime);
- if (!fResult)
- {
-#ifdef _DEBUG
- ULONG error = GetLastError();
- printf("GetThreadTimes failed: %d; handle is %p\n", error, hThread);
- _ASSERTE(FALSE);
-#endif
- return 0;
- }
-
- // Combine the user and kernel times into a single value (FILETIME is just a structure representing an
- // unsigned int64 in two 32-bit pieces).
- _ASSERTE(sizeof(FILETIME) == sizeof(UINT64));
- ULONGLONG ullCurrentUsage = *(ULONGLONG*)&sKernelTime + *(ULONGLONG*)&sUserTime;
-
- // Store the current processor usage as the new baseline, and retrieve the previous usage.
- ULONGLONG ullPreviousUsage = VolatileLoad(&m_ullProcessorUsageBaseline);
- if (ullPreviousUsage >= ullCurrentUsage ||
- ullPreviousUsage != (ULONGLONG)InterlockedCompareExchange64(
- (LONGLONG*)&m_ullProcessorUsageBaseline,
- (LONGLONG)ullCurrentUsage,
- (LONGLONG)ullPreviousUsage))
- {
- // another thread beat us to it, and already reported this usage.
- return 0;
- }
-
- // The result is the difference between this value and the previous usage value.
- return ullCurrentUsage - ullPreviousUsage;
-}
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
OBJECTHANDLE Thread::GetOrCreateDeserializationTracker()
{
CONTRACTL
// Holds per-thread information the debugger uses to expose locking information
// See ThreadDebugBlockingInfo.h for more details
ThreadDebugBlockingInfo DebugBlockingInfo;
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- // For the purposes of tracking resource usage we implement a simple cpu resource usage counter on each
- // thread. Every time QueryThreadProcessorUsage() is invoked it returns the amount of cpu time (a
- // combination of user and kernel mode time) used since the last call to QueryThreadProcessorUsage(). The
- // result is in 100 nanosecond units.
- ULONGLONG QueryThreadProcessorUsage();
private:
- // The amount of processor time (both user and kernel) in 100ns units used by this thread at the time of
- // the last call to QueryThreadProcessorUsage().
- ULONGLONG m_ullProcessorUsageBaseline;
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
// Disables pumping and thread join in RCW creation
bool m_fDisableComObjectEagerCleanup;
// See ThreadStore::TriggerGCForDeadThreadsIfNecessary()
bool m_fHasDeadThreadBeenConsideredForGCTrigger;
-private:
CLRRandom m_random;
public:
}
#endif
-BOOL EnableARM()
-{
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- CONTRACTL
- {
- NOTHROW;
- // TODO: this should really be GC_TRIGGERS so we wouldn't need the
- // CONTRACT_VIOLATION below but the hosting API that calls this
- // can be called on a COOP thread and it has a GC_NOTRIGGER contract.
- // We should use the AD unload thread to call this function on.
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- BOOL fARMEnabled = g_fEnableARM;
-
- if (!fARMEnabled)
- {
- if (ThreadStore::s_pThreadStore)
- {
- // We need to establish the baselines for the CPU usage counting.
- Thread *pThread = NULL;
- CONTRACT_VIOLATION(GCViolation);
-
- // Take the thread store lock while we enumerate threads.
- ThreadStoreLockHolder tsl ;
-
- while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
- {
- if (pThread->IsUnstarted() || pThread->IsDead())
- continue;
- pThread->QueryThreadProcessorUsage();
- }
- }
- g_fEnableARM = TRUE;
- }
-
- return fARMEnabled;
-#else // FEATURE_APPDOMAIN_RESOURCE_MONITORING
- return FALSE;
-#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-}
-
#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);
-#ifndef DACCESS_COMPILE
-// returns if ARM was already enabled or not.
-BOOL EnableARM();
-#endif // !DACCESS_COMPILE
-
int GetRandomInt(int maxVal);
//
BOOL g_fEnableETW = FALSE;
-BOOL g_fEnableARM = FALSE;
-
//
// Global state variable indicating if the EE is in its init phase.
//
#endif
extern BOOL g_fEnableETW;
-extern BOOL g_fEnableARM;
// Returns a BOOL to indicate if the runtime is active or not
BOOL IsRuntimeActive();