예제 #1
0
        public void MultipleReleaseAtDifferentThreadTest()
        {
            ThreadLocalPool <HandledObject> pool = NewPool(1024);
            HandledObject obj = pool.Take();

            Thread thread = new Thread(() =>
            {
                obj.Release();
            });

            thread.Start();
            thread.Join();

            ExceptionDispatchInfo exceptionDispatchInfo = null;
            Thread thread2 = new Thread(() =>
            {
                try
                {
                    obj.Release();
                }
                catch (Exception ex)
                {
                    Interlocked.Exchange(ref exceptionDispatchInfo, ExceptionDispatchInfo.Capture(ex));
                }
            });

            thread2.Start();
            thread2.Join();
            var exception = Assert.ThrowsAny <InvalidOperationException>(() => Volatile.Read(ref exceptionDispatchInfo)?.Throw());

            Assert.True(exception != null);
        }
예제 #2
0
        public void MultipleReleaseTest()
        {
            ThreadLocalPool <HandledObject> pool = NewPool(1024);
            HandledObject obj = pool.Take();

            obj.Release();
            var exception = Assert.ThrowsAny <InvalidOperationException>(() => obj.Release());

            Assert.True(exception != null);
        }
예제 #3
0
        public void ReleaseDisableTest()
        {
            ThreadLocalPool <HandledObject> pool = NewPool(-1);
            HandledObject obj = pool.Take();

            obj.Release();
            HandledObject obj2 = pool.Take();

            Assert.NotSame(obj, obj2);
            obj2.Release();
        }
예제 #4
0
        public void DiscardingExceedingElementsWithReleaseAtDifferentThreadTest()
        {
            int maxCapacity    = 32;
            int instancesCount = 0;

            ThreadLocalPool <HandledObject> pool = new ThreadLocalPool <HandledObject>(handle =>
            {
                Interlocked.Increment(ref instancesCount);
                return(new HandledObject(handle));
            }, maxCapacity, 2);

            // Borrow 2 * maxCapacity objects.
            HandledObject[] array = new HandledObject[maxCapacity * 2];
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = pool.Take();
            }

            Assert.Equal(array.Length, Volatile.Read(ref instancesCount));
            // Reset counter.
            Interlocked.Exchange(ref instancesCount, 0);

            // Release from other thread.
            Thread thread = new Thread(() =>
            {
                for (int i = 0; i < array.Length; i++)
                {
                    array[i].Release();
                }
            });

            thread.Start();
            thread.Join();

            Assert.Equal(0, Volatile.Read(ref instancesCount));

            // Borrow 2 * maxCapacity objects. Half of them should come from
            // the recycler queue, the other half should be freshly allocated.
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = pool.Take();
            }

            // The implementation uses maxCapacity / 2 as limit per WeakOrderQueue
            Assert.True(array.Length - maxCapacity / 2 <= Volatile.Read(ref instancesCount),
                        "The instances count (" + Volatile.Read(ref instancesCount) + ") must be <= array.length (" + array.Length
                        + ") - maxCapacity (" + maxCapacity + ") / 2 as we not pool all new handles" +
                        " internally");
        }
예제 #5
0
        public void ThreadCanBeCollectedEvenIfHandledObjectIsReferencedTest()
        {
            ThreadLocalPool <HandledObject> pool = NewPool(1024);
            HandledObject           reference    = null;
            WeakReference <Thread>  threadRef    = null;
            WeakReference <XThread> xThreadRef   = null;

            var thread1 = new Thread(() =>
            {
                //Don't know the reason, but thread2 will not be collected without wrapped with thread1
                var thread2 = new Thread(() =>
                {
                    Interlocked.Exchange(ref xThreadRef, new WeakReference <XThread>(XThread.CurrentThread));
                    HandledObject data = pool.Take();
                    // Store a reference to the HandledObject to ensure it is not collected when the run method finish.
                    Interlocked.Exchange(ref reference, data);
                });
                Interlocked.Exchange(ref threadRef, new WeakReference <Thread>(thread2));
                thread2.Start();
                thread2.Join();
                Assert.True(Volatile.Read(ref threadRef)?.TryGetTarget(out _));
                Assert.True(Volatile.Read(ref xThreadRef)?.TryGetTarget(out _));

                GC.KeepAlive(thread2);
                // Null out so it can be collected.
                thread2 = null;
            });

            thread1.Start();
            thread1.Join();

            for (int i = 0; i < 5; ++i)
            {
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
                GC.WaitForPendingFinalizers();

                if (Volatile.Read(ref threadRef)?.TryGetTarget(out _) == true || Volatile.Read(ref xThreadRef)?.TryGetTarget(out _) == true)
                {
                    Thread.Sleep(100);
                }
            }

            Assert.False(Volatile.Read(ref threadRef)?.TryGetTarget(out _));
            Assert.False(Volatile.Read(ref xThreadRef)?.TryGetTarget(out _));

            // Now call recycle after the Thread was collected to ensure this still works...
            reference.Release();
            reference = null;
        }
