Skip to content

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

Closed

Description

@dsyme

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....

Activity

  1. Dotnet-GitSync-Bot commented on Aug 24, 2020

    @Dotnet-GitSync-Bot
    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.

  2. changed the title [-]Uncooperative cancellation/abort/interrupt for interactive execution environments[/-] [+]Non-cooperative cancellation/abort/interrupt for interactive execution environments[/+] on Aug 24, 2020
  3. jkotas commented on Aug 25, 2020

    @jkotas
    Member
    class ControlledExecutionForUseByInteractiveExecutionEnvironmentsActingAsTheirOwnSupervisor
    {
        public ControlledExecution(Action action);
        // This can have more method and properties to control the execution
        void Run();
        void Abort();
    }
    
  4. dsyme commented on Aug 25, 2020

    @dsyme
    Author

    @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.

  5. jkotas commented on Aug 25, 2020

    @jkotas
    Member

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

  6. dsyme commented on Aug 25, 2020

    @dsyme
    Author

    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

  7. removed
    untriagedNew issue has not been triaged by the area owner
    on Sep 2, 2020
  8. added this to the 6.0.0 milestone on Sep 2, 2020
  9. goswinr commented on Nov 30, 2020

    @goswinr

    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.

  10. modified the milestones: 6.0.0, 7.0.0 on Jul 9, 2021
  11. ProIntegritate commented on Jul 26, 2021

    @ProIntegritate

    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.)

  12. alexrp commented on Jul 26, 2021

    @alexrp
    Contributor

    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.

  13. ProIntegritate commented on Jul 26, 2021

    @ProIntegritate

    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.

  14. danmoseley commented on Jul 26, 2021

    @danmoseley
    Contributor

    @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.

  15. alexrp commented on Jul 26, 2021

    @alexrp
    Contributor

    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.

  16. goswinr commented on Aug 24, 2021

    @goswinr
    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?

  17. jkotas commented on Aug 24, 2021

    @jkotas
    Member

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

    cc @mangod9

  18. AntonLapounov commented on Mar 15, 2022

    @AntonLapounov
    Contributor

    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.

  19. AntonLapounov commented on Aug 3, 2022

    @AntonLapounov
    Contributor

    Implemented in #71661.

  20. ghost locked as resolved and limited conversation to collaborators on Sep 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-VM-coreclr

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions