Fsharp: [External] Interrupting dotnet fsi results in unhandled PlatformNotSupportedException

Created on 4 Jun 2020  Â·  13Comments  Â·  Source: dotnet/fsharp

Repro steps

In a dotnet fsi interactive session, when I interrupt a long-running operating (e.g. by typing Ctrl+C), an unhandled PlatformNotSupportedException will be thrown, killing the process:

$ dotnet fsi

Microsoft (R) F# Interactive version 11.0.0.0 for F# 5.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> System.Threading.Thread.Sleep(100_000) ;;

- Interrupt
Unhandled exception. System.PlatformNotSupportedException: Thread abort is not supported on this platform.
   at System.Threading.Thread.Abort()
   at [email protected]() in F:\workspace\_work\1\s\src\fsharp\fsi\fsi.fs:line 1727
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Related information

Provide any related information (optional):

  • Operating system: Windows and Linux
  • .NET Runtime kind: .NET Core version 5.0.100-preview.6.20301.1
Area-FSI bug

Most helpful comment

The general request for uncooperative cancellation in .NET Core for developer evaluation scenarios is now here: https://github.com/dotnet/runtime/issues/41291.

@jkotas seems to think that it's plausible to recover this for non-production scenarios (that is, the abort is being issued by a developer/script-kiddy, and not routinely by code or users as part of production execution of apps). See https://github.com/dotnet/runtime/issues/11369#issuecomment-679326726

...the proper job is to execute the script in a separate process, and then we can just do a process kill on it. I expect we make a ton of assumptions that the repl and the executed code are in the same process, but I think that a separate process is the way to go.

The main rationale for Ctrl-C cancellation is that it doesn't require process restart (and specifically it doesn't require loss of established definitions and re-loading of massive data sets).

As @jkotas mentions using a separate process might be feasible if all work is submitted bia the debug API via FuncEval. Then Ctrl-C Abort is the same as FuncEval Abort. However then the VS debugger can't connect to that same process..... (among other potential issues like performance etc.)

All 13 comments

Don't know if it's a bug on our end. It seems the API Thread.Abort is not supported on the platform for some reason?

It seems the API Thread.Abort is not supported on the platform for some reason?

Correct, it's not support at all in .NET Core. I feel there's probably no good workaround to this, but perhaps it could be handled more gracefully.

Is there another way than Thread.Abort to interrupt an operation? Otherwise, the Ctrl-C handler could be placed in a try/with and just break, but not print the exception?

I've noticed in VS in the FSI window that some exceptions make the prompt disappear (but you can still continue writing a new statement). Maybe that's related.

It seems like we're just not doing it right here. Sounds like the proper solution is cancellation: https://stackoverflow.com/questions/53465551/dotnet-core-equivalent-to-thread-abort

Interesting, but that won't stop hanging threads, unless the cancelation token is queried regularly (if I understand that post correctly). In the same SO thread two forceful alternatives are also mentioned, they could be used as a last resort method of cancelation fails.

The problem is that the repl can execute arbitrary .NET code, and as such,
cooperative cancellation cannot be used.

On Fri, 5 Jun 2020, 21:13 Abel Braaksma, notifications@github.com wrote:

Interesting, but that won't stop hanging threads, unless the cancelation
token is queried regularly (if I understand that post correctly). In the
same SO thread two forceful alternatives are also mentioned, they could be
used as a last resort method of cancelation fails.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/dotnet/fsharp/issues/9397#issuecomment-639774993, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AAVO3M372E2KIGF7LPPCEPTRVFGYBANCNFSM4NS5BAKA
.

I didn't know about this issue until now. I'm seriously surprised that .NET Core removed all support for Thread.Abort - it is needed in interruptible interactive execution scenarios.

There's not a whole lot we can do about this. We could try to cancel by setting a checkable flag and/or Async.DefaultCancellationToken but to be honest the cancellation feature just isn't going to be particularly useful in .NET Core F# Scripting at this stage.

Here's a comment explaining the rationale behind deprecation. FWIW Thread.Abort() in of itself cannot guarantee cancellation in general, e.g. when running async code.

Perhaps then the best workaround here is to advance the repl state without attempting to cancel the worker thread. The user can then make the call whether to kill the session altogether, assuming the divergent thread significantly impacts the process health.

Perhaps then the best workaround here is to advance the repl state without attempting to cancel the worker thread. The user can then make the call whether to kill the session altogether, assuming the divergent thread significantly impacts the process health.

Yes, this seems sensible, though we'd need a new execution thread.

@KevinRansom We should consider this, rather than crashing.

I will spend some time thinking about this ... however, I think the proper job is to execute the script in a separate process, and then we can just do a process kill on it. I expect we make a ton of assumptions that the repl and the executed code are in the same process, but I think that a separate process is the way to go.

The general request for uncooperative cancellation in .NET Core for developer evaluation scenarios is now here: https://github.com/dotnet/runtime/issues/41291.

@jkotas seems to think that it's plausible to recover this for non-production scenarios (that is, the abort is being issued by a developer/script-kiddy, and not routinely by code or users as part of production execution of apps). See https://github.com/dotnet/runtime/issues/11369#issuecomment-679326726

...the proper job is to execute the script in a separate process, and then we can just do a process kill on it. I expect we make a ton of assumptions that the repl and the executed code are in the same process, but I think that a separate process is the way to go.

The main rationale for Ctrl-C cancellation is that it doesn't require process restart (and specifically it doesn't require loss of established definitions and re-loading of massive data sets).

As @jkotas mentions using a separate process might be feasible if all work is submitted bia the debug API via FuncEval. Then Ctrl-C Abort is the same as FuncEval Abort. However then the VS debugger can't connect to that same process..... (among other potential issues like performance etc.)

That's an interesting development and proposal and would certainly help here. I hope it will be considered :).

I will spend some time thinking about this ... however, I think the proper job is to execute the script in a separate process, and then we can just do a process kill on it. I expect we make a ton of assumptions that the repl and the executed code are in the same process, but I think that a separate process is the way to go.

@KevinRansom @dsyme My use case of F# scripting requires my FCS Evaluation sessions to be hosted in process. Would this change with the above proposal? Thread.Abort works well for me (on .NET Framework)

Was this page helpful?
0 / 5 - 0 ratings