Interrupt Execution

Jul 10, 2009 at 12:33 AM

Hi,

Are there any plans to implement interrupt execution in the DLR?

I was reading through the dlr-spec-hosting document and came across the "Interrupt Execution" paragraph (chapter 3.4 page 27 of the spec). It would solve a tricky issue I have had with IronRuby for over a year where the approach I have used to terminate scripts is to execute them on separate threads and abort them. The consequence of that has been memory and thread leaks and lots of unhappy users (all have been told there's cutting edge code on the application but they use it anyway).

I asked the same question on the IronRuby forum but after looking at the DLR source it looks to me like any implementation of the "interrupt execution" is going to be in the DLR classes. The main classes involved look to be Interpreter.cs (to stop the script instructions being executed) and Scope.cs (where the using application could signal the halt is required). The difficult part that I'm struggling with a bit is the classes in between but I'll probably be able to cobble something together. However it's guaranteed to be a clunky solution hence the question as to whether it's on the DLR team's list to put the interrupt execution feature in?

Regards,

Aaron

Coordinator
Jul 10, 2009 at 12:45 AM

Unfortunately, that’s not something we’re likely to work on soon (as in the next several months).  It is listed in the issues section for work we need to design and think about when to add support for it.

We’re adding some traceback debugging support that could in an weird way be co-opt’ed for this purpose as an IronRuby only feature until we get some support into the DLR.  IronRuby would have to add an option for you to hand off a function that they called at sequence points in the generated code, then you could decide for yourself to raise an exception there, catching at your top level for running script code.  It would be crufty :-), and I don’t know when IronRuby would even be able to support that since it is probably non on the v1 feature list.

Bill

From: aaronc [mailto:notifications@codeplex.com]
Sent: Thursday, July 09, 2009 4:34 PM
To: Bill Chiles
Subject: Interrupt Execution [dlr:62052]

From: aaronc

Hi,

Are there any plans to implement interrupt execution in the DLR?

I was reading through the dlr-spec-hosting document and came across the "Interrupt Execution" paragraph (chapter 3.4 page 27 of the spec). It would solve a tricky issue I have had with IronRuby for over a year where the approach I have used to terminate scripts is to execute them on separate threads and abort them. The consequence of that has been memory and thread leaks and lots of unhappy users (all have been told there's cutting edge code on the application but they use it anyway).

I asked the same question on the IronRuby forum but after looking at the DLR source it looks to me like any implementation of the "interrupt execution" is going to be in the DLR classes. The main classes involved look to be Interpreter.cs (to stop the script instructions being executed) and Scope.cs (where the using application could signal the halt is required). The difficult part that I'm struggling with a bit is the classes in between but I'll probably be able to cobble something together. However it's guaranteed to be a clunky solution hence the question as to whether it's on the DLR team's list to put the interrupt execution feature in?

Regards,

Aaron

Read the full discussion online.

To add a post to this discussion, reply to this email (dlr@discussions.codeplex.com)

To start a new discussion for this project, email dlr@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Jul 10, 2009 at 3:15 AM
Edited Jul 10, 2009 at 3:16 AM

Thanks for the reply Bill.

I'm attempting to get something quick and dirty so I can stop my scripts. In Interpreter.cs I have added the check below to the RunInstructions methods. That's good enough for me to interrupt the execution and works in a test where I set _haltExecution after some arbitrary number of instructions such as 30 or 40. I have also added a Halt method to Scope.cs and can call it from my application.

  if (_haltExecution) {
    throw new ApplicationException("Script was halted by external intervention.");
  }

Where I'm stuck is wiring things up so that a Halt method in the Scope class can set the _haltExecution variable in the Interpreter class. In between RubyScriptCode.cs and LightLamba.cs (which looks like the first class where I can access the interpreter) there is some black magic going on that I haven't managed to decipher yet. If anyone has a hint about how I could set a variable in the Interpreter class from a method on the Scope class it would be very gratefully received.

Thanks,

Aaron

Jul 11, 2009 at 2:00 PM

I eventually came up with an interrupt execution approach that works for me however it is extremely crude and specific to the way I use the DLR. Despite that it's far better than the previous situation with the Thread.Abort approach leaking memory and threads.

The way I did it was to was to add a static event to the Interpreter class in the Microsoft.Scripting class to notify my application everytime a new interpreter class is created. In my app I then keep a track of the Interpreter instances that belong to a certain thread - my app only ever runs one DLR instance at a time per thread - and when its time to interrupt the execution of a running script the application sets the _halt Execution boolean for all the Interpreter instances on that thread.

The relevant code is shown below on the off chance anyone else happens to have the same usage mode and interrupt execution requirement. The proper design would be to manage the interruption through the Scope or ScriptScope object but that was beyond me.

  public delegate void InterpreterCreatedDelegate(Interpreter interpreter);

    public class Interpreter {

       ...
        private bool m_haltExecution;
        public string ThreadName;

        public static event InterpreterCreatedDelegate InterpreterCreated;

        internal Interpreter(LambdaExpression lambda, bool[] localIsBoxed, int maxStackDepth,
            Instruction[] instructions, ExceptionHandler[] handlers, DebugInfo[] debugInfos) {

            ...
            ThreadName = Thread.CurrentThread.Name;
            if (InterpreterCreated != null) {
                InterpreterCreated(this);
            }
        }

       internal void RunInstructions(InterpretedFrame frame, int endInstruction) {
            var instructions = _instructions;
            int index = frame.InstructionIndex;
            while (index < endInstruction) {
                index += instructions[index].Run(frame);
                frame.InstructionIndex = index;

                if (m_haltExecution) {
                    throw new ApplicationException("Script was halted by external intervention.");
                }
            }
        }

        private void RunInstructions(InterpretedFrame frame) {
            var instructions = _instructions;
            int index = frame.InstructionIndex;
            while (index < instructions.Length) {
                index += instructions[index].Run(frame);
                frame.InstructionIndex = index;

                if (m_haltExecution) {
                    throw new ApplicationException("Script was halted by external intervention.");
                }
            }
        }

        public void Halt() {
            m_haltExecution = true;
        }

        public void Reset() {
            m_haltExecution = false;
        }

Regards,

Aaron

Jul 13, 2009 at 7:43 PM

> The way I did it was to was to add a static event to the Interpreter class in the Microsoft.Scripting class to notify my application everytime a new interpreter class is created. In my app I then keep a track of the Interpreter instances that belong to a certain thread - my app only ever runs one DLR instance at a time per thread - and when its time to interrupt the execution of a running script the application sets the _halt Execution boolean for all the Interpreter instances on that thread.

One other thing you’ll need to do is turn off adaptive compilation. Once a lambda has been interpreted “enough”, it compiles itself, which would then bypass the m_haltExecution check. See LightDelegateCreator. (Alternatively, you could add the m_haltExecution check to the compiled code, but that’s a little trickier).

- John

Jul 14, 2009 at 12:52 AM

John, thanks for the heads up on the adaptive compilation, I will turn that off.

I did briefly look at trying to add some kind of check to the compiled code but the only way I could think of was to insert an if statement every second line of the script and that seemed very fragile.

Thanks,

Aaron