From 630400da53267e83ad1f6129137b23e3e300afc4 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sat, 4 Jan 2020 11:55:12 +0100 Subject: [PATCH] avoid task.run on newer platforms --- .../PacketDispatcher/MqttPacketAwaiter.cs | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs b/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs index 8f906f60..b1722900 100644 --- a/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs +++ b/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs @@ -9,7 +9,7 @@ namespace MQTTnet.PacketDispatcher { public sealed class MqttPacketAwaiter : Disposable, IMqttPacketAwaiter where TPacket : MqttBasePacket { - private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); + private readonly TaskCompletionSource _taskCompletionSource; private readonly ushort? _packetIdentifier; private readonly MqttPacketDispatcher _owningPacketDispatcher; @@ -17,13 +17,18 @@ namespace MQTTnet.PacketDispatcher { _packetIdentifier = packetIdentifier; _owningPacketDispatcher = owningPacketDispatcher ?? throw new ArgumentNullException(nameof(owningPacketDispatcher)); +#if NET452 + _taskCompletionSource = new TaskCompletionSource(); +#else + _taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); +#endif } public async Task WaitOneAsync(TimeSpan timeout) { using (var timeoutToken = new CancellationTokenSource(timeout)) { - timeoutToken.Token.Register(() => _taskCompletionSource.TrySetException(new MqttCommunicationTimedOutException())); + timeoutToken.Token.Register(() => Fail(new MqttCommunicationTimedOutException())); var packet = await _taskCompletionSource.Task.ConfigureAwait(false); return (TPacket)packet; @@ -33,24 +38,47 @@ namespace MQTTnet.PacketDispatcher public void Complete(MqttBasePacket packet) { if (packet == null) throw new ArgumentNullException(nameof(packet)); - + + +#if NET452 // To prevent deadlocks it is required to call the _TrySetResult_ method // from a new thread because the awaiting code will not(!) be executed in // a new thread automatically (due to await). Furthermore _this_ thread will // do it. But _this_ thread is also reading incoming packets -> deadlock. + // NET452 does not support RunContinuationsAsynchronously Task.Run(() => _taskCompletionSource.TrySetResult(packet)); +#else + _taskCompletionSource.TrySetResult(packet); +#endif } public void Fail(Exception exception) { if (exception == null) throw new ArgumentNullException(nameof(exception)); - +#if NET452 + // To prevent deadlocks it is required to call the _TrySetResult_ method + // from a new thread because the awaiting code will not(!) be executed in + // a new thread automatically (due to await). Furthermore _this_ thread will + // do it. But _this_ thread is also reading incoming packets -> deadlock. + // NET452 does not support RunContinuationsAsynchronously Task.Run(() => _taskCompletionSource.TrySetException(exception)); +#else + _taskCompletionSource.TrySetException(exception); +#endif } public void Cancel() { +#if NET452 + // To prevent deadlocks it is required to call the _TrySetResult_ method + // from a new thread because the awaiting code will not(!) be executed in + // a new thread automatically (due to await). Furthermore _this_ thread will + // do it. But _this_ thread is also reading incoming packets -> deadlock. + // NET452 does not support RunContinuationsAsynchronously Task.Run(() => _taskCompletionSource.TrySetCanceled()); +#else + _taskCompletionSource.TrySetCanceled(); +#endif } protected override void Dispose(bool disposing)