From 9ffa18563f8ca396af7f37c1a20b3fda801d4cd7 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Mon, 27 Mar 2023 16:01:05 +0200 Subject: [PATCH] [quikcjs] libdom heartbeat.c --- src/ecmascript/libdom/quickjs/Makefile | 2 +- src/ecmascript/libdom/quickjs/heartbeat.c | 129 ++++++++++++++++++++++ src/ecmascript/libdom/quickjs/meson.build | 2 +- src/ecmascript/quickjs/heartbeat.cpp | 3 +- src/ecmascript/quickjs/heartbeat.h | 8 ++ 5 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/ecmascript/libdom/quickjs/heartbeat.c diff --git a/src/ecmascript/libdom/quickjs/Makefile b/src/ecmascript/libdom/quickjs/Makefile index a89bf8c5..7b46953c 100644 --- a/src/ecmascript/libdom/quickjs/Makefile +++ b/src/ecmascript/libdom/quickjs/Makefile @@ -1,6 +1,6 @@ top_builddir=../../../.. include $(top_builddir)/Makefile.config -OBJS = attr.o attributes.o collection.o console.o mapa.obj +OBJS = attr.o attributes.o collection.o console.o heartbeat.o mapa.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/libdom/quickjs/heartbeat.c b/src/ecmascript/libdom/quickjs/heartbeat.c new file mode 100644 index 00000000..01b4264d --- /dev/null +++ b/src/ecmascript/libdom/quickjs/heartbeat.c @@ -0,0 +1,129 @@ +/* The QuickJS ECMAScript backend heartbeat fuctionality. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* setitimer(2) */ +#include + +#include "elinks.h" + +#include "config/options.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/quickjs.h" +#include "ecmascript/quickjs/heartbeat.h" +#include "osdep/signals.h" +#include "session/session.h" +#include "util/lists.h" +#include "util/math.h" /* int_upper_bound */ +#include "util/memory.h" +#include "viewer/text/vs.h" + + + +static INIT_LIST_OF(struct heartbeat, heartbeats); + +static struct itimerval heartbeat_timer = { { 1, 0 }, { 1, 0 } }; + +/* This callback is installed by JS_SetInterruptHandler. + * Returning 1 terminates script execution immediately. */ + +int +js_heartbeat_callback(JSRuntime *rt, void *opaque) +{ + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)opaque; + + if (!interpreter || !interpreter->heartbeat || interpreter->heartbeat->ttl > 0) { + return 0; + } + return 1; +} + +/* Callback for SIGVTALRM. Go through all heartbeats, decrease each + * one's TTL, and call JS_RequestInterruptCallback if a heartbeat's TTL + * goes to 0. */ +void +check_heartbeats(void *data) +{ + struct heartbeat *hb; + + foreach (hb, heartbeats) { + assert(hb->interpreter); + --hb->ttl; + + if (hb->ttl <= 0) { + if (hb->interpreter->vs + && hb->interpreter->vs->doc_view + && hb->interpreter->vs->doc_view->session + && hb->interpreter->vs->doc_view->session->tab + && hb->interpreter->vs->doc_view->session->tab->term) { + struct session *ses = hb->interpreter->vs->doc_view->session; + struct terminal *term = ses->tab->term; + int max_exec_time = get_opt_int("ecmascript.max_exec_time", ses); + + ecmascript_timeout_dialog(term, max_exec_time); + } + } + } +#ifndef CONFIG_OS_DOS + install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); +#endif +} + +/* Create a new heartbeat for the given interpreter. */ +struct heartbeat * +add_heartbeat(struct ecmascript_interpreter *interpreter) +{ + struct session *ses; + struct heartbeat *hb; + + assert(interpreter); + + if (!interpreter->vs || !interpreter->vs->doc_view) + ses = NULL; + else + ses = interpreter->vs->doc_view->session; + hb = (struct heartbeat *)mem_alloc(sizeof(struct heartbeat)); + + if (!hb) return NULL; + + hb->ttl = get_opt_int("ecmascript.max_exec_time", ses); + hb->interpreter = interpreter; + add_to_list(heartbeats, hb); + +#ifndef CONFIG_OS_DOS + /* Update the heartbeat timer. */ + if (list_is_singleton(*hb)) { + heartbeat_timer.it_value.tv_sec = 1; + setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); + } + + /* We install the handler every call to add_heartbeat instead of only on + * module initialisation because other code may set other handlers for + * the signal. */ + install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); +#endif + return hb; +} + +/* Destroy the given heartbeat. */ +void +done_heartbeat(struct heartbeat *hb) +{ + if (!hb) return; /* add_heartbeat returned NULL */ + assert(hb->interpreter); + +#ifndef CONFIG_OS_DOS + /* Stop the heartbeat timer if this heartbeat is the only one. */ + if (list_is_singleton(*hb)) { + heartbeat_timer.it_value.tv_sec = 0; + setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL); + } +#endif + + del_from_list(hb); + hb->interpreter->heartbeat = NULL; + mem_free(hb); +} diff --git a/src/ecmascript/libdom/quickjs/meson.build b/src/ecmascript/libdom/quickjs/meson.build index e0fbb03a..22e7f4a9 100644 --- a/src/ecmascript/libdom/quickjs/meson.build +++ b/src/ecmascript/libdom/quickjs/meson.build @@ -1 +1 @@ -srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'mapa.cpp') +srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'heartbeat.c', 'mapa.cpp') diff --git a/src/ecmascript/quickjs/heartbeat.cpp b/src/ecmascript/quickjs/heartbeat.cpp index 01b4264d..10e4e8cf 100644 --- a/src/ecmascript/quickjs/heartbeat.cpp +++ b/src/ecmascript/quickjs/heartbeat.cpp @@ -21,7 +21,7 @@ #include "util/memory.h" #include "viewer/text/vs.h" - +#ifndef CONFIG_LIBDOM static INIT_LIST_OF(struct heartbeat, heartbeats); @@ -127,3 +127,4 @@ done_heartbeat(struct heartbeat *hb) hb->interpreter->heartbeat = NULL; mem_free(hb); } +#endif diff --git a/src/ecmascript/quickjs/heartbeat.h b/src/ecmascript/quickjs/heartbeat.h index 451f8b23..cd82bfde 100644 --- a/src/ecmascript/quickjs/heartbeat.h +++ b/src/ecmascript/quickjs/heartbeat.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct heartbeat { LIST_HEAD(struct heartbeat); @@ -19,4 +23,8 @@ void check_heartbeats(void *data); void done_heartbeat(struct heartbeat *hb); int js_heartbeat_callback(JSRuntime *rt, void *opaque); +#ifdef __cplusplus +} +#endif + #endif