From edd6fd626f7e21005bc828792cb7ee7848a01fe7 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 8 Sep 2019 17:31:18 +0200 Subject: [PATCH] Make sure that unlock API is still safe. --- .../AvaloniaNativeDeferredRendererLock.cs | 23 ++++++++++++++-- .../Rendering/ManagedDeferredRendererLock.cs | 26 ++++++++++--------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs b/src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs index 6dd5337b27..0031cc5b03 100644 --- a/src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs +++ b/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(); + } + } } } diff --git a/src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs b/src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs index 1295961a1b..a87fc9e39f 100644 --- a/src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs +++ b/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); - } /// /// 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); + } } } }