@@ -52,6 +52,8 @@ module Async2Implementation =
5252
5353 module BindContext =
5454 let bindCount = new ThreadLocal< int>()
55+ // Used to prevent sync over async deadlocks.
56+ let started = new AsyncLocal< bool>()
5557
5658 [<Literal>]
5759 let bindLimit = 100
@@ -193,6 +195,7 @@ module Async2Implementation =
193195
194196 interface Async2< 't> with
195197 member ts.StartImmediate ct = ts.GetCopy( false ) .StartImmediate( ct)
198+
196199 member ts.StartBound ct = ts.GetCopy( true ) .StartBound( ct)
197200
198201 member ts.TailCall ( ct , tc ) =
@@ -371,6 +374,7 @@ module Async2Implementation =
371374
372375 ( MoveNextMethodImpl<_>( fun sm ->
373376 __ resumeAt sm.ResumptionPoint
377+
374378 let mutable error = ValueNone
375379
376380 let __stack_go1 = not sm.Data.IsBound || yieldOnBindLimit() .Invoke(& sm)
@@ -471,13 +475,21 @@ module Async2 =
471475 let CheckAndThrowToken = AsyncLocal< CancellationToken>()
472476
473477 let inline start ct ( code : Async2 < _ >) =
474- CheckAndThrowToken.Value <- ct
475- code.StartImmediate ct
478+ let oldCt = CheckAndThrowToken.Value
479+
480+ try
481+ BindContext.started.Value <- true
482+ CheckAndThrowToken.Value <- ct
483+ code.StartImmediate ct
484+ finally
485+ CheckAndThrowToken.Value <- oldCt
486+ BindContext.started.Value <- false
476487
477488 let run ct ( code : Async2 < 't >) =
478489
479490 if
480- isNull SynchronizationContext.Current
491+ not BindContext.started.Value // should this be an assert fail or even an exception instead?
492+ && isNull SynchronizationContext.Current
481493 && TaskScheduler.Current = TaskScheduler.Default
482494 then
483495 start ct code |> _. GetAwaiter() .GetResult()
0 commit comments