Skip to content

Commit

Permalink
Fix LinkedSubSource leak in Async.Choice (#7892)
Browse files Browse the repository at this point in the history
* Fix LinkedSubSource leak in Async.Choice

* ref -> mutable
  • Loading branch information
Frassle authored and KevinRansom committed Nov 28, 2019
1 parent cab0520 commit acafb50
Showing 1 changed file with 38 additions and 19 deletions.
57 changes: 38 additions & 19 deletions src/fsharp/FSharp.Core/async.fs
Expand Up @@ -1293,35 +1293,54 @@ namespace Microsoft.FSharp.Control
| Choice1Of2 computations ->
ProtectedCode ctxt (fun ctxt ->
let ctxtWithSync = DelimitSyncContext ctxt
let noneCount = ref 0
let exnCount = ref 0
let mutable count = computations.Length
let mutable noneCount = 0
let mutable someOrExnCount = 0
let innerCts = new LinkedSubSource(ctxtWithSync.token)

let scont (result: 'T option) =
match result with
| Some _ ->
if Interlocked.Increment exnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.cont result)
let result =
match result with
| Some _ ->
if Interlocked.Increment &someOrExnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.cont result)
else
fake()

| None ->
if Interlocked.Increment &noneCount = computations.Length then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.cont None)
else
fake()

if Interlocked.Decrement &count = 0 then
innerCts.Dispose()

result

let econt (exn: ExceptionDispatchInfo) =
let result =
if Interlocked.Increment &someOrExnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.econt exn)
else
fake()

| None ->
if Interlocked.Increment noneCount = computations.Length then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.cont None)
if Interlocked.Decrement &count = 0 then
innerCts.Dispose()

result

let ccont (exn: OperationCanceledException) =
let result =
if Interlocked.Increment &someOrExnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.ccont exn)
else
fake()

let econt (exn: ExceptionDispatchInfo) =
if Interlocked.Increment exnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.econt exn)
else
fake()
if Interlocked.Decrement &count = 0 then
innerCts.Dispose()

let ccont (exn: OperationCanceledException) =
if Interlocked.Increment exnCount = 1 then
innerCts.Cancel(); ctxtWithSync.trampolineHolder.ExecuteWithTrampoline (fun () -> ctxtWithSync.ccont exn)
else
fake()
result

for c in computations do
QueueAsync innerCts.Token scont econt ccont c |> unfake
Expand Down

0 comments on commit acafb50

Please sign in to comment.