Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
.
  • Loading branch information
majocha committed Feb 1, 2024
commit a5a96058cb35750a28a07244ce65c7fbde70a663
25 changes: 15 additions & 10 deletions src/Compiler/Facilities/BuildGraph.fs
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,37 @@ type GraphNode<'T> private (compute: unit -> unit, tcs: TaskCompletionSource<'T>
(tcs.SetException),
(ignore >> tcs.SetCanceled),
// This is not a requestor's CancellationToken.
cts.Token)
cts.Token
)

GraphNode(compute, tcs, cts)

member _.GetOrComputeValue() =

// Lock for the sake of `started` flag.
let startNew = lock gate <| fun () ->
Interlocked.Increment &requestCount = 1 && not started
// The cancellation of the computation is not governed by the requestor's CancellationToken.
let startNew =
lock gate <| fun () -> Interlocked.Increment &requestCount = 1 && not started

// The cancellation of the computation is not governed by the requestor's CancellationToken.
// It will continue to run as long as there are requests.
if startNew then started <- true; compute()
if startNew then
started <- true
compute ()

async {
try
try
return! tcs.Task |> Async.AwaitTask
finally
if Interlocked.Decrement &requestCount = 0 then
// All requestors either finished or cancelled, so it is safe to cancel either way.
cts.Cancel()
}


member _.TryPeekValue() = if tcs.Task.IsCompleted then ValueSome tcs.Task.Result else ValueNone
member _.TryPeekValue() =
if tcs.Task.IsCompleted then
ValueSome tcs.Task.Result
else
ValueNone

member _.HasValue = tcs.Task.IsCompleted

Expand All @@ -99,4 +105,3 @@ type GraphNode<'T> private (compute: unit -> unit, tcs: TaskCompletionSource<'T>
let tcs = TaskCompletionSource()
tcs.SetResult result
GraphNode(ignore, tcs, new CancellationTokenSource())

8 changes: 4 additions & 4 deletions tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ module BuildGraphTests =

[<Fact>]
let ``Many requests to get a value asynchronously should only evaluate the computation once``() =
let requests = 10000
let requests = 10
let mutable computationCount = 0

let graphNode =
Expand All @@ -81,7 +81,7 @@ module BuildGraphTests =

[<Fact>]
let ``Many requests to get a value asynchronously should get the correct value``() =
let requests = 10000
let requests = 10

let graphNode = GraphNode(async { return 1 })

Expand Down Expand Up @@ -111,7 +111,7 @@ module BuildGraphTests =

[<Fact>]
let ``Many requests to get a value asynchronously should have its computation cleaned up by the GC``() =
let requests = 10000
let requests = 10

let weak =

Expand Down Expand Up @@ -177,7 +177,7 @@ module BuildGraphTests =

[<Fact>]
let ``Many requests to get a value asynchronously will never evaluate the value more than once``() =
let requests = 10000
let requests = 10
let resetEvent = new ManualResetEvent(false)
let mutable computationCountBeforeSleep = 0
let mutable computationCount = 0
Expand Down