Skip to content

Instantly share code, notes, and snippets.

@Xenakios
Last active February 10, 2026 15:08
Show Gist options
  • Select an option

  • Save Xenakios/2455b3eedba0c61da571ab4ef700bc64 to your computer and use it in GitHub Desktop.

Select an option

Save Xenakios/2455b3eedba0c61da571ab4ef700bc64 to your computer and use it in GitHub Desktop.
diff --git a/choc/javascript/choc_javascript.h b/choc/javascript/choc_javascript.h
index 95f1678..3abefcf 100644
--- a/choc/javascript/choc_javascript.h
+++ b/choc/javascript/choc_javascript.h
@@ -97,6 +97,7 @@ namespace choc::javascript
operator bool() const { return pimpl != nullptr; }
//==============================================================================
+
/// This callback is used by the run() method.
using CompletionHandler = std::function<void(const std::string& error,
const choc::value::ValueView& result)>;
@@ -162,6 +163,14 @@ namespace choc::javascript
/// Pumps the message loop in an engine-specific way - may have no effect on some platforms.
void pumpMessageLoop();
+ /// If supported by the engine, attempts tp cancel the execution of the JS code.
+ /// If the JS code is stuck in a blocking call itself, this won't work, but will
+ /// work if the JS code is running a loop, for example.
+ /// This obviously has to be called from another thread, so for example if your JS engine
+ /// is running in a worker thread, the GUI thread can call this.
+ /// If the cancellation worked, an exception will be thrown.
+ /// Currently only implemented in the QuickJS engine.
+ void cancel();
//==============================================================================
/// @internal
struct Pimpl;
@@ -235,7 +244,7 @@ struct Context::Pimpl
virtual void pushArg (double) = 0;
virtual void pushArg (bool) = 0;
virtual void pumpMessageLoop() = 0;
-
+ virtual void cancel() {};
void pushArg (const std::string& v) { pushArg (std::string_view (v)); }
void pushArg (const char* v) { pushArg (std::string_view (v)); }
void pushArg (uint64_t v) { pushArg (static_cast<int64_t> (v)); }
@@ -318,6 +327,12 @@ inline void Context::pumpMessageLoop()
pimpl->pumpMessageLoop();
}
+inline void Context::cancel()
+{
+ CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
+ pimpl->cancel();
+}
+
inline std::string makeSafeIdentifier (std::string s)
{
constexpr static std::string_view reservedWords[] =
diff --git a/choc/javascript/choc_javascript_QuickJS.h b/choc/javascript/choc_javascript_QuickJS.h
index 0617307..94982f5 100644
--- a/choc/javascript/choc_javascript_QuickJS.h
+++ b/choc/javascript/choc_javascript_QuickJS.h
@@ -64052,10 +64052,23 @@ struct QuickJSContext : public Context::Pimpl
context = JS_NewContext (runtime);
CHOC_ASSERT (context != nullptr);
JS_SetContextOpaque (context, this);
+ JS_SetInterruptHandler(runtime, [](JSRuntime *, void *opaque)
+ {
+ auto qjctx = static_cast<QuickJSContext*>(opaque);
+ if (qjctx && qjctx->shouldCancel.load())
+ {
+ qjctx->shouldCancel.store(false);
+ return 1;
+ }
+ return 0;}, this);
}
void pumpMessageLoop() override {}
-
+ void cancel() override
+ {
+ shouldCancel.store(true);
+ }
+
void pushObjectOrArray (const choc::value::ValueView& v) override { functionArgs.push_back (valueToJS (v).release()); }
void pushArg (std::string_view v) override { functionArgs.push_back (stringToJS (v).release()); }
void pushArg (int32_t v) override { functionArgs.push_back (JS_NewInt32 (context, v)); }
@@ -64350,7 +64363,7 @@ struct QuickJSContext : public Context::Pimpl
std::vector<Context::NativeFunction> registeredFunctions;
std::vector<JSValue> functionArgs;
JSAtom functionToCall = {};
-
+ std::atomic<bool> shouldCancel{false};
static constexpr const char* objectNameAttribute = "_objectName";
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment