* Update generator to emit function pointers * Regenerate interop files * Enable USE_LIBRARY_IMPORT in HarfBuzzSharp * Enable USE_LIBRARY_IMPORT on SkiaSharp * Set DisableRuntimeMarshalling on HarfBuzzSharp * Replace remaining DllImports with LibraryImport on SkiaSharp * Set DisableRuntimeMarshalling on SkiaSharp as well * Fix missed proxy definition * Regenerate skia api with a correct submodule version * Collections literals are not supported on the CI .NET SDK * An attempt to fix Tizen build * Forgot about partial * Set UnmanagedType.LPStr on evas_gl_proc_address_get instead * Set USE_LIBRARY_IMPORT on remaining projects too * Update generator tool to generate DelegateProxy as well * Regenerate HarfBuzz and SkiaSharp with new DelegateProxy source gen * Regenerate other projects as well * Add `protected internal` to test classes too, since this project has InternalsVisibleTo configured * Disable DelegateTypesAreValid and DelegateTypesHaveAttributes tests on .NET 7+ build, see comments * Reduce warnings noise * Update binding/SkiaSharp/GRGlInterface.cs Co-authored-by: Filip Navara <filip.navara@gmail.com> * Add missing USE_LIBRARY_IMPORT defines * Update binding/SkiaSharp/GRGlInterface.cs * Also needs USE_LIBRARY_IMPORT --------- Co-authored-by: Matthew Leibowitz <mattleibow@live.com> Co-authored-by: Filip Navara <filip.navara@gmail.com>
174 lines
5.1 KiB
C#
174 lines
5.1 KiB
C#
#nullable disable
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
|
|
/*
|
|
* This is a fix for issue #1383.
|
|
*
|
|
* https://github.com/mono/SkiaSharp/issues/1383
|
|
*
|
|
* On Windows, .NET locks are alertable when using the STA threading model and can
|
|
* cause the Windows message loop to be dispatched (typically on WM_PAINT messages).
|
|
* This can lead to re-entrancy and a deadlock on the HandleDictionary lock.
|
|
*
|
|
* This fix replaces the ReaderWriteLockSlim instance on Windows with a native Win32
|
|
* CRITICAL_SECTION.
|
|
*/
|
|
|
|
|
|
|
|
namespace SkiaSharp.Internals
|
|
{
|
|
/// <summary>
|
|
/// Abstracts a platform dependant lock implementation
|
|
/// </summary>
|
|
public interface IPlatformLock
|
|
{
|
|
void EnterReadLock ();
|
|
void ExitReadLock ();
|
|
void EnterWriteLock ();
|
|
void ExitWriteLock ();
|
|
void EnterUpgradeableReadLock ();
|
|
void ExitUpgradeableReadLock ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper class to create a IPlatformLock instance, by default according to the current platform
|
|
/// but also client toolkits can plugin their own implementation.
|
|
/// </summary>
|
|
public static partial class PlatformLock
|
|
{
|
|
/// <summary>
|
|
/// Creates a platform lock
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static IPlatformLock Create ()
|
|
{
|
|
// Just call the factory
|
|
return Factory ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The factory for creating platform locks
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Use this to plugin your own lock implementation. Must be set
|
|
/// before using other SkiaSharp functionality that causes the lock
|
|
/// to be created (currently only used by SkiaSharps internal
|
|
/// HandleDictionary).
|
|
/// </remarks>
|
|
public static Func<IPlatformLock> Factory { get; set; } = DefaultFactory;
|
|
|
|
/// <summary>
|
|
/// Default platform lock factory
|
|
/// </summary>
|
|
/// <returns>A reference to a new platform lock implementation</returns>
|
|
public static IPlatformLock DefaultFactory ()
|
|
{
|
|
if (PlatformConfiguration.IsWindows)
|
|
return new NonAlertableWin32Lock ();
|
|
else
|
|
return new ReadWriteLock ();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Non-Windows platform lock uses ReaderWriteLockSlim
|
|
/// </summary>
|
|
class ReadWriteLock : IPlatformLock
|
|
{
|
|
public void EnterReadLock () => _lock.EnterReadLock ();
|
|
public void ExitReadLock () => _lock.ExitReadLock ();
|
|
public void EnterWriteLock () => _lock.EnterWriteLock ();
|
|
public void ExitWriteLock () => _lock.ExitWriteLock ();
|
|
public void EnterUpgradeableReadLock () => _lock.EnterUpgradeableReadLock ();
|
|
public void ExitUpgradeableReadLock () => _lock.ExitUpgradeableReadLock ();
|
|
|
|
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Windows platform lock uses Win32 CRITICAL_SECTION
|
|
/// </summary>
|
|
partial class NonAlertableWin32Lock : IPlatformLock
|
|
{
|
|
public NonAlertableWin32Lock ()
|
|
{
|
|
_cs = Marshal.AllocHGlobal (Unsafe.SizeOf<CRITICAL_SECTION>());
|
|
if (_cs == IntPtr.Zero)
|
|
throw new OutOfMemoryException ("Failed to allocate memory for critical section");
|
|
|
|
InitializeCriticalSectionEx (_cs, 4000, 0);
|
|
}
|
|
|
|
~NonAlertableWin32Lock ()
|
|
{
|
|
if (_cs != IntPtr.Zero) {
|
|
DeleteCriticalSection (_cs);
|
|
Marshal.FreeHGlobal (_cs);
|
|
_cs = IntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
IntPtr _cs;
|
|
|
|
void Enter ()
|
|
{
|
|
if (_cs != IntPtr.Zero) {
|
|
EnterCriticalSection(_cs);
|
|
}
|
|
}
|
|
|
|
void Leave ()
|
|
{
|
|
if (_cs != IntPtr.Zero) {
|
|
LeaveCriticalSection(_cs);
|
|
}
|
|
}
|
|
|
|
public void EnterReadLock () { Enter (); }
|
|
public void ExitReadLock () { Leave (); }
|
|
public void EnterWriteLock () { Enter (); }
|
|
public void ExitWriteLock () { Leave (); }
|
|
public void EnterUpgradeableReadLock () { Enter (); }
|
|
public void ExitUpgradeableReadLock () { Leave (); }
|
|
|
|
[StructLayout (LayoutKind.Sequential)]
|
|
public struct CRITICAL_SECTION
|
|
{
|
|
public IntPtr DebugInfo;
|
|
public int LockCount;
|
|
public int RecursionCount;
|
|
public IntPtr OwningThread;
|
|
public IntPtr LockSemaphore;
|
|
public UIntPtr SpinCount;
|
|
}
|
|
|
|
#if USE_LIBRARY_IMPORT
|
|
[LibraryImport ("Kernel32.dll", SetLastError = true)]
|
|
[return: MarshalAs (UnmanagedType.Bool)]
|
|
private static partial bool InitializeCriticalSectionEx (IntPtr lpCriticalSection, uint dwSpinCount, uint Flags);
|
|
[LibraryImport ("Kernel32.dll")]
|
|
private static partial void DeleteCriticalSection (IntPtr lpCriticalSection);
|
|
[LibraryImport ("Kernel32.dll")]
|
|
private static partial void EnterCriticalSection (IntPtr lpCriticalSection);
|
|
[LibraryImport ("Kernel32.dll")]
|
|
private static partial void LeaveCriticalSection (IntPtr lpCriticalSection);
|
|
#else
|
|
[DllImport ("Kernel32.dll", SetLastError = true)]
|
|
[return: MarshalAs (UnmanagedType.Bool)]
|
|
static extern bool InitializeCriticalSectionEx (IntPtr lpCriticalSection, uint dwSpinCount, uint Flags);
|
|
[DllImport ("Kernel32.dll")]
|
|
static extern void DeleteCriticalSection (IntPtr lpCriticalSection);
|
|
[DllImport ("Kernel32.dll")]
|
|
static extern void EnterCriticalSection (IntPtr lpCriticalSection);
|
|
[DllImport ("Kernel32.dll")]
|
|
static extern void LeaveCriticalSection (IntPtr lpCriticalSection);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|