1

I am writing a language for educational purpose, which should run in web browsers. The language compiles to JavaScript.

So there is the problem of endless loops and recursion. Until that moment I thought the solution would be to have the runtime implemented as a WebWorker and a button on the ui, to terminate it if it runs to long.

I just found out, while testing my language, that the web worker isn't really terminated, by calling : runtime.terminate();

At least not until his last job has finished, i haven't tested what happens if it would be finished. Even in the documentation I found so far, its stated that it stops execution immediately.

So even if the user can continue working that way, the running worker in the background can use up resources and lead to at least a not responding browser.

So I need any way to terminate the execution in case of an endless loop or recursion, in response to a user event. As I din't find any way to put a thread to sleep in JavaScript, this doesn't work either, or is there something like sleep for web workers?

Have you got any suggestions what I could do?

joe
  • 3,752
  • 1
  • 32
  • 41
  • Fix your endless recursion loops. – Robert Harvey Feb 13 '15 at 15:26
  • 1
    @RobertHarvey, I think you have misunderstood what the OP is trying to do. He/she is writing a compiler. It's the users of the language who would be creating endless recursion loops. – radiaph Feb 13 '15 at 15:41
  • 1
    Yes you're right, I'm writing the compiler and so I can't prevent them, I just don't wan't users to end up with a hung up browser ... – user3025619 Feb 14 '15 at 18:33

4 Answers4

1

I would do it like this:

1) Have your compiler generate code such that instead of executing the program from start to finish, it breaks it up into segments - for example, the body of a loop or the body of a function could be a segment.

2) Each segment should end with a timeoutId = setTimeout(nextSegment, 0). This allows the web worker to receive and respond to asynchronous events in between executing segments.

3) When you want to terminate the web worker, use window.postMessage() to send it an asynchronous message.

4) Inside the web worker, have an event handler that, upon receiving that message, does a clearTimeout(timeoutId).

radiaph
  • 4,001
  • 1
  • 16
  • 19
0

I was curious about this recently, and I've just tested it. In Chrome and Firefox (as of 2023), an infinite loop is interrupted by worker.terminate().

However, in Chrome, it takes a couple of seconds for termination to occur, whereas in Firefox, it happens instantly. I posted a crbug issue about this here.

You can test the behaviour in your browser of choice by running this code:

let myWorker = new Worker(URL.createObjectURL(new Blob([`
  self.onmessage = function() {
    let i = 1;
    while(i++){
      if(i % 10000000 === 0) console.log(i);
    }
  }
`], { type: 'text/javascript' })));

myWorker.postMessage('start');

setTimeout(() => {
  console.log('Terminating worker...');
  myWorker.terminate();
}, 5000);

In Chrome, the console.log(i)'s occur for a couple of seconds after Terminating worker... is logged, whereas in Firefox, Terminating worker... is always the last thing that's logged.

joe
  • 3,752
  • 1
  • 32
  • 41
-1

Thanks for the response, I have thought about this way, so actually I wouldn't need the web worker for it. So the downside of this approach is:

1) That I would have to implement the loops as recursive function calls ...

And the bigger problem 2) The segment size has to be limited to one command, that this approach actually works, so I would have to wrap each command into a function that calls the next one, which would be a huge overhead...

Thats why I am looking for a way around, if there is any?

  • The overhead shouldn't be noticeable, unless your students are writing extremely computationally-intensive programs. The basic problem is this: 1) a button click can only generate an event, 2) the only way to communicate with web workers is via message events, and 3) a web worker can't respond to events if it is continually running. Returning control to the browser periodically is the only way the web worker can receive events and thus be informed that it needs to halt. – radiaph Feb 13 '15 at 18:16
  • Ok, what I did is rely on MDN documentation which said that worker.terminate() would terminate the immediately. What I didn't suggest that this immediately means when the event thats processed is over. I had something like unix kill for processes in mind ;-( – user3025619 Feb 14 '15 at 18:34
-1

Yes I'm writing a compiler.

As working on this approach I must mention, it might be that the overhead for the user might not be much, but the impact on compilation is really huge... It's like building a VM on top of Javascript...

What I got to this point is that additional to the above mentioned points I need also to:

-need an complex indexing system for function naming -take care of variable allocation -have to solve expressions in series -...

That's why I am looking for a more elegant variant...

  • I wouldn't call this elegant, but: any navigation from the page (reloading or following a link) will kill any web workers spawned by the page. So if you don't need the original page to remain unchanged, you could have your 'Terminate' button cause a window.location.reload(). – radiaph Feb 14 '15 at 19:46
  • Mmmmm, that sounds like a good solution, the only problem I've got that my appliction should also work offline, once loaded, is there a way to reload without server access?... To save changes I just need to save the changes in the code in local storage, which I will do anyway... And one other thing does this really kill the web worker? So as I understood the terminate method it also should kill it, but actually does it to friendly... – user3025619 Feb 15 '15 at 08:27
  • If you set the Expires HTTP header to far enough in the future (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ), the page should reload from cache, which can happen even when offline. And yes, reloading will really kill web workers, which cannot outlive their parent page. – radiaph Feb 15 '15 at 19:34