Beispiel #1
0
 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;
 }
 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();
     }
 }
            //==========================================================================================================
            // 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();
                }
            }
Beispiel #6
0
        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);
        }
Beispiel #7
0
            //==========================================================================================================
            // 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));
                }
            }
 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--;
             }
         }
     }
 }
            //==========================================================================================================
            // 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();
                }
            }