예제 #6
0
        public void RecycleDisableDrop()
        {
            ThreadLocalPool <HandledObject> recycler = NewPool(1024, 2, 0, 2, 0);
            HandledObject obj = recycler.Take();

            obj.Release();
            HandledObject obj2 = recycler.Take();

            Assert.Same(obj, obj2);
            obj2.Release();
            HandledObject obj3 = recycler.Take();

            Assert.Same(obj, obj3);
            obj3.Release();
        }
예제 #7
0
        public void RecycleDisableDelayedQueueDrop()
        {
            ThreadLocalPool <HandledObject> recycler = NewPool(1024, 2, 1, 2, 0);
            HandledObject o  = recycler.Take();
            HandledObject o2 = recycler.Take();
            HandledObject o3 = recycler.Take();

            Task.Run(() =>
            {
                o.Release();
                o2.Release();
                o3.Release();
            }).Wait();
            // In reverse order
            Assert.Same(o3, recycler.Take());
            Assert.Same(o, recycler.Take());
        }
예제 #8
0
        public void ReleaseAtDifferentThreadTest()
        {
            ThreadLocalPool <HandledObject> pool = NewPool(256, 10, 2, 10, 2);

            HandledObject obj    = pool.Take();
            HandledObject obj2   = pool.Take();
            Thread        thread = new Thread(() =>
            {
                obj.Release();
                obj2.Release();
            });

            thread.Start();
            thread.Join();

            Assert.Same(pool.Take(), obj);
            Assert.NotSame(pool.Take(), obj2);
        }
        void MaxCapacityTest0(int maxCapacity)
        {
            var recycler = new ThreadLocalPool <HandledObject>(handle => new HandledObject(handle), maxCapacity);

            var objects = new HandledObject[maxCapacity * 3];

            for (int i = 0; i < objects.Length; i++)
            {
                objects[i] = recycler.Take();
            }

            for (int i = 0; i < objects.Length; i++)
            {
                objects[i].Release();
                objects[i] = null;
            }
            Assert.Equal(maxCapacity, recycler.ThreadLocalCapacity);
        }
예제 #10
0
        public void MaxCapacityWithReleaseAtDifferentThreadTest()
        {
            const int maxCapacity = 4; // Choose the number smaller than WeakOrderQueue.LINK_CAPACITY
            var       pool        = NewPool(maxCapacity);

            // Borrow 2 * maxCapacity objects.
            // Return the half from the same thread.
            // Return the other half from the different thread.

            var array = new HandledObject[maxCapacity * 3];

            for (int i = 0; i < array.Length; i++)
            {
                array[i] = pool.Take();
            }

            for (int i = 0; i < maxCapacity; i++)
            {
                array[i].Release();
            }

            Thread thread = new Thread(() =>
            {
                for (int i = maxCapacity; i < array.Length; i++)
                {
                    array[i].Release();
                }
            });

            thread.Start();
            thread.Join();

            Assert.Equal(maxCapacity, pool.ThreadLocalCapacity);
            Assert.Equal(1, pool.ThreadLocalSize);

            for (int i = 0; i < array.Length; i++)
            {
                pool.Take();
            }

            Assert.Equal(maxCapacity, pool.ThreadLocalCapacity);
            Assert.Equal(0, pool.ThreadLocalSize);
        }
예제 #11
0
        static void MaxCapacityTest0(int maxCapacity)
        {
            var recycler = NewPool(maxCapacity);

            var objects = new HandledObject[maxCapacity * 3];

            for (int i = 0; i < objects.Length; i++)
            {
                objects[i] = recycler.Take();
            }

            for (int i = 0; i < objects.Length; i++)
            {
                objects[i].Release();
                objects[i] = null;
            }
            Assert.True(maxCapacity >= recycler.ThreadLocalCapacity,
                        "The threadLocalCapacity (" + recycler.ThreadLocalCapacity + ") must be <= maxCapacity ("
                        + maxCapacity + ") as we not pool all new handles internally");
        }
        public void MaxCapacityWithRecycleAtDifferentThreadTest()
        {
            const int maxCapacity = 4; // Choose the number smaller than WeakOrderQueue.LINK_CAPACITY
            var       recycler    = new ThreadLocalPool <HandledObject>(handle => new HandledObject(handle), maxCapacity);

            // Borrow 2 * maxCapacity objects.
            // Return the half from the same thread.
            // Return the other half from the different thread.

            var array = new HandledObject[maxCapacity * 3];

            for (int i = 0; i < array.Length; i++)
            {
                array[i] = recycler.Take();
            }

            for (int i = 0; i < maxCapacity; i++)
            {
                array[i].Release();
            }

            Task.Run(() =>
            {
                for (int i = maxCapacity; i < array.Length; i++)
                {
                    array[i].Release();
                }
            }).Wait();

            Assert.Equal(recycler.ThreadLocalCapacity, maxCapacity);
            Assert.Equal(recycler.ThreadLocalSize, maxCapacity);

            for (int i = 0; i < array.Length; i++)
            {
                recycler.Take();
            }

            Assert.Equal(maxCapacity, recycler.ThreadLocalCapacity);
            Assert.Equal(0, recycler.ThreadLocalSize);
        }
예제 #13
0
        /// <inheritdoc/>
        protected internal override void PostInput()
        {
            if (activeHandle != null)
            {
                if (activeHandle.IsDragged())
                {
                    if (!isDragged)
                    {
                        isDragged = true;

                        SceneObject[] selectedSceneObjects = Selection.SceneObjects;
                        activeSelection = new HandledObject[selectedSceneObjects.Length];
                        for (int i = 0; i < selectedSceneObjects.Length; i++)
                            activeSelection[i] = new HandledObject(selectedSceneObjects[i]);

                        initialHandlePosition = activeHandle.Position;
                        initialHandleRotation = activeHandle.Rotation;
                    }
                }
                else
                {
                    isDragged = false;
                    activeSelection = null;
                }

                activeHandle.PostInput();

                if (activeHandle.IsDragged())
                {
                    switch (activeHandleType)
                    {
                        case SceneViewTool.Move:
                            MoveHandle moveHandle = (MoveHandle) activeHandle;

                            foreach (var selectedObj in activeSelection)
                                selectedObj.so.LocalPosition = selectedObj.initialPosition + moveHandle.Delta;

                            break;
                        case SceneViewTool.Rotate:
                        {
                            RotateHandle rotateHandle = (RotateHandle) activeHandle;

                            // Make sure we transform relative to the handle position
                            SceneObject temporarySO = new SceneObject("Temp");
                            temporarySO.Position = initialHandlePosition;
                            temporarySO.LocalRotation = initialHandleRotation;

                            SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                            for (int i = 0; i < activeSelection.Length; i++)
                            {
                                originalParents[i] = activeSelection[i].so.Parent;
                                activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                                activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                                activeSelection[i].so.Parent = temporarySO;
                            }

                            temporarySO.LocalRotation *= rotateHandle.Delta;

                            for (int i = 0; i < activeSelection.Length; i++)
                                activeSelection[i].so.Parent = originalParents[i];

                            temporarySO.Destroy();
                        }
                            break;
                        case SceneViewTool.Scale:
                        {
                            ScaleHandle scaleHandle = (ScaleHandle) activeHandle;

                            // Make sure we transform relative to the handle position
                            SceneObject temporarySO = new SceneObject("Temp");
                            temporarySO.Position = activeHandle.Position;

                            SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                            for (int i = 0; i < activeSelection.Length; i++)
                            {
                                originalParents[i] = activeSelection[i].so.Parent;
                                activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                                activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                                activeSelection[i].so.LocalScale = activeSelection[i].initialScale;
                                activeSelection[i].so.Parent = temporarySO;
                            }

                            temporarySO.LocalScale += scaleHandle.Delta;

                            for (int i = 0; i < activeSelection.Length; i++)
                                activeSelection[i].so.Parent = originalParents[i];

                            temporarySO.Destroy();
                        }
                            break;
                    }

                    EditorApplication.SetSceneDirty();
                }
            }
            else
            {
                isDragged = false;
                activeSelection = null;
            }
        }
