2

I'm trying to implement a safety feature that puts a timeout around a huge function call. Pretty simple, I thought, but it turned out much harder than expected; there's no built-ins for this in any of the C languages I've looked at, apparently because it's too complex under the hood. But JS engines do this all the time; they tell you that the page is unresponsive and asks if you want to wait a bit longer or terminate it.

How do they implement the "terminate" part, having jit'ed to machine code? Is there a ton of conditional jumps, e.g. one inside every loop and one in every function body? Do they run in a separate process, so the whole process can be shut down easily with help from the OS? Do they trigger a special exception?

I'm hoping I can draw some inspiration from some of the most optimized implementations of this in the world, since the requirements are pretty similar; effectively sandboxed code, relatively long timeout that almost never fires, relatively high performance requirements.

3
  • 3
    Are you sure it's the JS engine terminating the script? I would have guessed it's the browser terminating the JS engine. Sep 28 '20 at 8:53
  • I would also examine the assumption "...having jit'ed to machine code" - my broad understanding is that most JIT engines are dropping in small chunks of compiled code within the main interpreter loop, not handing complete control of the process to a large block of machine instructions.
    – IMSoP
    Sep 28 '20 at 10:28
  • They probably just add a check every so often: if(script_is_too_long() && user_wants_to_cancel_script()) throw script_canceled_by_user_exception();
    – user253751
    Sep 28 '20 at 14:09
4

Its not all that hard, watchdog timers are old technology. You set an asynchronous timer. If the timer goes off before some event occurs (such as the interpreter saying the script is finished, or at least has temporarily yielded the CPU) you kill that operation. How that happens can differ based on the implementation. If the JS interpreter is a separate process, just kill the process.

If its on a thread of your own process... well, its not generally safe to kill a thread from outside the thread. So you send a message to that thread saying that it needs to self terminate, and have that thread check for events regularly. The important thing is that you need the interpreter to check this flag, not the script. Since the interpreter is running the script, its easy to code it to check the flag every few instructions. When it sees it, it does any cleanup it needs, then kills its own thread.

The reason you can't do this as easily in C is that there's no interpreter to force the thread to check for a terminate signal. So there's no reliable way to do it. But the presence of a supervisor level of code assures you have a place to release resources and always check for terminals, avoiding the problems with bare metal code doing the same thing.

In firmware its actually not unusual for this to be implemented with a hardware timer causing a CPU reset, or if the device is sophisticated enough to have an OS to send an interrupt for the OS to terminate a process.

-4

You could use a WebWorker and call terminate

https://developer.mozilla.org/en-US/docs/Web/API/Worker/terminate

or Promise.race

https://italonascimento.github.io/applying-a-timeout-to-your-promises/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.