From 5d84b05c8b518e63dc12b8af05f8c87bc0861312 Mon Sep 17 00:00:00 2001 From: KevinRansom Date: Wed, 24 Aug 2022 01:31:15 -0700 Subject: [PATCH] Rework to ctrl+C to match updated apis --- src/Compiler/Checking/CheckExpressions.fsi | 1 - .../Interactive/ControlledExecution.fs | 61 ++++++++----------- src/Compiler/Interactive/fsi.fs | 10 ++- 3 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fsi b/src/Compiler/Checking/CheckExpressions.fsi index 3b70a5caa1e..0bbaca89177 100644 --- a/src/Compiler/Checking/CheckExpressions.fsi +++ b/src/Compiler/Checking/CheckExpressions.fsi @@ -126,7 +126,6 @@ val TcFieldInit: range -> ILFieldInit -> Const val LightweightTcValForUsingInBuildMethodCall: g: TcGlobals -> vref: ValRef -> vrefFlags: ValUseFlag -> vrefTypeInst: TTypes -> m: range -> Expr * TType - /// Indicates whether a syntactic type is allowed to include new type variables /// not declared anywhere, e.g. `let f (x: 'T option) = x.Value` type ImplicitlyBoundTyparsAllowed = diff --git a/src/Compiler/Interactive/ControlledExecution.fs b/src/Compiler/Interactive/ControlledExecution.fs index 5ec0e929c0c..81faf21576a 100644 --- a/src/Compiler/Interactive/ControlledExecution.fs +++ b/src/Compiler/Interactive/ControlledExecution.fs @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -// This wraps System.Runtime.CompilerServices.ControlledExecution +// This wraps System.Runtime.ControlledExecution // This class enables scripting engines such as Fsi to abort threads safely in the coreclr // This functionality will be introduced in .net 7.0. -// because we continue to dupport older coreclrs and the windows desktop framework through netstandard2.0 +// because we continue to support older coreclrs and the windows desktop framework through netstandard2.0 // we access the features using reflection namespace FSharp.Compiler.Interactive @@ -14,54 +14,43 @@ open System.Threading open Internal.Utilities.FSharpEnvironment -type internal ControlledExecution (thread:Thread) = +open Unchecked + +type internal ControlledExecution () = + + let mutable cts: CancellationTokenSource voption = ValueNone + let mutable thread: Thread voption = ValueNone static let ceType: Type option = - Option.ofObj (Type.GetType("System.Runtime.CompilerServices.ControlledExecution, System.Private.CoreLib", false)) + Option.ofObj (Type.GetType("System.Runtime.ControlledExecution, System.Private.CoreLib", false)) static let threadType: Type option = Option.ofObj (typeof) - static let ceConstructor: ConstructorInfo option = - match ceType with - | None -> None - | Some t -> Option.ofObj (t.GetConstructor([|typeof|])) - static let ceRun: MethodInfo option = match ceType with | None -> None - | Some t -> Option.ofObj (t.GetMethod("Run", [||]) ) - - static let ceTryAbort: MethodInfo option = - match ceType with - | None -> None - | Some t -> Option.ofObj (t.GetMethod("TryAbort", [|typeof|])) + | Some t -> Option.ofObj (t.GetMethod("Run", BindingFlags.Static ||| BindingFlags.Public, defaultof, [|typeof; typeof|], [||] )) static let threadResetAbort: MethodInfo option = match isRunningOnCoreClr, threadType with | false, Some t -> Option.ofObj (t.GetMethod("ResetAbort", [||])) | _ -> None - let newInstance (action: Action) = - match ceConstructor with - | None -> None - | Some c -> Option.ofObj (c.Invoke([|action|])) - - let mutable instance = Unchecked.defaultof - - member this.Run(action: Action) = - let newinstance = newInstance(action) - match newinstance, ceRun with - | Some inst, Some ceRun -> - instance <- newinstance - ceRun.Invoke(inst, [||]) |> ignore - | _ -> action.Invoke() - - member _.TryAbort(timeout: TimeSpan): bool = - match isRunningOnCoreClr, instance, ceTryAbort with - | _, Some instance, Some tryAbort -> tryAbort.Invoke(instance, [|timeout|]) :?> bool - | false, _, _ -> thread.Abort(); true - | true, _, _ -> true + member _.Run (action: Action) = + match ceRun with + | Some run -> + cts <- ValueSome (new CancellationTokenSource()) + run.Invoke(null, [|action; cts.Value.Token|]) |> ignore + | _ -> + thread <- ValueSome (Thread.CurrentThread) + action.Invoke() + + member _.TryAbort(): unit = + match isRunningOnCoreClr, cts, thread with + | true, ValueSome cts, _ -> cts.Cancel() + | false, _, ValueSome thread -> thread.Abort(); () + | _ -> () member _.ResetAbort() = match thread, threadResetAbort with @@ -72,4 +61,4 @@ type internal ControlledExecution (thread:Thread) = match exn with | :? TargetInvocationException as e when not(isNull e.InnerException) -> ControlledExecution.StripTargetInvocationException(e.InnerException) - | _ -> exn + | _ -> exn \ No newline at end of file diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 32a8ad40592..d2632c3fe69 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -2262,10 +2262,7 @@ type internal FsiInterruptController( if killThreadRequest = ThreadAbortRequest then if progress then fsiConsoleOutput.uprintnfn "%s" (FSIstrings.SR.fsiAbortingMainThread()) killThreadRequest <- NoRequest - let rec abortLoop n = - if n > 0 then - if not (controlledExecution.TryAbort(TimeSpan.FromSeconds(30))) then abortLoop (n-1) - abortLoop 3 + controlledExecution.TryAbort() ()), Name="ControlCAbortThread") killerThread.IsBackground <- true killerThread.Start() @@ -2888,7 +2885,8 @@ type FsiInteractionProcessor fsiInterruptController.ControlledExecution().ResetAbort() (istate,CtrlC) - | :? TargetInvocationException as e when (ControlledExecution.StripTargetInvocationException(e)).GetType().Name = "ThreadAbortException" -> + | :? TargetInvocationException as e when (ControlledExecution.StripTargetInvocationException(e)).GetType().Name = "ThreadAbortException" || + (ControlledExecution.StripTargetInvocationException(e)).GetType().Name = "OperationCanceledException" -> fsiInterruptController.ClearInterruptRequest() fsiInterruptController.InterruptAllowed <- InterruptIgnored fsiInterruptController.ControlledExecution().ResetAbort() @@ -3386,7 +3384,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i let fsiDynamicCompiler = FsiDynamicCompiler(fsi, timeReporter, tcConfigB, tcLockObject, outWriter, tcImports, tcGlobals, fsiOptions, fsiConsoleOutput, fsiCollectible, niceNameGen, resolveAssemblyRef) - let controlledExecution = ControlledExecution(Thread.CurrentThread) + let controlledExecution = ControlledExecution() let fsiInterruptController = FsiInterruptController(fsiOptions, controlledExecution, fsiConsoleOutput)