InternalPlatformThreadingInterface.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Avalonia.Platform;
  7. using Avalonia.Rendering;
  8. using Avalonia.Threading;
  9. namespace Avalonia.Controls.Platform
  10. {
  11. public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderTimer
  12. {
  13. public InternalPlatformThreadingInterface()
  14. {
  15. TlsCurrentThreadIsLoopThread = true;
  16. StartTimer(
  17. DispatcherPriority.Render,
  18. new TimeSpan(0, 0, 0, 0, 66),
  19. () => Tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount)));
  20. }
  21. private readonly AutoResetEvent _signaled = new AutoResetEvent(false);
  22. private readonly AutoResetEvent _queued = new AutoResetEvent(false);
  23. private readonly Queue<Action> _actions = new Queue<Action>();
  24. public void RunLoop(CancellationToken cancellationToken)
  25. {
  26. var handles = new[] {_signaled, _queued};
  27. while (true)
  28. {
  29. if (0 == WaitHandle.WaitAny(handles))
  30. Signaled?.Invoke(null);
  31. else
  32. {
  33. while (true)
  34. {
  35. Action item;
  36. lock (_actions)
  37. if (_actions.Count == 0)
  38. break;
  39. else
  40. item = _actions.Dequeue();
  41. item();
  42. }
  43. }
  44. }
  45. }
  46. public void Send(Action cb)
  47. {
  48. lock (_actions)
  49. {
  50. _actions.Enqueue(cb);
  51. _queued.Set();
  52. }
  53. }
  54. class WatTimer : IDisposable
  55. {
  56. private readonly IDisposable _timer;
  57. private GCHandle _handle;
  58. public WatTimer(IDisposable timer)
  59. {
  60. _timer = timer;
  61. _handle = GCHandle.Alloc(_timer);
  62. }
  63. public void Dispose()
  64. {
  65. _handle.Free();
  66. _timer.Dispose();
  67. }
  68. }
  69. public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
  70. {
  71. return new WatTimer(new System.Threading.Timer(delegate
  72. {
  73. var tcs = new TaskCompletionSource<int>();
  74. Send(() =>
  75. {
  76. try
  77. {
  78. tick();
  79. }
  80. finally
  81. {
  82. tcs.SetResult(0);
  83. }
  84. });
  85. tcs.Task.Wait();
  86. }, null, TimeSpan.Zero, interval));
  87. }
  88. public void Signal(DispatcherPriority prio)
  89. {
  90. _signaled.Set();
  91. }
  92. [ThreadStatic] private static bool TlsCurrentThreadIsLoopThread;
  93. public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread;
  94. public event Action<DispatcherPriority?> Signaled;
  95. public event Action<TimeSpan> Tick;
  96. }
  97. }