Browse Source

Special handling for macos dispatcher quirks

pull/12230/head
Nikita Tsukanov 3 years ago
parent
commit
ed7a9f8813
  1. 20
      src/Avalonia.Base/Threading/Dispatcher.Queue.cs
  2. 2
      src/Avalonia.Base/Threading/Dispatcher.Timers.cs
  3. 3
      src/Avalonia.Base/Threading/Dispatcher.cs
  4. 8
      src/Avalonia.Base/Threading/DispatcherFrame.cs

20
src/Avalonia.Base/Threading/Dispatcher.Queue.cs

@ -9,7 +9,9 @@ public partial class Dispatcher
private readonly DispatcherPriorityQueue _queue = new(); private readonly DispatcherPriorityQueue _queue = new();
private bool _signaled; private bool _signaled;
private bool _explicitBackgroundProcessingRequested; private bool _explicitBackgroundProcessingRequested;
private const int MaximumTimeProcessingBackgroundJobs = 50; private const int MaximumInputStarvationTimeInFallbackMode = 50;
private const int MaximumInputStarvationTimeInExplicitProcessingExplicitMode = 50;
private int _maximumInputStarvationTime;
void RequestBackgroundProcessing() void RequestBackgroundProcessing()
{ {
@ -35,8 +37,8 @@ public partial class Dispatcher
lock (InstanceLock) lock (InstanceLock)
{ {
_explicitBackgroundProcessingRequested = false; _explicitBackgroundProcessingRequested = false;
ExecuteJobsCore();
} }
ExecuteJobsCore(true);
} }
/// <summary> /// <summary>
@ -130,10 +132,10 @@ public partial class Dispatcher
lock (InstanceLock) lock (InstanceLock)
_signaled = false; _signaled = false;
ExecuteJobsCore(); ExecuteJobsCore(false);
} }
void ExecuteJobsCore() void ExecuteJobsCore(bool fromExplicitBackgroundProcessingCallback)
{ {
long? backgroundJobExecutionStartedAt = null; long? backgroundJobExecutionStartedAt = null;
while (true) while (true)
@ -151,7 +153,6 @@ public partial class Dispatcher
if (job.Priority > DispatcherPriority.Input) if (job.Priority > DispatcherPriority.Input)
{ {
ExecuteJob(job); ExecuteJob(job);
backgroundJobExecutionStartedAt = null;
} }
// If platform supports pending input query, ask the platform if we can continue running low priority jobs // If platform supports pending input query, ask the platform if we can continue running low priority jobs
else if (_pendingInputImpl?.CanQueryPendingInput == true) else if (_pendingInputImpl?.CanQueryPendingInput == true)
@ -164,6 +165,13 @@ public partial class Dispatcher
return; return;
} }
} }
// We can't ask if the implementation has pending input, so we should let it to call us back
// Once it thinks that input is handled
else if (_backgroundProcessingImpl != null && !fromExplicitBackgroundProcessingCallback)
{
RequestBackgroundProcessing();
return;
}
// We can't check if there is pending input, but still need to enforce interactivity // We can't check if there is pending input, but still need to enforce interactivity
// so we stop processing background jobs after some timeout and start a timer to continue later // so we stop processing background jobs after some timeout and start a timer to continue later
else else
@ -171,7 +179,7 @@ public partial class Dispatcher
if (backgroundJobExecutionStartedAt == null) if (backgroundJobExecutionStartedAt == null)
backgroundJobExecutionStartedAt = Now; backgroundJobExecutionStartedAt = Now;
if (Now - backgroundJobExecutionStartedAt.Value > MaximumTimeProcessingBackgroundJobs) if (Now - backgroundJobExecutionStartedAt.Value > _maximumInputStarvationTime)
{ {
_signaled = true; _signaled = true;
RequestBackgroundProcessing(); RequestBackgroundProcessing();

2
src/Avalonia.Base/Threading/Dispatcher.Timers.cs

@ -127,7 +127,7 @@ public partial class Dispatcher
if (needToPromoteTimers) if (needToPromoteTimers)
PromoteTimers(); PromoteTimers();
if (needToProcessQueue) if (needToProcessQueue)
ExecuteJobsCore(); ExecuteJobsCore(false);
UpdateOSTimer(); UpdateOSTimer();
} }

3
src/Avalonia.Base/Threading/Dispatcher.cs

@ -34,6 +34,9 @@ public partial class Dispatcher : IDispatcher
_controlledImpl = _impl as IControlledDispatcherImpl; _controlledImpl = _impl as IControlledDispatcherImpl;
_pendingInputImpl = _impl as IDispatcherImplWithPendingInput; _pendingInputImpl = _impl as IDispatcherImplWithPendingInput;
_backgroundProcessingImpl = _impl as IDispatcherImplWithExplicitBackgroundProcessing; _backgroundProcessingImpl = _impl as IDispatcherImplWithExplicitBackgroundProcessing;
_maximumInputStarvationTime = _backgroundProcessingImpl == null ?
MaximumInputStarvationTimeInFallbackMode :
MaximumInputStarvationTimeInExplicitProcessingExplicitMode;
if (_backgroundProcessingImpl != null) if (_backgroundProcessingImpl != null)
_backgroundProcessingImpl.ReadyForBackgroundProcessing += OnReadyForExplicitBackgroundProcessing; _backgroundProcessingImpl.ReadyForBackgroundProcessing += OnReadyForExplicitBackgroundProcessing;
} }

8
src/Avalonia.Base/Threading/DispatcherFrame.cs

@ -38,10 +38,14 @@ public class DispatcherFrame
/// for their important criteria to be met. These frames /// for their important criteria to be met. These frames
/// should have a timeout associated with them. /// should have a timeout associated with them.
/// </param> /// </param>
public DispatcherFrame(bool exitWhenRequested) public DispatcherFrame(bool exitWhenRequested) : this(Dispatcher.UIThread, exitWhenRequested)
{ {
Dispatcher = Dispatcher.UIThread;
Dispatcher.VerifyAccess(); Dispatcher.VerifyAccess();
}
internal DispatcherFrame(Dispatcher dispatcher, bool exitWhenRequested)
{
Dispatcher = dispatcher;
_exitWhenRequested = exitWhenRequested; _exitWhenRequested = exitWhenRequested;
_continue = true; _continue = true;
} }

Loading…
Cancel
Save