franciscocpg / beanshell2

Automatically exported from code.google.com/p/beanshell2
0 stars 0 forks source link

Feature request: interruptor: Provide a way to interrupt looping script, conditionally and controllably. #76

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Feature request: interruptor.

As a scripting language, it's likely to be embedded into other host 
applications. However scripting can easily cause deadlock. While it would be 
nice for host applications to have some control over the running script, rather 
than easily hang due to script error.

One real example is the javascript engine in modern browsers. If a script has 
run too long, you will see a popup dialog asking whether to stop the script, or 
continue it.

Such a feature makes the script engine more usable in actual production 
environment. 

The feature is easy to implement, but the hard part is how to define the common 
interface. So it should be reviewed and revised carefully.

I had some experiments and it works in my environment. The attachment is the 
delta code (as well as the base code).

The implement covers 3 possible loop points in scripting:
   while (including do-while)
   for
   enhanced for (BSH only).

There are possibly other points: 
Recursive function call (both directly and indirectly). However I think that 
may not be the point to check. Recursive function call will finally and easily 
result in stackoverflow. So it will not hang the script for long.

Original issue reported on code.google.com by verilo...@gmail.com on 11 Oct 2012 at 4:01

Attachments:

GoogleCodeExporter commented 9 years ago
It seems issue #63 is for the same feature. Link it here. Let's find a proper 
and common way to achieve this...
http://code.google.com/p/beanshell2/issues/detail?id=63

Original comment by verilo...@gmail.com on 11 Oct 2012 at 7:31

GoogleCodeExporter commented 9 years ago
One problem with this is that stopping a script could still deadlock another 
part of the code e.g. by acquiring and not releasing a lock. Anyone trying to 
control this will have to somehow keep track of all locks, monitors, etc. 
acquired by the script and break those locks after stopping the script.

Original comment by bogusan...@gmail.com on 16 Jan 2014 at 3:47

GoogleCodeExporter commented 9 years ago
@bogusandre, you are correct. The java lock could be another point for deadlock 
and that should be considered carefully. This is likely non-trivial task.

The bsh_delta_interruptor provided above was an update to handle 
while/do-while/for/enhanced-for loops. Here's some example usage, which is used 
in http://robotypo.appspot.com  to avoid deadlocking:

/**
 * Interruptor specifies some conditions to indicate interruption.
 * 
 * Usage example 1:
 * 
 *  Interpreter i = ...
 *  DefaultInterruptor r = new DefaultInterruptor();
 *  i.setInterruptor(r);
 * 
 *  r.resetTimeLimit(3000); //3 seconds at the most
 *  i.source(...);
 * 
 * Usage example 2: Use time limit and accumulated time limit
 * 
 *  r.resetAccumulatedTimeLimit(10000); //set total time limit
 *  i.source(...);
 *  r.resetTimeLimit(3000);
 *  //invoke part of the script, e.g. from XThis...
 *  //...
 *  r.resetTimeLimit(3000);
 *  i.eval(...);
 *  r.resetTimeLimit(3000);
 *  //invoke some other part of the script using the same interpreter.
 *  //...
 * 
 * Usage example 3: Control whether to continue on timeout.
 * 
 *  Interruptor r = new DefaultInterruptor() {
 *      protected boolean onTimeout() {
 *          boolean continueScript = ... //ask user whether to stop the script or not
 *          return continueScript;
 *      }
 *  };

Original comment by verilo...@gmail.com on 17 Jan 2014 at 3:06

GoogleCodeExporter commented 9 years ago
This may not be a good total solution, but hope it can be helpful for some 
simple use cases, e.g. educational app, etc.

Original comment by verilo...@gmail.com on 17 Jan 2014 at 3:08

GoogleCodeExporter commented 9 years ago
It isn't possible just to wrap the eval task in a thread and monitor it with 
another thread?

Something like this:

Thread t = new Thread(
new Runnable(){

@Override
public void run(){
 Interpreter i = new Interpreter();
 i.eval("code");
}

}
);

//Somewhere
ScheduledExecutorService _instance = Executors.newScheduledThreadPool(5);
_instance.schedule(/*runnable that stops thread t*/null, 3000, 
TimeUnit.MILLISECONDS);

Original comment by lucas.mc...@gmail.com on 26 Jun 2014 at 9:26