Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-cooperative cancellation/abort/interrupt for interactive execution environments #41291

Closed
dsyme opened this issue Aug 24, 2020 · 15 comments
Closed
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-VM-coreclr
Milestone

Comments

@dsyme
Copy link

dsyme commented Aug 24, 2020

There are a range of execution environments for .NET code that have historically utilised non-cooperative cancellation. These environments have the following characteristics

  1. in-process compilation and execution

  2. execute arbitrary .NET code entered interactively by the user

  3. use arbitrary .NET libraries

  4. most user code runs solely on one specific known thread

  5. these are developer scenarios (not production scenarios) - in the sense that the developer is issuing the abort while coding/executing and it is not happening as a routine part of production execution

  6. reliability of the cancellation mechanism must be "good" but need not be "perfect" - occasional weirdness requiring process restart is tolerated by the developer.

Examples are

  • the F# REPL (dotnet fsi)

  • the C# REPL (dotnet csi)

  • .NET Interactive notebook kernels

and likely many others.

On .NET Framework these have previously relied on Thread.Abort() to support some cancellation scenarios (user enters code, preses run and suddenly decides that wasn't a good idea). However Thread.Abort() has been removed from .NET Core, see #11369

At the moment it's impossible to have an "Interrupt" button in any .NET execution environment executing arbitrary user code, ever. For example, .NET Interactive Jupyter notebooks can't support the Jupyter "Interrupt" button to stop user code execution, or a future .NET teaching environment can't ever have an "Interrupt" button. And REPLs can't support Ctrl-C, one of the most basic functions of a REPL.

These scenarios matter for the long term future of .NET.

This continues the discussion about production scenarios here: #11369 (comment)

@jkotas said

We still have the "good enough" thread abort functionality available for debuggers via debugging APIs. If the other debugger-like environments cannot act as real debuggers, I would not be opposed to exploring ways how to make the thread abort available to them.

@dsyme said:

In theory it might be possible to rearchitect the F# REPL to use a supervised process but it would be a large amount of work. And that work would likely be needed again for .NET Interactive and C# REPL. It's very different to what we are doing today for F# Interactive etc....

Finally @dsyme suggested this:

If it were possible to put on the agenda a System.Runtime.Helpers.UnsafeThreadAbortOnlyForUseByInteractiveExecutionEnvironmentsActingAsTheirOwnSupervisor() that would be grand....

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Aug 24, 2020
@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@jkotas jkotas added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-VM-coreclr labels Aug 24, 2020
@dsyme dsyme changed the title Uncooperative cancellation/abort/interrupt for interactive execution environments Non-cooperative cancellation/abort/interrupt for interactive execution environments Aug 24, 2020
@jkotas
Copy link
Member

jkotas commented Aug 25, 2020

class ControlledExecutionForUseByInteractiveExecutionEnvironmentsActingAsTheirOwnSupervisor
{
    public ControlledExecution(Action action);
    // This can have more method and properties to control the execution
    void Run();
    void Abort();
}

@dsyme
Copy link
Author

dsyme commented Aug 25, 2020

@jkotas Ship it :)

Seriously it would be fantastic to have this addressed. No massive design needed really, just a replacement for thread abort is enough from my perspective.

Am I right in thinking this would be fairly simple to implement, ie the basic abort mechanisms are still in place?

I guess it's worth asking if there is other non-coop thread control functionality lying around (pause?) that could enable user gestures in a REPL without embracing being a full debugger. But equally abort is really enough to warrant this.

@jkotas
Copy link
Member

jkotas commented Aug 25, 2020

I think it would be medium (ie several weeks of work) sized feature.

@dsyme
Copy link
Author

dsyme commented Aug 25, 2020

OK cool. Please let me know who else we need to bring on board, if anyone, or if you feel it can be driven from your side

@mangod9 mangod9 removed the untriaged New issue has not been triaged by the area owner label Sep 2, 2020
@mangod9 mangod9 added this to the 6.0.0 milestone Sep 2, 2020
@goswinr
Copy link

goswinr commented Nov 30, 2020

