@@ -85,16 +85,17 @@ and CancellableResumptionDynamicInfo<'TOverall> = ResumptionDynamicInfo<Cancella
85
85
and CancellableCode < 'TOverall , 'T > = ResumableCode< CancellableStateMachineData< 'TOverall>, 'T>
86
86
87
87
[<Sealed>]
88
- type Trampoline ( cancellationToken : CancellationToken ) =
88
+ type Trampoline () =
89
89
90
90
let mutable bindDepth = 0
91
+ let cancellationToken = FSharp.Compiler.Cancellable.Token
91
92
92
93
[<Literal>]
93
94
static let bindDepthLimit = 100
94
95
95
- static let current = new ThreadLocal < Trampoline>()
96
+ static let current = new AsyncLocal < Trampoline voption >()
96
97
97
- let delayed = System.Collections.Generic.Stack< ITrampolineInvocation>()
98
+ let pending = System.Collections.Generic.Stack< ITrampolineInvocation>()
98
99
99
100
member this.IsCancelled = cancellationToken.IsCancellationRequested
100
101
@@ -103,15 +104,13 @@ type Trampoline(cancellationToken: CancellationToken) =
103
104
104
105
member this.ShoudBounce = bindDepth % bindDepthLimit = 0
105
106
106
- static member Install ct = current.Value <- Trampoline ct
107
-
108
107
member val LastError : ExceptionDispatchInfo voption = ValueNone with get, set
109
108
110
109
member this.RunDelayed ( continuation , invocation ) =
111
110
// The calling state machine is now suspended. We need to resume it next.
112
- delayed .Push continuation
111
+ pending .Push continuation
113
112
// Schedule the delayed invocation to run.
114
- delayed .Push invocation
113
+ pending .Push invocation
115
114
116
115
member this.RunImmediate ( invocation : ITrampolineInvocation ) =
117
116
bindDepth <- bindDepth + 1
@@ -121,16 +120,19 @@ type Trampoline(cancellationToken: CancellationToken) =
121
120
invocation.MoveNext()
122
121
123
122
while not invocation.IsCompleted do
124
- if delayed .Peek() .IsCompleted then
125
- delayed .Pop() |> ignore
123
+ if pending .Peek() .IsCompleted then
124
+ pending .Pop() |> ignore
126
125
else
127
- delayed .Peek() .MoveNext()
126
+ pending .Peek() .MoveNext()
128
127
// In case this was a delayed invocation, which captures the exception, we need to replay it.
129
128
invocation.ReplayExceptionIfStored()
130
129
finally
131
130
bindDepth <- bindDepth - 1
132
131
133
- static member Current = current.Value
132
+ static member Current = current.Value.Value
133
+
134
+ static member EnsureInstalled () =
135
+ if current.Value.IsNone then current.Value <- ValueSome <| Trampoline()
134
136
135
137
type ITrampolineInvocation < 'T > =
136
138
inherit ITrampolineInvocation
@@ -354,22 +356,20 @@ module CancellableAutoOpens =
354
356
module Cancellable =
355
357
open Internal.Utilities .Library .CancellableImplementation
356
358
357
- let run ct ( code : Cancellable < _ >) =
358
- use _ = FSharp.Compiler.Cancellable.UsingToken ct
359
-
359
+ let run ( code : Cancellable < _ >) =
360
360
let invocation = code.GetInvocation( false )
361
- Trampoline.Install ct
361
+ Trampoline.EnsureInstalled ()
362
362
Trampoline.Current.RunImmediate invocation
363
- invocation
363
+ invocation.Result
364
364
365
365
let runWithoutCancellation code =
366
- code |> run CancellationToken.None |> _. Result
366
+ use _ = FSharp.Compiler.Cancellable.UsingToken CancellationToken.None
367
+ run code
367
368
368
369
let toAsync code =
369
370
async {
370
- let! ct = Async.CancellationToken
371
-
372
- return run ct code |> _. Result
371
+ use! _holder = FSharp.Compiler.Cancellable.UseToken()
372
+ return run code
373
373
}
374
374
375
375
let token () =
0 commit comments