Skip to content

Commit

Permalink
Add API to support multi-threaded usage
Browse files Browse the repository at this point in the history
To allow multiple threads to share the same JSRuntime in lockstep.
  • Loading branch information
oleavr committed May 27, 2022
1 parent 2292188 commit 1e14b01
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 5 deletions.
24 changes: 19 additions & 5 deletions list.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ static inline void init_list_head(struct list_head *head)
head->next = head;
}

static inline int list_empty(const struct list_head *el)
{
return el->next == el;
}

/* insert 'el' between 'prev' and 'next' */
static inline void __list_add(struct list_head *el,
struct list_head *prev, struct list_head *next)
Expand All @@ -67,6 +72,20 @@ static inline void list_add_tail(struct list_head *el, struct list_head *head)
__list_add(el, head->prev, head);
}

static inline void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
struct list_head *a = list->next;
struct list_head *b = list->prev;
struct list_head *c = head->next;
head->next = a;
a->prev = head;
b->next = c;
c->prev = b;
}
}

static inline void list_del(struct list_head *el)
{
struct list_head *prev, *next;
Expand All @@ -78,11 +97,6 @@ static inline void list_del(struct list_head *el)
el->next = NULL; /* fail safe */
}

static inline int list_empty(struct list_head *el)
{
return el->next == el;
}

#define list_for_each(el, head) \
for(el = (head)->next; el != (head); el = el->next)

Expand Down
43 changes: 43 additions & 0 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,13 @@ struct JSRuntime {
void *user_opaque;
};

typedef struct JSRuntimeInternalThreadState {
uintptr_t stack_top;
JSValue current_exception;
struct JSStackFrame *current_stack_frame;
struct list_head job_list;
} JSRuntimeInternalThreadState;

struct JSClass {
uint32_t class_id; /* 0 means free entry */
JSAtom class_name;
Expand Down Expand Up @@ -1769,6 +1776,42 @@ JSRuntime *JS_NewRuntime(void)
return JS_NewRuntime2(&def_malloc_funcs, NULL);
}

void JS_Enter(JSRuntime *rt)
{
rt->stack_top = js_get_stack_pointer();
}

void JS_Suspend(JSRuntime *rt, JSRuntimeThreadState *state)
{
JSRuntimeInternalThreadState *s = (JSRuntimeInternalThreadState *)state;

s->stack_top = rt->stack_top;
s->current_exception = rt->current_exception;
s->current_stack_frame = rt->current_stack_frame;
memcpy(&s->job_list, &rt->job_list, sizeof(rt->job_list));

rt->stack_top = 0;
rt->current_exception = JS_NULL;
rt->current_stack_frame = NULL;
init_list_head(&rt->job_list);
}

void JS_Resume(JSRuntime *rt, const JSRuntimeThreadState *state)
{
const JSRuntimeInternalThreadState *s =
(const JSRuntimeInternalThreadState *)state;

rt->stack_top = s->stack_top;
rt->current_exception = s->current_exception;
rt->current_stack_frame = s->current_stack_frame;
list_splice(&s->job_list, &rt->job_list);
}

void JS_Leave(JSRuntime *rt)
{
rt->stack_top = 0;
}

void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
{
rt->malloc_state.malloc_limit = limit;
Expand Down
8 changes: 8 additions & 0 deletions quickjs.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data);

typedef struct JSRuntimeThreadState {
char data[64];
} JSRuntimeThreadState;

typedef struct JSMallocState {
size_t malloc_count;
size_t malloc_size;
Expand All @@ -329,6 +333,10 @@ typedef struct JSMallocFunctions {
typedef struct JSGCObjectHeader JSGCObjectHeader;

JSRuntime *JS_NewRuntime(void);
void JS_Enter(JSRuntime *rt);
void JS_Suspend(JSRuntime *rt, JSRuntimeThreadState *state);
void JS_Resume(JSRuntime *rt, const JSRuntimeThreadState *state);
void JS_Leave(JSRuntime *rt);
/* info lifetime must exceed that of rt */
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
Expand Down

0 comments on commit 1e14b01

Please sign in to comment.