I almost daily actively use Thread.Abort in my iterative F# scripting. I have to host F# interactive in a bigger CAD process. see my talk please allow in process cancellation of threads so that I can move to NET 5 eventually too.

@ProIntegritate
Copy link

Honestly, thread.abort() is sometimes necessary when a thread gets stuck or halted in a blocking operation and can't control itself, or when a malicious user create a condition where all the threads gets allocated and not used in a piece of server software, in that case no one (*) would care if data gets thrown away and the thread needs to die with either .abort() or .nukefromhighorbit() from say, a watcher thread that checks for a threads vital signs. I can't believe you removed it at all.

(* except people on StackOverflow debating the academical implications of threads being terminated and how they know better than anyone else.)

@alexrp
Copy link
Contributor

alexrp commented Jul 26, 2021

Honestly, thread.abort() is sometimes necessary when a thread gets stuck or halted in a blocking operation and can't control itself, or when a malicious user create a condition where all the threads gets allocated and not used in a piece of server software, in that case no one (*) would care if data gets thrown away and the thread needs to die with either .abort() or .nukefromhighorbit() from say, a watcher thread that checks for a threads vital signs. I can't believe you removed it at all.

(* except people on StackOverflow debating the academical implications of threads being terminated and how they know better than anyone else.)

The problems with Thread.Abort are numerous and are absolutely not remotely "academic". The very use cases you bring up suggest you aren't fully familiar with those problems, as those are not appropriate places to use Thread.Abort.

@ProIntegritate
Copy link

Honestly, thread.abort() is sometimes necessary when a thread gets stuck or halted in a blocking operation and can't control itself, or when a malicious user create a condition where all the threads gets allocated and not used in a piece of server software, in that case no one () would care if data gets thrown away and the thread needs to die with either .abort() or .nukefromhighorbit() from say, a watcher thread that checks for a threads vital signs. I can't believe you removed it at all.
(
except people on StackOverflow debating the academical implications of threads being terminated and how they know better than anyone else.)

The problems with Thread.Abort are numerous and are absolutely not remotely "academic". The very use cases you bring up suggest you aren't fully familiar with those problems, as those are not appropriate places to use Thread.Abort.

Another one... It really does not matter, if the thread is in the state i described it needs to die, regardless of how it's done.

@danmoseley
Copy link
Member

@ProIntegritate

Another one... It really does not matter, if the thread is in the state i described it needs to die, regardless of how it's done

If the abort possibly corrupts the process state leading to undefined behavior would it still be useful to you? Or possibly just hangs.

The proposal above is for scenarios where that situation is not disastrous.

@alexrp
Copy link
Contributor

alexrp commented Jul 26, 2021

Another one... It really does not matter, if the thread is in the state i described it needs to die, regardless of how it's done.

The dismissive attitude is neither helpful nor warranted. You are not on Stack Overflow; you are in a forum with people who have worked on the core components of the .NET ecosystem for many years. Few here are interested in abstract philosophical debate. Claims are going to be evaluated on their technical merits, and the fact of the matter is that Thread.Abort has many very real, very subtle, and very nasty problems.

@goswinr
Copy link

goswinr commented Aug 24, 2021

class ControlledExecutionForUseByInteractiveExecutionEnvironmentsActingAsTheirOwnSupervisor
{
    public ControlledExecution(Action action);
    // This can have more method and properties to control the execution
    void Run();
    void Abort();
}

@jkotas is this still on the agenda of possible additions? @dsyme What is the best way today to cancel an interactive evaluation?

@jkotas
Copy link
Member

jkotas commented Aug 24, 2021

This is in our back log. We may consider it for .NET 7.

cc @mangod9

@AntonLapounov
Copy link
Member

I have created a discussion for possible API and implementation details based on the proposal above: #66480. I have some concerns regarding lack of reliability guarantees, e.g., the process silently going to a bad state.

@AntonLapounov
Copy link
Member

Implemented in #71661.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-VM-coreclr
Projects
None yet
Development

No branches or pull requests

9 participants