public static void Release(CctorHandle cctor) { using (LockHolder.Hold(s_cctorGlobalLock)) { Cctor[] cctors = cctor.Array; int cctorIndex = cctor.Index; if (0 == Interlocked.Decrement(ref cctors[cctorIndex]._refCount)) { if (cctors[cctorIndex].Exception == null) { cctors[cctorIndex] = new Cctor(); s_count--; } } } }
public static void Release(CctorHandle cctor) { s_cctorGlobalLock.Acquire(); try { Cctor[] cctors = cctor.Array; int cctorIndex = cctor.Index; if (0 == Interlocked.Decrement(ref cctors[cctorIndex]._refCount)) { if (cctors[cctorIndex].Exception == null) { cctors[cctorIndex] = new Cctor(); s_count--; } } } finally { s_cctorGlobalLock.Release(); } }
public CctorHandle(Cctor[] array, int index) { _array = array; _index = index; }
//========================================================================================================== // 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(); } }
public static unsafe void EnsureClassConstructorRun(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; } 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); ((delegate * < void >)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); }
//========================================================================================================== // 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 // WASMTODO: Remove this when the Initialize method gets called by the runtime startup #if TARGET_WASM if (s_cctorGlobalLock == null) { Interlocked.CompareExchange(ref s_cctorGlobalLock, new Lock(), null); } if (s_cctorArrays == null) { Interlocked.CompareExchange(ref s_cctorArrays, new Cctor[10][], null); } #endif // TARGET_WASM using (LockHolder.Hold(s_cctorGlobalLock)) { 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)); } }
//========================================================================================================== // 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(); } }