@@ -52,8 +52,6 @@ module Async2Implementation =
52
52
53
53
module BindContext =
54
54
let bindCount = new ThreadLocal< int>()
55
- // Used to prevent sync over async deadlocks.
56
- let started = new AsyncLocal< bool>()
57
55
58
56
[<Literal>]
59
57
let bindLimit = 100
@@ -103,6 +101,8 @@ module Async2Implementation =
103
101
104
102
member this.Ref : ICriticalNotifyCompletion ref = ref this
105
103
104
+ member _.Running = running
105
+
106
106
static member Current = holder.Value
107
107
108
108
module ExceptionCache =
@@ -474,36 +474,40 @@ module Async2 =
474
474
475
475
let CheckAndThrowToken = AsyncLocal< CancellationToken>()
476
476
477
+ let startInThreadPool ct ( code : Async2 < _ >) =
478
+ Task.Run< 't>( fun () ->
479
+ CheckAndThrowToken.Value <- ct
480
+ code.StartImmediate ct |> _. Task)
481
+
477
482
let inline start ct ( code : Async2 < _ >) =
478
- let oldCt = CheckAndThrowToken.Value
479
- let oldStarted = BindContext.started.Value
480
483
481
484
let immediate =
482
- not oldStarted
485
+ not Trampoline.Current.Running // prevent deadlock, TODO: better solution?
483
486
&& isNull SynchronizationContext.Current
484
487
&& TaskScheduler.Current = TaskScheduler.Default
485
488
486
- try
487
- BindContext.started.Value <- true
488
- CheckAndThrowToken.Value <- ct
489
+ if immediate then
490
+ let oldCt = CheckAndThrowToken.Value
489
491
490
- if immediate then
492
+ try
493
+ CheckAndThrowToken.Value <- ct
491
494
code.StartImmediate ct |> _. Task
492
- else
493
- Task.Run < 't >( fun () -> code.StartImmediate ct |> _. Task )
494
- finally
495
- CheckAndThrowToken.Value <- oldCt
496
- BindContext.started.Value <- oldStarted
495
+
496
+ finally
497
+ CheckAndThrowToken.Value <- oldCt
498
+ else
499
+ startInThreadPool ct code
497
500
498
501
let run ct ( code : Async2 < 't >) =
499
- start ct code |> _. GetAwaiter() .GetResult()
502
+ startInThreadPool ct code |> _. GetAwaiter() .GetResult()
500
503
501
504
let runWithoutCancellation code = run CancellationToken.None code
502
505
503
506
//let queueTask ct code =
504
507
// Task.Run<'t>(fun () -> start ct code)
505
508
506
- let startAsTaskWithoutCancellation code = start CancellationToken.None code
509
+ let startAsTaskWithoutCancellation code =
510
+ startInThreadPool CancellationToken.None code
507
511
508
512
let toAsync ( code : Async2 < 't >) =
509
513
async {
@@ -530,15 +534,15 @@ type Async2 =
530
534
531
535
static member Start ( computation : Async2 < _ >, ? cancellationToken : CancellationToken ) : unit =
532
536
let ct = defaultArg cancellationToken CancellationToken.None
533
- Async2.start ct computation |> ignore
537
+ Async2.startInThreadPool ct computation |> ignore
534
538
535
539
static member StartAsTask ( computation : Async2 < _ >, ? cancellationToken : CancellationToken ) : Task < _ > =
536
540
let ct = defaultArg cancellationToken CancellationToken.None
537
- Async2.start ct computation
541
+ Async2.startInThreadPool ct computation
538
542
539
543
static member RunImmediate ( computation : Async2 < 'T >, ? cancellationToken : CancellationToken ) : 'T =
540
544
let ct = defaultArg cancellationToken CancellationToken.None
541
- Async2.run ct computation
545
+ Async2.start ct computation |> _. GetAwaiter () .GetResult ()
542
546
543
547
static member Parallel ( computations : Async2 < _ > seq ) =
544
548
async2 {
@@ -555,7 +559,7 @@ type Async2 =
555
559
lcts.Cancel()
556
560
return raise exn
557
561
}
558
- |> Async2.start lcts.Token
562
+ |> Async2.startInThreadPool lcts.Token
559
563
}
560
564
561
565
return ! Task.WhenAll tasks
@@ -584,25 +588,25 @@ type Async2 =
584
588
static member TryCancelled ( computation : Async2 < 'T >, compensation ) =
585
589
async2 {
586
590
let! ct = Async2.CancellationToken
587
- let task = Async2.start ct computation
591
+ let invocation = computation.StartImmediate ct
588
592
589
593
try
590
- return ! task
594
+ return ! invocation
591
595
finally
592
- if task .IsCanceled then
596
+ if invocation.Task .IsCanceled then
593
597
compensation ()
594
598
}
595
599
596
600
static member StartChild ( computation : Async2 < 'T >) : Async2 < Async2 < 'T >> =
597
601
async2 {
598
602
let! ct = Async2.CancellationToken
599
- return async2 { return ! computation |> Async2.start ct }
603
+ return async2 { return ! computation |> Async2.startInThreadPool ct }
600
604
}
601
605
602
606
static member StartChildAsTask ( computation : Async2 < 'T >) : Async2 < Task < 'T >> =
603
607
async2 {
604
608
let! ct = Async2.CancellationToken
605
- let task = computation |> Async2.start ct
609
+ let task = computation |> Async2.startInThreadPool ct
606
610
return task
607
611
}
608
612
0 commit comments