Skip to content

Commit a35f98b

Browse files
committed
automatically prevent sync over async
1 parent dfc6b56 commit a35f98b

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

src/Compiler/Utilities/Async2.fs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)