예제 #14
0
        /// <inheritdoc/>
        protected internal override void PostInput()
        {
            if (activeHandle != null)
            {
                if (activeHandle.IsDragged())
                {
                    if (!isDragged)
                    {
                        isDragged = true;

                        SceneObject[] selectedSceneObjects = Selection.SceneObjects;
                        activeSelection = new HandledObject[selectedSceneObjects.Length];
                        for (int i = 0; i < selectedSceneObjects.Length; i++)
                        {
                            activeSelection[i] = new HandledObject(selectedSceneObjects[i]);
                        }

                        initialHandlePosition = activeHandle.Position;
                        initialHandleRotation = activeHandle.Rotation;
                    }
                }
                else
                {
                    isDragged       = false;
                    activeSelection = null;
                }

                activeHandle.PostInput();

                if (activeHandle.IsDragged())
                {
                    switch (activeHandleType)
                    {
                    case SceneViewTool.Move:
                        MoveHandle moveHandle = (MoveHandle)activeHandle;

                        foreach (var selectedObj in activeSelection)
                        {
                            selectedObj.so.LocalPosition = selectedObj.initialPosition + moveHandle.Delta;
                        }

                        break;

                    case SceneViewTool.Rotate:
                    {
                        RotateHandle rotateHandle = (RotateHandle)activeHandle;

                        // Make sure we transform relative to the handle position
                        SceneObject temporarySO = new SceneObject("Temp");
                        temporarySO.Position      = initialHandlePosition;
                        temporarySO.LocalRotation = initialHandleRotation;

                        SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            originalParents[i] = activeSelection[i].so.Parent;
                            activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                            activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                            activeSelection[i].so.Parent        = temporarySO;
                        }

                        temporarySO.LocalRotation *= rotateHandle.Delta;

                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            activeSelection[i].so.Parent = originalParents[i];
                        }

                        temporarySO.Destroy();
                    }
                    break;

                    case SceneViewTool.Scale:
                    {
                        ScaleHandle scaleHandle = (ScaleHandle)activeHandle;

                        // Make sure we transform relative to the handle position
                        SceneObject temporarySO = new SceneObject("Temp");
                        temporarySO.Position = activeHandle.Position;

                        SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            originalParents[i] = activeSelection[i].so.Parent;
                            activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                            activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                            activeSelection[i].so.LocalScale    = activeSelection[i].initialScale;
                            activeSelection[i].so.Parent        = temporarySO;
                        }

                        temporarySO.LocalScale += scaleHandle.Delta;

                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            activeSelection[i].so.Parent = originalParents[i];
                        }

                        temporarySO.Destroy();
                    }
                    break;
                    }

                    EditorApplication.SetSceneDirty();
                }
            }
            else
            {
                isDragged       = false;
                activeSelection = null;
            }
        }
예제 #15
0
        public void MaxCapacityWithRecycleAtDifferentThreadTest()
        {
            const int maxCapacity = 4; // Choose the number smaller than WeakOrderQueue.LINK_CAPACITY
            var recycler = new ThreadLocalPool<HandledObject>(handle => new HandledObject(handle), maxCapacity);

            // Borrow 2 * maxCapacity objects.
            // Return the half from the same thread.
            // Return the other half from the different thread.

            var array = new HandledObject[maxCapacity * 3];
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = recycler.Take();
            }

            for (int i = 0; i < maxCapacity; i++)
            {
                array[i].Release();
            }

            Task.Run(() =>
            {
                for (int i = maxCapacity; i < array.Length; i++)
                {
                    array[i].Release();
                }
            }).Wait();

            Assert.Equal(recycler.ThreadLocalCapacity, maxCapacity);
            Assert.Equal(recycler.ThreadLocalSize, maxCapacity);

            for (int i = 0; i < array.Length; i++)
            {
                recycler.Take();
            }

            Assert.Equal(maxCapacity, recycler.ThreadLocalCapacity);
            Assert.Equal(0, recycler.ThreadLocalSize);
        }
