From cbb42d756c01d6fdd236c6d1f17b50b6ced5770b Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 16 Dec 2022 00:29:57 +0600 Subject: [PATCH] Added some threading checks --- .../CompositionCustomVisualHandler.cs | 39 ++++++++++++++++--- .../Composition/Server/ServerCompositor.cs | 19 ++++++++- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs index 43bf075a3e..b7ed6fe612 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs @@ -21,16 +21,45 @@ public abstract class CompositionCustomVisualHandler public abstract void OnRender(ImmediateDrawingContext drawingContext); - protected Vector2 EffectiveSize => _host?.Size ?? default; + void VerifyAccess() + { + if (_host == null) + throw new InvalidOperationException("Object is not yet attached to the compositor"); + _host.Compositor.VerifyAccess(); + } + + protected Vector2 EffectiveSize + { + get + { + VerifyAccess(); + return _host!.Size; + } + } + + protected TimeSpan CompositionNow + { + get + { + VerifyAccess(); + return _host!.Compositor.ServerNow; + } + } - protected TimeSpan CompositionNow => _host?.Compositor.ServerNow ?? default; - public virtual Rect GetRenderBounds() => new(0, 0, EffectiveSize.X, EffectiveSize.Y); internal void Attach(ServerCompositionCustomVisual visual) => _host = visual; - protected void Invalidate() => _host?.HandlerInvalidate(); + protected void Invalidate() + { + VerifyAccess(); + _host!.HandlerInvalidate(); + } - protected void RegisterForNextAnimationFrameUpdate() => _host?.HandlerRegisterForNextAnimationFrameUpdate(); + protected void RegisterForNextAnimationFrameUpdate() + { + VerifyAccess(); + _host!.HandlerRegisterForNextAnimationFrameUpdate(); + } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs index d83e06c820..e7405995f5 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Threading; using Avalonia.Logging; using Avalonia.Platform; using Avalonia.Rendering.Composition.Animations; @@ -31,6 +32,7 @@ namespace Avalonia.Rendering.Composition.Server internal BatchStreamObjectPool BatchObjectPool; internal BatchStreamMemoryPool BatchMemoryPool; private object _lock = new object(); + private Thread? _safeThread; public PlatformRenderInterfaceContextManager RenderInterface { get; } internal static readonly object RenderThreadJobsStartMarker = new(); internal static readonly object RenderThreadJobsEndMarker = new(); @@ -129,7 +131,15 @@ namespace Avalonia.Rendering.Composition.Server { lock (_lock) { - RenderCore(); + try + { + _safeThread = Thread.CurrentThread; + RenderCore(); + } + finally + { + _safeThread = null; + } } } @@ -180,5 +190,12 @@ namespace Avalonia.Rendering.Composition.Server using (RenderInterface.EnsureCurrent()) return RenderInterface.CreateRenderTarget(surfaces); } + + public bool CheckAccess() => _safeThread == Thread.CurrentThread; + public void VerifyAccess() + { + if (!CheckAccess()) + throw new InvalidOperationException("This object can be only accessed under compositor lock"); + } } }