mirror of
				https://github.com/rkd77/elinks.git
				synced 2025-10-21 19:54:04 -04:00 
			
		
		
		
	[quickjs] Added interrupt handler.
This commit is contained in:
		| @@ -27,6 +27,7 @@ | ||||
| #include "ecmascript/quickjs.h" | ||||
| #include "ecmascript/quickjs/console.h" | ||||
| #include "ecmascript/quickjs/document.h" | ||||
| #include "ecmascript/quickjs/heartbeat.h" | ||||
| #include "ecmascript/quickjs/history.h" | ||||
| #include "ecmascript/quickjs/localstorage.h" | ||||
| #include "ecmascript/quickjs/location.h" | ||||
| @@ -157,7 +158,7 @@ quickjs_get_interpreter(struct ecmascript_interpreter *interpreter) | ||||
|  | ||||
| //	JS::SetWarningReporter(ctx, error_reporter); | ||||
|  | ||||
| //	JS_AddInterruptCallback(ctx, heartbeat_callback); | ||||
| 	JS_SetInterruptHandler(rt, js_heartbeat_callback, interpreter); | ||||
| //	JS::RealmOptions options; | ||||
|  | ||||
| //	JS::RootedObject window_obj(ctx, JS_NewGlobalObject(ctx, &window_class, NULL, JS::FireOnNewGlobalHook, options)); | ||||
| @@ -378,7 +379,7 @@ quickjs_eval(struct ecmascript_interpreter *interpreter, | ||||
|  | ||||
| //	JS::Realm *comp = JS::EnterRealm(ctx, interpreter->ac); | ||||
|  | ||||
| //	interpreter->heartbeat = add_heartbeat(interpreter); | ||||
| 	interpreter->heartbeat = add_heartbeat(interpreter); | ||||
| 	interpreter->ret = ret; | ||||
|  | ||||
| //	JS::RootedObject cg(ctx, JS::CurrentGlobalOrNull(ctx)); | ||||
| @@ -394,7 +395,7 @@ quickjs_eval(struct ecmascript_interpreter *interpreter, | ||||
|  | ||||
| //	spidermonkey_check_for_exception(ctx); | ||||
|  | ||||
| //	done_heartbeat(interpreter->heartbeat); | ||||
| 	done_heartbeat(interpreter->heartbeat); | ||||
| //	JS::LeaveRealm(ctx, comp); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										124
									
								
								src/ecmascript/quickjs/heartbeat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/ecmascript/quickjs/heartbeat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| /* The QuickJS ECMAScript backend heartbeat fuctionality. */ | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "config.h" | ||||
| #endif | ||||
|  | ||||
| #include <sys/time.h>    /* setitimer(2) */ | ||||
| #include <signal.h> | ||||
|  | ||||
| #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 = 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. */ | ||||
| static 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); | ||||
| } | ||||
|  | ||||
| /* 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 = 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); | ||||
|  | ||||
| 	/* 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); | ||||
|  | ||||
| 	return hb; | ||||
| } | ||||
|  | ||||
| /* Destroy the given heartbeat. */ | ||||
| void | ||||
| done_heartbeat(struct heartbeat *hb) | ||||
| { | ||||
| 	if (!hb) return; /* add_heartbeat returned NULL */ | ||||
| 	assert(hb->interpreter); | ||||
|  | ||||
| 	/* 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); | ||||
| 	} | ||||
|  | ||||
| 	del_from_list(hb); | ||||
| 	hb->interpreter->heartbeat = NULL; | ||||
| 	mem_free(hb); | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/ecmascript/quickjs/heartbeat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/ecmascript/quickjs/heartbeat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #ifndef EL__ECMASCRIPT_QUICKJS_HEARTBEAT_H | ||||
| #define EL__ECMASCRIPT_QUICKJS_HEARTBEAT_H | ||||
|  | ||||
| #include <quickjs/quickjs.h> | ||||
|  | ||||
| struct heartbeat { | ||||
|         LIST_HEAD(struct heartbeat); | ||||
|  | ||||
|         int ttl; /* Time to live.  This value is assigned when the | ||||
|                   * script begins execution and is decremented every | ||||
|                   * second.  When it reaches 0, script execution is | ||||
|                   * terminated. */ | ||||
|  | ||||
|         struct ecmascript_interpreter *interpreter; | ||||
| }; | ||||
|  | ||||
| struct heartbeat *add_heartbeat(struct ecmascript_interpreter *interpreter); | ||||
| void done_heartbeat(struct heartbeat *hb); | ||||
| int js_heartbeat_callback(JSRuntime *rt, void *opaque); | ||||
|  | ||||
| #endif | ||||
| @@ -1 +1 @@ | ||||
| srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'document.c', 'element.c', 'form.c', 'forms.c', 'history.c', 'implementation.c', 'input.c', 'localstorage.c', 'location.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c') | ||||
| srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'document.c', 'element.c', 'form.c', 'forms.c', 'heartbeat.c', 'history.c', 'implementation.c', 'input.c', 'localstorage.c', 'location.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user