mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-23 04:26:50 +03:00
Dukky: Add refcounting to threads
In order to cope with threads which manage to navigate entirely while executing (sadly possible) we need to handle the possibility that a thread is destroyed by the browser but still needs to live until it returns from whatever exec it was doing at the time. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
This commit is contained in:
parent
3c4652c1c3
commit
80e7ac7345
@ -59,6 +59,7 @@
|
|||||||
struct jsheap {
|
struct jsheap {
|
||||||
duk_context *ctx; /**< duktape base context */
|
duk_context *ctx; /**< duktape base context */
|
||||||
duk_uarridx_t next_thread; /**< monotonic thread counter */
|
duk_uarridx_t next_thread; /**< monotonic thread counter */
|
||||||
|
unsigned int live_threads; /**< number of live threads */
|
||||||
uint64_t exec_start_time;
|
uint64_t exec_start_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ struct jsheap {
|
|||||||
* dukky javascript thread
|
* dukky javascript thread
|
||||||
*/
|
*/
|
||||||
struct jsthread {
|
struct jsthread {
|
||||||
|
bool pending_destroy; /**< Whether this thread is pending destruction */
|
||||||
|
unsigned int in_use; /**< The number of times this thread is in use */
|
||||||
jsheap *heap; /**< The heap this thread belongs to */
|
jsheap *heap; /**< The heap this thread belongs to */
|
||||||
duk_context *ctx; /**< The duktape thread context */
|
duk_context *ctx; /**< The duktape thread context */
|
||||||
duk_uarridx_t thread_idx; /**< The thread number */
|
duk_uarridx_t thread_idx; /**< The thread number */
|
||||||
@ -621,6 +624,7 @@ js_newheap(int timeout, jsheap **heap)
|
|||||||
/* exported interface documented in js.h */
|
/* exported interface documented in js.h */
|
||||||
void js_destroyheap(jsheap *heap)
|
void js_destroyheap(jsheap *heap)
|
||||||
{
|
{
|
||||||
|
assert(heap->live_threads == 0);
|
||||||
NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
|
NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
|
||||||
duk_destroy_heap(heap->ctx);
|
duk_destroy_heap(heap->ctx);
|
||||||
free(heap);
|
free(heap);
|
||||||
@ -652,6 +656,7 @@ nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread **th
|
|||||||
ret->ctx = duk_require_context(heap->ctx, -1);
|
ret->ctx = duk_require_context(heap->ctx, -1);
|
||||||
ret->thread_idx = heap->next_thread++;
|
ret->thread_idx = heap->next_thread++;
|
||||||
duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
|
duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
|
||||||
|
heap->live_threads++;
|
||||||
duk_pop(heap->ctx); /* ... */
|
duk_pop(heap->ctx); /* ... */
|
||||||
duk_push_int(CTX, 0);
|
duk_push_int(CTX, 0);
|
||||||
duk_push_int(CTX, 1);
|
duk_push_int(CTX, 1);
|
||||||
@ -738,11 +743,16 @@ nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread **th
|
|||||||
#undef CTX
|
#undef CTX
|
||||||
#define CTX (thread->ctx)
|
#define CTX (thread->ctx)
|
||||||
|
|
||||||
|
/**
|
||||||
/* exported interface documented in js.h */
|
* Destroy a Duktape thread
|
||||||
void js_destroythread(jsthread *thread)
|
*/
|
||||||
|
static void dukky_destroythread(jsthread *thread)
|
||||||
{
|
{
|
||||||
jsheap *heap = thread->heap;
|
jsheap *heap = thread->heap;
|
||||||
|
|
||||||
|
assert(thread->in_use == 0);
|
||||||
|
assert(thread->pending_destroy = true);
|
||||||
|
|
||||||
/* Closing down the extant thread */
|
/* Closing down the extant thread */
|
||||||
NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread, heap);
|
NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread, heap);
|
||||||
duk_get_global_string(CTX, MAGIC(closedownThread));
|
duk_get_global_string(CTX, MAGIC(closedownThread));
|
||||||
@ -759,6 +769,33 @@ void js_destroythread(jsthread *thread)
|
|||||||
/* Finally give the heap a chance to clean up */
|
/* Finally give the heap a chance to clean up */
|
||||||
duk_gc(heap->ctx, 0);
|
duk_gc(heap->ctx, 0);
|
||||||
duk_gc(heap->ctx, DUK_GC_COMPACT);
|
duk_gc(heap->ctx, DUK_GC_COMPACT);
|
||||||
|
heap->live_threads--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exported interface documented in js.h */
|
||||||
|
void js_destroythread(jsthread *thread)
|
||||||
|
{
|
||||||
|
thread->pending_destroy = true;
|
||||||
|
if (thread->in_use == 0) {
|
||||||
|
dukky_destroythread(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dukky_enter_thread(jsthread *thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
thread->in_use++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dukky_leave_thread(jsthread *thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
assert(thread->in_use > 0);
|
||||||
|
|
||||||
|
thread->in_use--;
|
||||||
|
if (thread->in_use == 0 && thread->pending_destroy == true) {
|
||||||
|
dukky_destroythread(thread);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
duk_bool_t dukky_check_timeout(void *udata)
|
duk_bool_t dukky_check_timeout(void *udata)
|
||||||
@ -845,12 +882,15 @@ void dukky_log_stack_frame(duk_context *ctx, const char * reason)
|
|||||||
bool
|
bool
|
||||||
js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
|
js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
assert(thread);
|
assert(thread);
|
||||||
|
|
||||||
if (txt == NULL || txtlen == 0) {
|
if (txt == NULL || txtlen == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dukky_enter_thread(thread);
|
||||||
|
|
||||||
duk_set_top(CTX, 0);
|
duk_set_top(CTX, 0);
|
||||||
NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen, name);
|
NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen, name);
|
||||||
/* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
|
/* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
|
||||||
@ -877,11 +917,14 @@ js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
|
|||||||
if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
|
if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
|
||||||
NSLOG(dukky, DEEPDEBUG, "Returning %s",
|
NSLOG(dukky, DEEPDEBUG, "Returning %s",
|
||||||
duk_get_boolean(CTX, 0) ? "true" : "false");
|
duk_get_boolean(CTX, 0) ? "true" : "false");
|
||||||
return duk_get_boolean(CTX, 0);
|
ret = duk_get_boolean(CTX, 0);
|
||||||
|
goto out;
|
||||||
|
|
||||||
handle_error:
|
handle_error:
|
||||||
dukky_dump_error(CTX);
|
dukky_dump_error(CTX);
|
||||||
return false;
|
out:
|
||||||
|
dukky_leave_thread(thread);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* dukky_event_proto(dom_event *evt)
|
static const char* dukky_event_proto(dom_event *evt)
|
||||||
@ -1406,6 +1449,8 @@ void js_handle_new_element(jsthread *thread, struct dom_element *node)
|
|||||||
if (exc != DOM_NO_ERR) return;
|
if (exc != DOM_NO_ERR) return;
|
||||||
if (map == NULL) return;
|
if (map == NULL) return;
|
||||||
|
|
||||||
|
dukky_enter_thread(thread);
|
||||||
|
|
||||||
exc = dom_namednodemap_get_length(map, &siz);
|
exc = dom_namednodemap_get_length(map, &siz);
|
||||||
if (exc != DOM_NO_ERR) goto out;
|
if (exc != DOM_NO_ERR) goto out;
|
||||||
|
|
||||||
@ -1455,11 +1500,14 @@ out:
|
|||||||
dom_node_unref(attr);
|
dom_node_unref(attr);
|
||||||
|
|
||||||
dom_namednodemap_unref(map);
|
dom_namednodemap_unref(map);
|
||||||
|
|
||||||
|
dukky_leave_thread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void js_event_cleanup(jsthread *thread, struct dom_event *evt)
|
void js_event_cleanup(jsthread *thread, struct dom_event *evt)
|
||||||
{
|
{
|
||||||
assert(thread);
|
assert(thread);
|
||||||
|
dukky_enter_thread(thread);
|
||||||
/* ... */
|
/* ... */
|
||||||
duk_get_global_string(CTX, EVENT_MAGIC);
|
duk_get_global_string(CTX, EVENT_MAGIC);
|
||||||
/* ... EVENT_MAP */
|
/* ... EVENT_MAP */
|
||||||
@ -1469,6 +1517,7 @@ void js_event_cleanup(jsthread *thread, struct dom_event *evt)
|
|||||||
/* ... EVENT_MAP */
|
/* ... EVENT_MAP */
|
||||||
duk_pop(CTX);
|
duk_pop(CTX);
|
||||||
/* ... */
|
/* ... */
|
||||||
|
dukky_leave_thread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc, struct dom_node *target)
|
bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc, struct dom_node *target)
|
||||||
@ -1507,6 +1556,7 @@ bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc,
|
|||||||
dom_event_unref(evt);
|
dom_event_unref(evt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
dukky_enter_thread(thread);
|
||||||
/* ... */
|
/* ... */
|
||||||
duk_get_global_string(CTX, HANDLER_MAGIC);
|
duk_get_global_string(CTX, HANDLER_MAGIC);
|
||||||
/* ... handlers */
|
/* ... handlers */
|
||||||
@ -1523,6 +1573,7 @@ bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc,
|
|||||||
exc = dom_html_document_get_body(doc, &body);
|
exc = dom_html_document_get_body(doc, &body);
|
||||||
if (exc != DOM_NO_ERR) {
|
if (exc != DOM_NO_ERR) {
|
||||||
dom_event_unref(evt);
|
dom_event_unref(evt);
|
||||||
|
dukky_leave_thread(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
dukky_push_node(CTX, (struct dom_node *)body);
|
dukky_push_node(CTX, (struct dom_node *)body);
|
||||||
@ -1533,6 +1584,7 @@ bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc,
|
|||||||
dom_node_unref(body);
|
dom_node_unref(body);
|
||||||
/* ... handlers */
|
/* ... handlers */
|
||||||
duk_pop(CTX);
|
duk_pop(CTX);
|
||||||
|
dukky_leave_thread(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* Unref the body, we don't need it any more */
|
/* Unref the body, we don't need it any more */
|
||||||
@ -1574,6 +1626,7 @@ bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc,
|
|||||||
/* ... */
|
/* ... */
|
||||||
js_event_cleanup(thread, evt);
|
js_event_cleanup(thread, evt);
|
||||||
dom_event_unref(evt);
|
dom_event_unref(evt);
|
||||||
|
dukky_leave_thread(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* ... result */
|
/* ... result */
|
||||||
@ -1581,5 +1634,6 @@ bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc,
|
|||||||
/* ... */
|
/* ... */
|
||||||
js_event_cleanup(thread, evt);
|
js_event_cleanup(thread, evt);
|
||||||
dom_event_unref(evt);
|
dom_event_unref(evt);
|
||||||
|
dukky_leave_thread(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user