Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / corlib / System.Collections.Concurrent / ObjectPool.cs
index 2abfa2022ab8bf7a0971a2f903b752e041f16cd3..853953ba4922187573505f88c735ca5c1e1673f2 100644 (file)
@@ -37,7 +37,12 @@ namespace System.Collections.Concurrent
 {
        internal abstract class ObjectPool<T> where T : class
        {
+               // This is the number of objects we are going to cache
                const int capacity = 20;
+               /* We use this bit in addIndex to synchronize the array and the index itself
+                * Namely when we update addIndex we also set that bit for the time the value
+                * in the array hasn't still been updated to the object we are returning to the cache
+                */
                const int bit = 0x8000000;
 
                readonly T[] buffer;
@@ -52,22 +57,28 @@ namespace System.Collections.Concurrent
                        addIndex = capacity - 1;
                }
 
+               /* Code that want to use a pool subclass it and
+                * implement that method. In most case 'new T ()'.
+                */
                protected abstract T Creator ();
 
                public T Take ()
                {
+                       // If no element in the cache, we return a new object
                        if ((addIndex & ~bit) - 1 == removeIndex)
                                return Creator ();
 
                        int i;
                        T result;
+                       int tries = 3;
 
                        do {
                                i = removeIndex;
-                               if ((addIndex & ~bit) - 1 == i)
+                               // We return a new element when looping becomes too costly
+                               if ((addIndex & ~bit) - 1 == i || tries == 0)
                                        return Creator ();
                                result = buffer[i % capacity];
-                       } while (Interlocked.CompareExchange (ref removeIndex, i + 1, i) != i);
+                       } while (Interlocked.CompareExchange (ref removeIndex, i + 1, i) != i && --tries > -1);
 
                        return result;
                }
@@ -80,14 +91,19 @@ namespace System.Collections.Concurrent
                        int i;
                        int tries = 3;
                        do {
+                               // While an array update is ongoing (i.e. an extra write op) we loop
                                do {
                                        i = addIndex;
                                } while ((i & bit) > 0);
-                               if (i - removeIndex >= capacity - 1)
+                               // If no more room or too busy just forget about the object altogether
+                               if (i - removeIndex >= capacity - 1 || tries == 0)
                                        return;
-                       } while (Interlocked.CompareExchange (ref addIndex, i + 1 + bit, i) != i && --tries > 0);
+                               // We update addIndex and notify that we are going to set buffer correctly
+                       } while (Interlocked.CompareExchange (ref addIndex, i + 1 + bit, i) != i && --tries > -1);
 
                        buffer[i % capacity] = obj;
+                       Thread.MemoryBarrier ();
+                       // Since bit essentialy acts like a lock, we simply use an atomic read/write combo
                        addIndex = addIndex - bit;
                }
        }