From 8e7074fd2500868e60d2944f474740a140d56f0a Mon Sep 17 00:00:00 2001 From: Sidi Liang <1467329765@qq.com> Date: Sat, 9 Nov 2024 13:40:45 +0800 Subject: [PATCH] [web] Attempt to add timeouts for REPL (not working properly, it works in some cases but causes a segfault, and in other cases the timeouts were ignored) --- src/nasal_web.cpp | 41 ++++++++++++++++++++++++++++++++++------- src/nasal_web.h | 1 + 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/nasal_web.cpp b/src/nasal_web.cpp index 889e5a0..67b5c2f 100644 --- a/src/nasal_web.cpp +++ b/src/nasal_web.cpp @@ -59,6 +59,7 @@ struct WebReplContext { std::string last_error; bool allow_output; bool initialized; + std::chrono::seconds timeout{1}; // Default 1 second timeout WebReplContext() : allow_output(false), initialized(false) { repl_instance = std::make_unique(); @@ -217,6 +218,12 @@ void nasal_repl_cleanup(void* context) { delete static_cast(context); } +// Add new function to set REPL timeout +void nasal_repl_set_timeout(void* context, int seconds) { + auto* ctx = static_cast(context); + ctx->timeout = std::chrono::seconds(seconds); +} + const char* nasal_repl_eval(void* context, const char* line) { auto* ctx = static_cast(context); @@ -276,17 +283,37 @@ const char* nasal_repl_eval(void* context, const char* line) { auto old_cout = std::cout.rdbuf(output.rdbuf()); auto old_cerr = std::cerr.rdbuf(output.rdbuf()); - // Update source in repl instance and run - ctx->repl_instance->get_runtime().set_repl_mode_flag(true); - ctx->repl_instance->get_runtime().set_allow_repl_output_flag(true); - ctx->repl_instance->set_source(ctx->source); - bool success = ctx->repl_instance->run(); + // Create a copy of the source for the async task + auto source_copy = ctx->source; - // Restore output streams + // Create a future for the REPL execution using the existing instance + auto future = std::async(std::launch::async, [repl = ctx->repl_instance.get(), source_copy]() { + repl->get_runtime().set_repl_mode_flag(true); + repl->get_runtime().set_allow_repl_output_flag(true); + repl->set_source(source_copy); + return repl->run(); + }); + + // Wait for completion or timeout + auto status = future.wait_for(ctx->timeout); + + // Restore output streams first std::cout.rdbuf(old_cout); std::cerr.rdbuf(old_cerr); - // Get the output + if (status == std::future_status::timeout) { + ctx->source.pop_back(); // Remove the line that caused timeout + + // Reset the REPL instance state + ctx->repl_instance->get_runtime().set_repl_mode_flag(true); + ctx->repl_instance->get_runtime().set_allow_repl_output_flag(true); + ctx->repl_instance->set_source(ctx->source); + + throw std::runtime_error("Execution timed out after " + + std::to_string(ctx->timeout.count()) + " seconds"); + } + + bool success = future.get(); std::string result = output.str(); if (!success) { diff --git a/src/nasal_web.h b/src/nasal_web.h index ad4cf14..3bc7d98 100644 --- a/src/nasal_web.h +++ b/src/nasal_web.h @@ -23,6 +23,7 @@ NASAL_EXPORT const char* nasal_get_error(void* context); // REPL NASAL_EXPORT void* nasal_repl_init(); NASAL_EXPORT void nasal_repl_cleanup(void* repl_context); +NASAL_EXPORT void nasal_repl_set_timeout(void* repl_context, int seconds); NASAL_EXPORT const char* nasal_repl_eval(void* repl_context, const char* line); NASAL_EXPORT int nasal_repl_is_complete(void* repl_context, const char* line); NASAL_EXPORT const char* nasal_repl_get_version();