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);
 }
示例#2
0
        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);
        }
示例#3
0
 private unsafe static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase)
 {
     CheckStaticClassConstruction(ref context);
     return(nonGcStaticBase);
 }
示例#4
0
 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();
                }
            }
示例#7
0
 private unsafe static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext* context, IntPtr nonGcStaticBase)
 {
     EnsureClassConstructorRun(context);
     return nonGcStaticBase;
 }
示例#8
0
 private unsafe static object CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext* context, object gcStaticBase)
 {
     EnsureClassConstructorRun(context);
     return gcStaticBase;
 }
示例#9
0
 public static unsafe void* CheckStaticClassConstruction(void* returnValue, StaticClassConstructionContext* pContext)
 {
     EnsureClassConstructorRun(pContext);
     return returnValue;
 }
示例#10
0
 private unsafe static object CheckStaticClassConstructionReturnThreadStaticBase(TypeManagerSlot* pModuleData, Int32 typeTlsIndex, StaticClassConstructionContext* context)
 {
     object threadStaticBase = ThreadStatics.GetThreadStaticBaseForType(pModuleData, typeTlsIndex);
     EnsureClassConstructorRun(context);
     return threadStaticBase;
 }
示例#11
0
 private static unsafe IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase)
 {
     EnsureClassConstructorRun(ref context);
     return(nonGcStaticBase);
 }