Merge pull request #73026 from SirUppyPancakes/sync-context-send

Implement GodotSynchronizationContext.Send
This commit is contained in:
Rémi Verschelde 2023-02-12 22:34:18 +01:00
commit 49e8a2fb66
No known key found for this signature in database
GPG key ID: C3336907360768E1

View file

@ -1,17 +1,44 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace Godot namespace Godot
{ {
public sealed class GodotSynchronizationContext : SynchronizationContext, IDisposable public sealed class GodotSynchronizationContext : SynchronizationContext, IDisposable
{ {
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue = new(); private readonly BlockingCollection<(SendOrPostCallback Callback, object State)> _queue = new();
public override void Send(SendOrPostCallback d, object state)
{
// Shortcut if we're already on this context
// Also necessary to avoid a deadlock, since Send is blocking
if (Current == this)
{
d(state);
return;
}
var source = new TaskCompletionSource();
_queue.Add((st =>
{
try
{
d(st);
}
finally
{
source.SetResult();
}
}, state));
source.Task.Wait();
}
public override void Post(SendOrPostCallback d, object state) public override void Post(SendOrPostCallback d, object state)
{ {
_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state)); _queue.Add((d, state));
} }
/// <summary> /// <summary>
@ -21,7 +48,7 @@ namespace Godot
{ {
while (_queue.TryTake(out var workItem)) while (_queue.TryTake(out var workItem))
{ {
workItem.Key(workItem.Value); workItem.Callback(workItem.State);
} }
} }