예제 #16
0
        void MaxCapacityTest(int maxCapacity)
        {
            var recycler = new ThreadLocalPool<HandledObject>(handle => new HandledObject(handle), maxCapacity);

            var objects = new HandledObject[maxCapacity * 3];
            for (int i = 0; i < objects.Length; i++)
            {
                objects[i] = recycler.Take();
            }

            for (int i = 0; i < objects.Length; i++)
            {
                objects[i].Release();
                objects[i] = null;
            }
            Assert.Equal(maxCapacity, recycler.ThreadLocalCapacity);
        }
예제 #17
0
        /// <inheritdoc/>
        protected internal override void PostInput()
        {
            if (activeHandle != null)
            {
                if (activeHandle.IsDragged())
                {
                    if (!isDragged)
                    {
                        isDragged = true;

                        SceneObject[] selectedSceneObjects = Selection.SceneObjects;
                        GameObjectUndo.RecordSceneObjectHeader(selectedSceneObjects);

                        activeSelection = new HandledObject[selectedSceneObjects.Length];
                        for (int i = 0; i < selectedSceneObjects.Length; i++)
                        {
                            activeSelection[i] = new HandledObject(selectedSceneObjects[i]);
                        }

                        initialHandlePosition = activeHandle.Position;
                        initialHandleRotation = activeHandle.Rotation;
                    }
                }
                else
                {
                    if (isDragged)
                    {
                        GameObjectUndo.ResolveDiffs();
                    }

                    isDragged       = false;
                    activeSelection = null;
                }

                activeHandle.PostInput();

                if (activeHandle.IsDragged())
                {
                    switch (activeHandleType)
                    {
                    case SceneViewTool.Move:
                        MoveHandle moveHandle = (MoveHandle)activeHandle;

                        foreach (var selectedObj in activeSelection)
                        {
                            SceneObject parentSO = selectedObj.so.Parent;
                            if (parentSO == null)
                            {
                                selectedObj.so.LocalPosition = selectedObj.initialPosition + moveHandle.Delta;
                            }
                            else
                            {
                                Vector3 parentRelativeDelta = parentSO.Rotation.Inverse.Rotate(moveHandle.Delta);
                                selectedObj.so.LocalPosition = selectedObj.initialPosition + parentRelativeDelta;
                            }
                        }

                        break;

                    case SceneViewTool.Rotate:
                    {
                        RotateHandle rotateHandle = (RotateHandle)activeHandle;

                        // Make sure we transform relative to the handle position
                        SceneObject temporarySO = new SceneObject("Temp");
                        temporarySO.Position      = initialHandlePosition;
                        temporarySO.LocalRotation = initialHandleRotation;

                        SceneObject[] originalParents = new SceneObject[activeSelection.Length];
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            originalParents[i] = activeSelection[i].so.Parent;
                            activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
                            activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
                            activeSelection[i].so.Parent        = temporarySO;
                        }

                        temporarySO.LocalRotation *= rotateHandle.Delta;

                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            activeSelection[i].so.Parent = originalParents[i];
                        }

                        temporarySO.Destroy();
                    }
                    break;

                    case SceneViewTool.Scale:
                    {
                        ScaleHandle scaleHandle = (ScaleHandle)activeHandle;

                        Vector3 origin = activeHandle.Position;
                        for (int i = 0; i < activeSelection.Length; i++)
                        {
                            Vector3 posDiff  = activeSelection[i].initialPosition - origin;
                            Vector3 scale    = activeSelection[i].initialScale;
                            Vector3 newScale = scale + scaleHandle.Delta;

                            Vector3 pctScale = new Vector3(
                                newScale.x / scale.x,
                                newScale.y / scale.y,
                                newScale.z / scale.z);

                            activeSelection[i].so.LocalScale = newScale;
                            activeSelection[i].so.Position   = origin + posDiff * pctScale;
                        }
                    }
                    break;
                    }

                    SceneObject[] selectedSceneObjects = new SceneObject[activeSelection.Length];
                    for (int i = 0; i < activeSelection.Length; i++)
                    {
                        selectedSceneObjects[i] = activeSelection[i].so;
                    }

                    // Make sure to update handle positions for the drawing method (otherwise they lag one frame)
                    UpdateActiveHandleTransform(selectedSceneObjects);

                    EditorApplication.SetSceneDirty();
                }
            }
            else
            {
                isDragged       = false;
                activeSelection = null;
            }
        }