@@ -787,14 +787,12 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s
787787 member __.Gui = gui
788788
789789/// Set the current ui culture for the current thread.
790- #if FX_ LCIDFROMCODEPAGE
791790let internal SetCurrentUICultureForThread ( lcid : int option ) =
792791 let culture = Thread.CurrentThread.CurrentUICulture
793792 match lcid with
794793 | Some n -> Thread.CurrentThread.CurrentUICulture <- new CultureInfo( n)
795794 | None -> ()
796795 { new IDisposable with member x.Dispose () = Thread.CurrentThread.CurrentUICulture <- culture }
797- #endif
798796
799797//----------------------------------------------------------------------------
800798// Reporting - warnings, errors
@@ -1336,22 +1334,18 @@ type internal FsiDynamicCompiler
13361334 member __.FormatValue ( obj : obj , objTy ) =
13371335 valuePrinter.FormatValue( obj, objTy)
13381336
1339-
13401337//----------------------------------------------------------------------------
13411338// ctrl-c handling
13421339//----------------------------------------------------------------------------
13431340
1344- module internal NativeMethods =
1345-
1346- type ControlEventHandler = delegate of int -> bool
1341+ type ControlEventHandler = delegate of int -> bool
13471342
1348- [<DllImport( " kernel32.dll" ) >]
1349- extern bool SetConsoleCtrlHandler( ControlEventHandler _ callback, bool _ add)
13501343
13511344// One strange case: when a TAE happens a strange thing
13521345// occurs the next read from stdin always returns
13531346// 0 bytes, i.e. the channel will look as if it has been closed. So we check
13541347// for this condition explicitly. We also recreate the lexbuf whenever CtrlC kicks.
1348+
13551349type internal FsiInterruptStdinState =
13561350 | StdinEOFPermittedBecauseCtrlCRecentlyPressed
13571351 | StdinNormal
@@ -1366,149 +1360,74 @@ type internal FsiInterruptControllerKillerThreadRequest =
13661360 | ExitRequest
13671361 | PrintInterruptRequest
13681362
1369- type internal FsiInterruptController ( fsiOptions : FsiCommandLineOptions ,
1370- fsiConsoleOutput: FsiConsoleOutput) =
1363+ type internal FsiInterruptController ( fsiOptions : FsiCommandLineOptions , fsiConsoleOutput : FsiConsoleOutput ) =
13711364
13721365 let mutable stdinInterruptState = StdinNormal
13731366 let CTRL_C = 0
13741367 let mutable interruptAllowed = InterruptIgnored
13751368 let mutable killThreadRequest = NoRequest
1376- let mutable ctrlEventHandlers = [] : NativeMethods.ControlEventHandler list
1377- let mutable ctrlEventActions = [] : ( unit -> unit) list
1369+
1370+ let mutable ctrlEventHandlers = []: ControlEventHandler list
1371+ let mutable ctrlEventActions = []: ( unit -> unit) list
13781372 let mutable exitViaKillThread = false
13791373
13801374 let mutable posixReinstate = ( fun () -> ())
13811375
1382- member __.Exit () =
1383- if exitViaKillThread then
1376+ member __.Exit () =
1377+ if exitViaKillThread then
13841378 killThreadRequest <- ExitRequest
13851379 Thread.Sleep( 1000 )
13861380 exit 0
13871381
1388- member __.FsiInterruptStdinState with get () = stdinInterruptState and set v = stdinInterruptState <- v
1382+ member __.FsiInterruptStdinState
1383+ with get () = stdinInterruptState
1384+ and set v = stdinInterruptState <- v
13891385
13901386 member __.ClearInterruptRequest () = killThreadRequest <- NoRequest
1391-
1392- member __.InterruptAllowed with set v = interruptAllowed <- v
1393-
1387+
1388+ member __.InterruptAllowed
1389+ with set v = interruptAllowed <- v
1390+
13941391 member __.Interrupt () = ctrlEventActions |> List.iter ( fun act -> act())
1395-
1392+
13961393 member __.EventHandlers = ctrlEventHandlers
13971394
1398- // REVIEW: streamline all this code to use the same code on Windows and Posix.
1399- member controller.InstallKillThread ( threadToKill : Thread , pauseMilliseconds : int ) =
1400- #if DYNAMIC_ CODE_ EMITS_ INTERRUPT_ CHECKS
1401- let action () =
1402- Microsoft.FSharp.Silverlight.InterruptThread( threadToKill.ManagedThreadId)
1395+ member controller.InstallKillThread ( threadToKill : Thread , pauseMilliseconds : int ) =
14031396
1404- ctrlEventActions <- action :: ctrlEventActions;
1405- #else
1406- #if FX_ NO_ THREADABORT
1407- ignore threadToKill
1408- ignore pauseMilliseconds
1409- ignore fsiConsoleOutput
1410- ignore CTRL_ C
1411- ignore fsiOptions
1412- exitViaKillThread <- false
1413- #else
1414- if ! progress then fprintfn fsiConsoleOutput.Out " installing CtrlC handler"
1415- // WINDOWS TECHNIQUE: .NET has more safe points, and you can do more when a safe point.
1416- // Hence we actually start up the killer thread within the handler.
1417- try
1418- let raiseCtrlC () =
1419- #if FX_ LCIDFROMCODEPAGE
1420- use _scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
1421- #else
1422- ignore fsiOptions
1423- #endif
1424- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiInterrupt())
1425- stdinInterruptState <- StdinEOFPermittedBecauseCtrlCRecentlyPressed
1426- if ( interruptAllowed = InterruptCanRaiseException) then
1427- killThreadRequest <- ThreadAbortRequest
1428- let killerThread =
1429- new Thread( new ThreadStart( fun () ->
1430- #if FX_ LCIDFROMCODEPAGE
1431- use _ scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
1432- #endif
1433- // sleep long enough to allow ControlEventHandler handler on main thread to return
1434- // Also sleep to give computations a bit of time to terminate
1435- Thread.Sleep( pauseMilliseconds)
1436- if ( killThreadRequest = ThreadAbortRequest) then
1437- if ! progress then fsiConsoleOutput.uprintnfn " %s " ( FSIstrings.SR.fsiAbortingMainThread())
1438- killThreadRequest <- NoRequest
1439- threadToKill.Abort()
1440- ()), Name= " ControlCAbortThread" )
1441- killerThread.IsBackground <- true
1442- killerThread.Start()
1443-
1444- let ctrlEventHandler = new NativeMethods.ControlEventHandler( fun i -> if i = CTRL_ C then ( raiseCtrlC(); true ) else false )
1445- ctrlEventHandlers <- ctrlEventHandler :: ctrlEventHandlers
1446- ctrlEventActions <- raiseCtrlC :: ctrlEventActions
1447- let _resultOK = NativeMethods.SetConsoleCtrlHandler( ctrlEventHandler, true )
1448- exitViaKillThread <- false // don't exit via kill thread
1449- with e ->
1450- if ! progress then fprintfn fsiConsoleOutput.Error " Failed to install ctrl-c handler using Windows technique - trying to install one using Unix signal handling..." ;
1451- // UNIX TECHNIQUE: We start up a killer thread, and it watches the mutable reference location.
1452- // We can't have a dependency on Mono DLLs (indeed we don't even have them!)
1453- // So SOFT BIND the following code:
1454- // Mono.Unix.Native.Stdlib.signal(Mono.Unix.Native.Signum.SIGINT,new Mono.Unix.Native.SignalHandler(fun n -> PosixSignalProcessor.PosixInvoke(n))) |> ignore;
1455- match ( try Choice1Of2( Assembly.Load( new System.Reflection.AssemblyName( " Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" ))) with e -> Choice2Of2 e) with
1456- | Choice1Of2( monoPosix) ->
1457- try
1458- if ! progress then fprintfn fsiConsoleOutput.Error " loading type Mono.Unix.Native.Stdlib..."
1459- let monoUnixStdlib = monoPosix.GetType( " Mono.Unix.Native.Stdlib" )
1460- if ! progress then fprintfn fsiConsoleOutput.Error " loading type Mono.Unix.Native.SignalHandler..."
1461- let monoUnixSignalHandler = monoPosix.GetType( " Mono.Unix.Native.SignalHandler" )
1462- if ! progress then fprintfn fsiConsoleOutput.Error " creating delegate..."
1463- controller.PosixInvoke(- 1 )
1464- let monoHandler = System.Delegate.CreateDelegate( monoUnixSignalHandler, controller, " PosixInvoke" )
1465- if ! progress then fprintfn fsiConsoleOutput.Error " registering signal handler..."
1466- let monoSignalNumber = System.Enum.Parse( monoPosix.GetType( " Mono.Unix.Native.Signum" ), " SIGINT" )
1467- let register () = Utilities.callStaticMethod monoUnixStdlib " signal" [ monoSignalNumber; box monoHandler ] |> ignore
1468- posixReinstate <- register
1469- register()
1397+ // Fsi Interupt handler
1398+ let raiseCtrlC () =
1399+ use _scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
1400+ fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiInterrupt())
1401+
1402+ stdinInterruptState <- StdinEOFPermittedBecauseCtrlCRecentlyPressed
1403+ if ( interruptAllowed = InterruptCanRaiseException) then
1404+ killThreadRequest <- ThreadAbortRequest
14701405 let killerThread =
14711406 new Thread( new ThreadStart( fun () ->
1472- #if FX_ LCIDFROMCODEPAGE
14731407 use _ scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
1474- #endif
1475- while true do
1476- //fprintf fsiConsoleOutput.Error "\n- kill thread loop...\n"; errorWriter.Flush();
1477- Thread.Sleep( pauseMilliseconds* 2 )
1478- match killThreadRequest with
1479- | PrintInterruptRequest ->
1480- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiInterrupt()); fsiConsoleOutput.Error.Flush()
1481- killThreadRequest <- NoRequest
1482- | ThreadAbortRequest ->
1483- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiInterrupt()); fsiConsoleOutput.Error.Flush()
1484- if ! progress then fsiConsoleOutput.uprintnfn " %s " ( FSIstrings.SR.fsiAbortingMainThread())
1485- killThreadRequest <- NoRequest
1486- threadToKill.Abort()
1487- | ExitRequest ->
1488- // Mono has some weird behaviour where it blocks on exit
1489- // once CtrlC has ever been pressed. Who knows why? Perhaps something
1490- // to do with having a signal handler installed, but it only happens _after_
1491- // at least one CtrLC has been pressed. Maybe raising a ThreadAbort causes
1492- // exiting to have problems.
1493- //
1494- // Anyway, we make "#q" work this case by setting ExitRequest and brutally calling
1495- // the process-wide 'exit'
1496- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiExit()); fsiConsoleOutput.Error.Flush()
1497- Utilities.callStaticMethod monoUnixStdlib " exit" [ box 0 ] |> ignore
1498- | _ -> ()
1499- done ), Name= " ControlCAbortAlternativeThread" )
1408+ // sleep long enough to allow ControlEventHandler handler on main thread to return
1409+ // Also sleep to give computations a bit of time to terminate
1410+ Thread.Sleep( pauseMilliseconds)
1411+ if ( killThreadRequest = ThreadAbortRequest) then
1412+ if ! progress then fsiConsoleOutput.uprintnfn " %s " ( FSIstrings.SR.fsiAbortingMainThread())
1413+ killThreadRequest <- NoRequest
1414+ threadToKill.Abort()
1415+ ()), Name= " ControlCAbortThread" )
15001416 killerThread.IsBackground <- true
15011417 killerThread.Start()
1502- // exit via kill thread to workaround block-on-exit bugs with Mono once a CtrlC has been pressed
1503- exitViaKillThread <- true
1504- with e ->
1505- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiCouldNotInstallCtrlCHandler( e.Message))
1506- exitViaKillThread <- false
1507- | Choice2Of2 e ->
1508- fprintf fsiConsoleOutput.Error " %s " ( FSIstrings.SR.fsiCouldNotInstallCtrlCHandler( e.Message))
1509- exitViaKillThread <- false
1510- #endif
15111418
1419+ let fsiInterruptHandler ( args : ConsoleCancelEventArgs ) =
1420+ args.Cancel <- true
1421+ ctrlEventHandlers |> List.iter( fun handler -> handler.Invoke( CTRL_ C) |> ignore)
1422+
1423+ do Console.CancelKeyPress.Add( fsiInterruptHandler)
1424+
1425+ // WINDOWS TECHNIQUE: .NET has more safe points, and you can do more when a safe point.
1426+ // Hence we actually start up the killer thread within the handler.
1427+ let ctrlEventHandler = new ControlEventHandler( fun i -> if i = CTRL_ C then ( raiseCtrlC(); true ) else false )
1428+ ctrlEventHandlers <- ctrlEventHandler :: ctrlEventHandlers
1429+ ctrlEventActions <- raiseCtrlC :: ctrlEventActions
1430+ exitViaKillThread <- false // don't exit via kill thread
15121431
15131432 member x.PosixInvoke ( n : int ) =
15141433 // we run this code once with n = -1 to make sure it is JITted before execution begins
@@ -1519,8 +1438,6 @@ type internal FsiInterruptController(fsiOptions : FsiCommandLineOptions,
15191438 stdinInterruptState <- StdinEOFPermittedBecauseCtrlCRecentlyPressed
15201439 killThreadRequest <- if ( interruptAllowed = InterruptCanRaiseException) then ThreadAbortRequest else PrintInterruptRequest
15211440
1522- #endif
1523-
15241441//----------------------------------------------------------------------------
15251442// assembly finder
15261443//----------------------------------------------------------------------------
@@ -1809,9 +1726,7 @@ type internal FsiInteractionProcessor
18091726
18101727 // FSI error logging on switched to thread
18111728 InstallErrorLoggingOnThisThread errorLogger
1812- #if FX_ LCIDFROMCODEPAGE
18131729 use _ scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
1814- #endif
18151730 f ctok istate)
18161731 with _ ->
18171732 ( istate, Completed None)
@@ -2185,9 +2100,7 @@ type internal FsiInteractionProcessor
21852100 member __.EvalInteraction ( ctok , sourceText , scriptFileName , errorLogger ) =
21862101 use _unwind1 = ErrorLogger.PushThreadBuildPhaseUntilUnwind( ErrorLogger.BuildPhase.Interactive)
21872102 use _unwind2 = ErrorLogger.PushErrorLoggerPhaseUntilUnwind( fun _ -> errorLogger)
2188- #if FX_ LCIDFROMCODEPAGE
21892103 use _scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
2190- #endif
21912104 let lexbuf = UnicodeLexing.StringAsLexbuf( sourceText)
21922105 let tokenizer = fsiStdinLexerProvider.CreateBufferLexer( scriptFileName, lexbuf, errorLogger)
21932106 currState
@@ -2204,9 +2117,7 @@ type internal FsiInteractionProcessor
22042117 member __.EvalExpression ( ctok , sourceText , scriptFileName , errorLogger ) =
22052118 use _unwind1 = ErrorLogger.PushThreadBuildPhaseUntilUnwind( ErrorLogger.BuildPhase.Interactive)
22062119 use _unwind2 = ErrorLogger.PushErrorLoggerPhaseUntilUnwind( fun _ -> errorLogger)
2207- #if FX_ LCIDFROMCODEPAGE
22082120 use _scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
2209- #endif
22102121 let lexbuf = UnicodeLexing.StringAsLexbuf( sourceText)
22112122 let tokenizer = fsiStdinLexerProvider.CreateBufferLexer( scriptFileName, lexbuf, errorLogger)
22122123 currState
@@ -2235,9 +2146,7 @@ type internal FsiInteractionProcessor
22352146 let stdinReaderThread =
22362147 new Thread( new ThreadStart( fun () ->
22372148 InstallErrorLoggingOnThisThread errorLogger // FSI error logging on stdinReaderThread, e.g. parse errors.
2238- #if FX_ LCIDFROMCODEPAGE
22392149 use _ scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
2240- #endif
22412150 try
22422151 try
22432152 let initialTokenizer = fsiStdinLexerProvider.CreateStdinLexer( errorLogger)
@@ -2341,9 +2250,7 @@ let internal SpawnInteractiveServer
23412250 fsiConsoleOutput : FsiConsoleOutput ) =
23422251 //printf "Spawning fsi server on channel '%s'" !fsiServerName;
23432252 SpawnThread " ServerThread" ( fun () ->
2344- #if FX_ LCIDFROMCODEPAGE
23452253 use _ scope = SetCurrentUICultureForThread fsiOptions.FsiLCID
2346- #endif
23472254 try
23482255 fsi.StartServer( fsiOptions.FsiServerName)
23492256 with e ->
0 commit comments