private static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase) { // CORERT-TODO: Early out if initializer was set to anything. The runner doesn't handle recursion and assumes it's access from // a different thread and deadlocks itself. CoreRT will cause recursion for things like trying to get a static // base from the CCtor (which means that pretty much all cctors will deadlock). if (context.initialized == 0) { CheckStaticClassConstruction(ref context); } return(nonGcStaticBase); }
private static unsafe void CheckStaticClassConstruction(ref StaticClassConstructionContext context) { // Very simplified class constructor runner. In real world, the class constructor runner // would need to be able to deal with potentially multiple threads racing to initialize // a single class, and would need to be able to deal with potential deadlocks // between class constructors. if (context.initialized == 1) { return; } context.initialized = 1; // Run the class constructor. Call <int>(context.cctorMethodAddress); }
private unsafe static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase) { CheckStaticClassConstruction(ref context); return(nonGcStaticBase); }
private unsafe static object CheckStaticClassConstructionReturnGCStaticBase(ref StaticClassConstructionContext context, object gcStaticBase) { CheckStaticClassConstruction(ref context); return(gcStaticBase); }
public static unsafe void* EnsureClassConstructorRun(void* returnValue, StaticClassConstructionContext* pContext) { IntPtr pfnCctor = pContext->cctorMethodAddress; NoisyLog("EnsureClassConstructorRun, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); // If we were called from MRT, this check is redundant but harmless. This is in case someone within classlib // (cough, Reflection) needs to call this explicitly. if (pContext->initialized == 1) { NoisyLog("Cctor already run, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); return returnValue; } CctorHandle cctor = Cctor.GetCctor(pContext); Cctor[] cctors = cctor.Array; int cctorIndex = cctor.Index; try { Lock cctorLock = cctors[cctorIndex].Lock; if (DeadlockAwareAcquire(cctor, pfnCctor)) { int currentManagedThreadId = CurrentManagedThreadId; try { NoisyLog("Acquired cctor lock, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId); cctors[cctorIndex].HoldingThread = currentManagedThreadId; if (pContext->initialized == 0) // Check again in case some thread raced us while we were acquiring the lock. { TypeInitializationException priorException = cctors[cctorIndex].Exception; if (priorException != null) throw priorException; try { NoisyLog("Calling cctor, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId); Call<int>(pfnCctor); // Insert a memory barrier here to order any writes executed as part of static class // construction above with respect to the initialized flag update we're about to make // below. This is important since the fast path for checking the cctor uses a normal read // and doesn't come here so without the barrier it could observe initialized == 1 but // still see uninitialized static fields on the class. Interlocked.MemoryBarrier(); NoisyLog("Set type inited, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId); pContext->initialized = 1; } catch (Exception e) { TypeInitializationException wrappedException = new TypeInitializationException(null, SR.TypeInitialization_Type_NoTypeAvailable, e); cctors[cctorIndex].Exception = wrappedException; throw wrappedException; } } } finally { cctors[cctorIndex].HoldingThread = ManagedThreadIdNone; NoisyLog("Releasing cctor lock, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId); cctorLock.Release(); } } else { // Cctor cycle resulted in a deadlock. We will break the guarantee and return without running the // .cctor. } } finally { Cctor.Release(cctor); } NoisyLog("EnsureClassConstructorRun complete, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); return returnValue; }
//========================================================================================================== // Gets the Cctor entry associated with a specific class constructor context (creating it if necessary.) //========================================================================================================== public static CctorHandle GetCctor(StaticClassConstructionContext* pContext) { #if DEBUG const int Grow = 2; #else const int Grow = 10; #endif s_cctorGlobalLock.Acquire(); try { Cctor[] resultArray = null; int resultIndex = -1; if (s_count != 0) { // Search for the cctor context in our existing arrays for (int cctorIndex = 0; cctorIndex < s_cctorArraysCount; ++cctorIndex) { Cctor[] segment = s_cctorArrays[cctorIndex]; for (int i = 0; i < segment.Length; i++) { if (segment[i]._pContext == pContext) { resultArray = segment; resultIndex = i; break; } } if (resultArray != null) break; } } if (resultArray == null) { // look for an empty entry in an existing array for (int cctorIndex = 0; cctorIndex < s_cctorArraysCount; ++cctorIndex) { Cctor[] segment = s_cctorArrays[cctorIndex]; for (int i = 0; i < segment.Length; i++) { if (segment[i]._pContext == default(StaticClassConstructionContext*)) { resultArray = segment; resultIndex = i; break; } } if (resultArray != null) break; } if (resultArray == null) { // allocate a new array resultArray = new Cctor[Grow]; if (s_cctorArraysCount == s_cctorArrays.Length) { // grow the container Array.Resize(ref s_cctorArrays, (s_cctorArrays.Length * 2) + 1); } // store the array in the container, this cctor gets index 0 s_cctorArrays[s_cctorArraysCount] = resultArray; s_cctorArraysCount++; resultIndex = 0; } Debug.Assert(resultArray[resultIndex]._pContext == default(StaticClassConstructionContext*)); resultArray[resultIndex]._pContext = pContext; resultArray[resultIndex].Lock = new Lock(); s_count++; } Interlocked.Increment(ref resultArray[resultIndex]._refCount); return new CctorHandle(resultArray, resultIndex); } finally { s_cctorGlobalLock.Release(); } }
private unsafe static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext* context, IntPtr nonGcStaticBase) { EnsureClassConstructorRun(context); return nonGcStaticBase; }
private unsafe static object CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext* context, object gcStaticBase) { EnsureClassConstructorRun(context); return gcStaticBase; }
public static unsafe void* CheckStaticClassConstruction(void* returnValue, StaticClassConstructionContext* pContext) { EnsureClassConstructorRun(pContext); return returnValue; }
private unsafe static object CheckStaticClassConstructionReturnThreadStaticBase(TypeManagerSlot* pModuleData, Int32 typeTlsIndex, StaticClassConstructionContext* context) { object threadStaticBase = ThreadStatics.GetThreadStaticBaseForType(pModuleData, typeTlsIndex); EnsureClassConstructorRun(context); return threadStaticBase; }
private static unsafe IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase) { EnsureClassConstructorRun(ref context); return(nonGcStaticBase); }