Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions src/fsharp/FSharp.Core/async.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,8 +1066,8 @@ namespace Microsoft.FSharp.Control
[<DebuggerHidden>]
let RunSynchronously cancellationToken (computation: Async<'T>) timeout =
// Reuse the current ThreadPool thread if possible.
match Thread.CurrentThread.IsThreadPoolThread, timeout with
| true, None -> RunImmediate cancellationToken computation
match SynchronizationContext.Current, Thread.CurrentThread.IsThreadPoolThread, timeout with
| null, true, None -> RunImmediate cancellationToken computation
| _ -> QueueAsyncAndWaitForResultSynchronously cancellationToken computation timeout

[<DebuggerHidden>]
Expand Down
11 changes: 8 additions & 3 deletions src/fsharp/FSharp.Core/async.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,19 @@ namespace Microsoft.FSharp.Control
///
/// If no cancellation token is provided then the default cancellation token is used.
///
/// The computation is started on the current thread if <see cref="P:System.Threading.SynchronizationContext.Current"/> is null,
/// <see cref="P:System.Threading.Thread.CurrentThread"/> has <see cref="P:System.Threading.Thread.IsThreadPoolThread"/>
/// of <c>true</c>, and no timeout is specified. Otherwise the computation is started by queueing a new work item in the thread pool,
/// and the current thread is blocked awaiting the completion of the computation.
///
/// The timeout parameter is given in milliseconds. A value of -1 is equivalent to
/// System.Threading.Timeout.Infinite.</remarks>
/// <see cref="F:System.Threading.Timeout.Infinite"/>.
/// </remarks>
///
/// <param name="computation">The computation to run.</param>
/// <param name="timeout">The amount of time in milliseconds to wait for the result of the
/// computation before raising a <see cref="T:System.TimeoutException"/>. If no value is provided
/// for timeout then a default of -1 is used to correspond to <see cref="F:System.Threading.Timeout.Infinite"/>.
/// If a cancellable cancellationToken is provided, timeout parameter will be ignored</param>
/// for timeout then a default of -1 is used to correspond to <see cref="F:System.Threading.Timeout.Infinite"/>.</param>
/// <param name="cancellationToken">The cancellation token to be associated with the computation.
/// If one is not supplied, the default cancellation token is used.</param>
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,20 +409,40 @@ type AsyncModule() =
[<Fact>]
member _.``RunSynchronously.NoThreadJumpsAndTimeout.DifferentSyncContexts``() =
let run syncContext =
let old = System.Threading.SynchronizationContext.Current
System.Threading.SynchronizationContext.SetSynchronizationContext(syncContext)
let old = SynchronizationContext.Current
SynchronizationContext.SetSynchronizationContext(syncContext)
let longRunningTask = async { sleep(5000) }
let mutable failed = false
try
Async.RunSynchronously(longRunningTask, timeout = 500)
failed <- true
with
:? System.TimeoutException -> ()
System.Threading.SynchronizationContext.SetSynchronizationContext(old)
SynchronizationContext.SetSynchronizationContext(old)
if failed then Assert.Fail("TimeoutException expected")
run null
run (System.Threading.SynchronizationContext())

[<Fact>]
// See https://github.com/dotnet/fsharp/issues/12637#issuecomment-1020199383
member _.``RunSynchronously.ThreadJump.IfSyncCtxtNonNull``() =
async {
do! Async.SwitchToThreadPool()
let old = SynchronizationContext.Current
SynchronizationContext.SetSynchronizationContext(SynchronizationContext())
Assert.NotNull(SynchronizationContext.Current)
Assert.True(Thread.CurrentThread.IsThreadPoolThread)
let computation =
async {
let ctxt = SynchronizationContext.Current
Assert.Null(ctxt)
Assert.True(Thread.CurrentThread.IsThreadPoolThread)
}
Async.RunSynchronously(computation)
SynchronizationContext.SetSynchronizationContext(old)
}
|> Async.RunSynchronously

[<Fact>]
member _.``RaceBetweenCancellationAndError.AwaitWaitHandle``() =
let disposedEvent = new System.Threading.ManualResetEvent(false)
Expand Down