Browse Source

Make sure that unlock API is still safe.

Dariusz Komosinski 6 years ago
parent
commit
edd6fd626f

+ 21 - 2
src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs

@@ -1,5 +1,8 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
 using System;
-using System.Reactive.Disposables;
+using System.Threading;
 using Avalonia.Native.Interop;
 using Avalonia.Rendering;
 
@@ -13,11 +16,27 @@ namespace Avalonia.Native
         {
             _window = window;
         }
+
         public IDisposable TryLock()
         {
             if (_window.TryLock())
-                return Disposable.Create(() => _window.Unlock());
+                return new UnlockDisposable(_window);
             return null;
         }
+
+        private class UnlockDisposable : IDisposable
+        {
+            private IAvnWindowBase _window;
+
+            public UnlockDisposable(IAvnWindowBase window)
+            {
+                _window = window;
+            }
+
+            public void Dispose()
+            {
+                Interlocked.Exchange(ref _window, null)?.Unlock();
+            }
+        }
     }
 }

+ 14 - 12
src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs

@@ -1,3 +1,6 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
 using System;
 using System.Threading;
 
@@ -6,12 +9,6 @@ namespace Avalonia.Rendering
     public class ManagedDeferredRendererLock : IDeferredRendererLock
     {
         private readonly object _lock = new object();
-        private readonly LockDisposable _lockDisposable;
-
-        public ManagedDeferredRendererLock()
-        {
-            _lockDisposable = new LockDisposable(_lock);
-        }
 
         /// <summary>
         /// Tries to lock the target surface or window
@@ -20,7 +17,7 @@ namespace Avalonia.Rendering
         public IDisposable TryLock()
         {
             if (Monitor.TryEnter(_lock))
-                return _lockDisposable;
+                return new UnlockDisposable(_lock);
             return null;
         }
 
@@ -30,21 +27,26 @@ namespace Avalonia.Rendering
         public IDisposable Lock()
         {
             Monitor.Enter(_lock);
-            return _lockDisposable;
+            return new UnlockDisposable(_lock);
         }
 
-        private class LockDisposable : IDisposable
+        private class UnlockDisposable : IDisposable
         {
-            private readonly object _lock;
+            private object _lock;
 
-            public LockDisposable(object @lock)
+            public UnlockDisposable(object @lock)
             {
                 _lock = @lock;
             }
 
             public void Dispose()
             {
-                Monitor.Exit(_lock);
+                object @lock = Interlocked.Exchange(ref _lock, null);
+
+                if (@lock != null)
+                {
+                    Monitor.Exit(@lock);
+                }
             }
         }
     }