SkiaSharp: [BUG] SkiaSharp can call WM_PAINT handler and random COM callbacks when creating or obtaning objects
Avalonia.Win32.dll!Avalonia.Win32.WindowImpl.WndProc(System.IntPtr hWnd, uint msg, System.IntPtr wParam, System.IntPtr lParam) Line 30 C#
[Native to Managed Transition]
[Managed to Native Transition]
System.Private.CoreLib.dll!System.Threading.WaitHandle.WaitOneNoCheck(int millisecondsTimeout) Unknown
System.Private.CoreLib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout) Unknown
System.Private.CoreLib.dll!System.Threading.ReaderWriterLockSlim.WaitOnEvent(System.Threading.EventWaitHandle waitEvent, ref uint numWaiters, System.Threading.ReaderWriterLockSlim.TimeoutTracker timeout, System.Threading.ReaderWriterLockSlim.EnterLockType enterLockType) Unknown
System.Private.CoreLib.dll!System.Threading.ReaderWriterLockSlim.TryEnterWriteLockCore(System.Threading.ReaderWriterLockSlim.TimeoutTracker timeout) Unknown
SkiaSharp.dll!SkiaSharp.HandleDictionary.RegisterHandle(System.IntPtr handle, SkiaSharp.SKObject instance) Unknown
SkiaSharp.dll!SkiaSharp.SKObject.RegisterHandle(System.IntPtr handle, SkiaSharp.SKObject instance) Unknown
SkiaSharp.dll!SkiaSharp.SKObject.Handle.set(System.IntPtr value) Unknown
SkiaSharp.dll!SkiaSharp.SKObject.SKObject(System.IntPtr handle, bool owns) Unknown
SkiaSharp.dll!SkiaSharp.SKPath.SKPath(System.IntPtr handle, bool owns) Unknown
SkiaSharp.dll!SkiaSharp.SKPath.SKPath() Unknown
This is caused by all locks in .NET being alertable locks that can still run the message pump when waiting for a lock.
This behavior might lead to unexpected behavior in the user code or even deadlocks, since user code doesn’t expect to receive WM_PAINT while calling SKPath constructor.
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 1
- Comments: 19 (12 by maintainers)
Hi Andrew, thanks for your insight on this - that’s really valuable info. Message hooks to filter paint messages sounds like too much fun.
This is all a bit of a mess, but for understood reasons. I think we agree SkiaSharp could improve things with a non-pumping lock, or at least a way to plugin your own sync mechanism.
Unless, or until this can be fixed SkiaSharp I’m tempted to just disable the pumping wait entirely. I feel like I’m more exposed by that than anything else the app or any plugins might do. But I’m sure that’ll bite me somewhere else 😃
@mattleibow you were right! TIL, plain c# locks (ie.,
Monitor.Enter
/Monitor.Exit
) also pump on an STA thread 👀 https://gist.github.com/noseratio/0d93133b826339c7eaf49c9feec142e3#file-winformsapp-cs-L60Now I wonder if there’s any managed blocking synchronization primitive that doesn’t pump in this case, besides
Thread.Sleep
…Edited: and here’s where the pumping magic is happening: https://github.com/dotnet/runtime/blob/0c0bd5a4066bc9b1a165a45e3553dfa14b87729b/src/coreclr/vm/threads.cpp#L3342
@mattleibow I might be wrong but I think in this particular case it’s caused by
Thread.CurrentThread.Join(100)
, where they call it on the main UI thread. This call does indeed pump:I think,
Monitor.Enter
/Monitor.Exit
should be mapping to Win32EnterCriticalSection
/LeaveCriticalSection
directly, maybe with some added “spin-before-sleep” improvement, but I can’t find anything confirming that in thedotnet
repo right away. I might try modifying the code you linked to verify this theory 😃@noseratio I think using
lock
also had this issue: https://gist.github.com/retran/b57e4db1a173048c2cee49ac6d523fc2