1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-06 18:43:04 +00:00

Address #288 and partially #287

The %q formatter for janet_formatc now expects a Janet, not a JanetString or
JanetSymbol or JanetKeyword.

Also fix some reference counting issues with threads when destroying
threads, which should fix #287's
SIGSEGV. Still fails to send messages sometimes, though.
This commit is contained in:
Calvin Rose
2020-02-27 17:58:17 -06:00
parent 10ec319c32
commit 6b093bdcca
2 changed files with 43 additions and 29 deletions

View File

@@ -202,7 +202,7 @@ JanetSlot janetc_resolve(
switch (btype) { switch (btype) {
default: default:
case JANET_BINDING_NONE: case JANET_BINDING_NONE:
janetc_error(c, janet_formatc("unknown symbol %q", sym)); janetc_error(c, janet_formatc("unknown symbol %q", janet_wrap_symbol(sym)));
return janetc_cslot(janet_wrap_nil()); return janetc_cslot(janet_wrap_nil());
case JANET_BINDING_DEF: case JANET_BINDING_DEF:
case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */ case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */

View File

@@ -51,10 +51,6 @@ struct JanetMailbox {
pthread_cond_t cond; pthread_cond_t cond;
#endif #endif
/* Setup procedure - requires a parent mailbox
* to receive thunk from */
JanetMailbox *parent;
/* Memory management - reference counting */ /* Memory management - reference counting */
int refCount; int refCount;
int closed; int closed;
@@ -70,6 +66,11 @@ struct JanetMailbox {
JanetBuffer messages[]; JanetBuffer messages[];
}; };
typedef struct {
JanetMailbox *original;
JanetMailbox *newbox;
} JanetMailboxPair;
static JANET_THREAD_LOCAL JanetMailbox *janet_vm_mailbox = NULL; static JANET_THREAD_LOCAL JanetMailbox *janet_vm_mailbox = NULL;
static JANET_THREAD_LOCAL JanetThread *janet_vm_thread_current = NULL; static JANET_THREAD_LOCAL JanetThread *janet_vm_thread_current = NULL;
static JANET_THREAD_LOCAL JanetTable *janet_vm_thread_decode = NULL; static JANET_THREAD_LOCAL JanetTable *janet_vm_thread_decode = NULL;
@@ -82,7 +83,7 @@ static JanetTable *janet_thread_get_decode(void) {
return janet_vm_thread_decode; return janet_vm_thread_decode;
} }
static JanetMailbox *janet_mailbox_create(JanetMailbox *parent, int refCount, uint16_t capacity) { static JanetMailbox *janet_mailbox_create(int refCount, uint16_t capacity) {
JanetMailbox *mailbox = malloc(sizeof(JanetMailbox) + sizeof(JanetBuffer) * (size_t) capacity); JanetMailbox *mailbox = malloc(sizeof(JanetMailbox) + sizeof(JanetBuffer) * (size_t) capacity);
if (NULL == mailbox) { if (NULL == mailbox) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
@@ -96,7 +97,6 @@ static JanetMailbox *janet_mailbox_create(JanetMailbox *parent, int refCount, ui
#endif #endif
mailbox->refCount = refCount; mailbox->refCount = refCount;
mailbox->closed = 0; mailbox->closed = 0;
mailbox->parent = parent;
mailbox->messageCount = 0; mailbox->messageCount = 0;
mailbox->messageCapacity = capacity; mailbox->messageCapacity = capacity;
mailbox->messageFirst = 0; mailbox->messageFirst = 0;
@@ -175,6 +175,23 @@ static int thread_mark(void *p, size_t size) {
return 0; return 0;
} }
static JanetMailboxPair *make_mailbox_pair(JanetMailbox *original) {
JanetMailboxPair *pair = malloc(sizeof(JanetMailboxPair));
if (NULL == pair) {
JANET_OUT_OF_MEMORY;
}
pair->original = original;
janet_mailbox_ref(original, 1);
pair->newbox = janet_mailbox_create(1, 16);
return pair;
}
static void destory_mailbox_pair(JanetMailboxPair *pair) {
janet_mailbox_ref(pair->original, -1);
janet_mailbox_ref(pair->newbox, -1);
free(pair);
}
/* Abstract waiting for timeout across windows/posix */ /* Abstract waiting for timeout across windows/posix */
typedef struct { typedef struct {
int timedwait; int timedwait;
@@ -402,6 +419,7 @@ static JanetAbstractType Thread_AT = {
static JanetThread *janet_make_thread(JanetMailbox *mailbox, JanetTable *encode) { static JanetThread *janet_make_thread(JanetMailbox *mailbox, JanetTable *encode) {
JanetThread *thread = janet_abstract(&Thread_AT, sizeof(JanetThread)); JanetThread *thread = janet_abstract(&Thread_AT, sizeof(JanetThread));
janet_mailbox_ref(mailbox, 1);
thread->mailbox = mailbox; thread->mailbox = mailbox;
thread->encode = encode; thread->encode = encode;
return thread; return thread;
@@ -412,12 +430,13 @@ JanetThread *janet_getthread(const Janet *argv, int32_t n) {
} }
/* Runs in new thread */ /* Runs in new thread */
static int thread_worker(JanetMailbox *mailbox) { static int thread_worker(JanetMailboxPair *pair) {
JanetFiber *fiber = NULL; JanetFiber *fiber = NULL;
Janet out; Janet out;
/* Use the mailbox we were given */ /* Use the mailbox we were given */
janet_vm_mailbox = mailbox; janet_vm_mailbox = pair->newbox;
janet_mailbox_ref(pair->newbox, 1);
/* Init VM */ /* Init VM */
janet_init(); janet_init();
@@ -426,9 +445,7 @@ static int thread_worker(JanetMailbox *mailbox) {
JanetTable *encode = janet_get_core_table("make-image-dict"); JanetTable *encode = janet_get_core_table("make-image-dict");
/* Create parent thread */ /* Create parent thread */
JanetThread *parent = janet_make_thread(mailbox->parent, encode); JanetThread *parent = janet_make_thread(pair->original, encode);
janet_mailbox_ref(mailbox->parent, -1);
mailbox->parent = NULL; /* only used to create the thread */
Janet parentv = janet_wrap_abstract(parent); Janet parentv = janet_wrap_abstract(parent);
/* Unmarshal the function */ /* Unmarshal the function */
@@ -449,16 +466,18 @@ static int thread_worker(JanetMailbox *mailbox) {
fiber = janet_fiber(func, 64, 1, argv); fiber = janet_fiber(func, 64, 1, argv);
JanetSignal sig = janet_continue(fiber, janet_wrap_nil(), &out); JanetSignal sig = janet_continue(fiber, janet_wrap_nil(), &out);
if (sig != JANET_SIGNAL_OK) { if (sig != JANET_SIGNAL_OK) {
janet_eprintf("in thread %v: ", janet_wrap_abstract(janet_make_thread(mailbox, encode))); janet_eprintf("in thread %v: ", janet_wrap_abstract(janet_make_thread(pair->newbox, encode)));
janet_stacktrace(fiber, out); janet_stacktrace(fiber, out);
} }
/* Normal exit */ /* Normal exit */
destory_mailbox_pair(pair);
janet_deinit(); janet_deinit();
return 0; return 0;
/* Fail to set something up */ /* Fail to set something up */
error: error:
destory_mailbox_pair(pair);
janet_eprintf("\nthread failed to start\n"); janet_eprintf("\nthread failed to start\n");
janet_deinit(); janet_deinit();
return 1; return 1;
@@ -467,12 +486,12 @@ error:
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
static DWORD WINAPI janet_create_thread_wrapper(LPVOID param) { static DWORD WINAPI janet_create_thread_wrapper(LPVOID param) {
thread_worker((JanetMailbox *)param); thread_worker((JanetMailboxPair *)param);
return 0; return 0;
} }
static int janet_thread_start_child(JanetThread *thread) { static int janet_thread_start_child(JanetMailboxPair *pair) {
HANDLE handle = CreateThread(NULL, 0, janet_create_thread_wrapper, thread->mailbox, 0, NULL); HANDLE handle = CreateThread(NULL, 0, janet_create_thread_wrapper, pair, 0, NULL);
int ret = NULL == handle; int ret = NULL == handle;
/* Does not kill thread, simply detatches */ /* Does not kill thread, simply detatches */
if (!ret) CloseHandle(handle); if (!ret) CloseHandle(handle);
@@ -482,13 +501,13 @@ static int janet_thread_start_child(JanetThread *thread) {
#else #else
static void *janet_pthread_wrapper(void *param) { static void *janet_pthread_wrapper(void *param) {
thread_worker((JanetMailbox *)param); thread_worker((JanetMailboxPair *)param);
return NULL; return NULL;
} }
static int janet_thread_start_child(JanetThread *thread) { static int janet_thread_start_child(JanetMailboxPair *pair) {
pthread_t handle; pthread_t handle;
int error = pthread_create(&handle, NULL, janet_pthread_wrapper, thread->mailbox); int error = pthread_create(&handle, NULL, janet_pthread_wrapper, pair);
if (error) { if (error) {
return 1; return 1;
} else { } else {
@@ -505,7 +524,7 @@ static int janet_thread_start_child(JanetThread *thread) {
void janet_threads_init(void) { void janet_threads_init(void) {
if (NULL == janet_vm_mailbox) { if (NULL == janet_vm_mailbox) {
janet_vm_mailbox = janet_mailbox_create(NULL, 1, 10); janet_vm_mailbox = janet_mailbox_create(1, 10);
} }
janet_vm_thread_decode = NULL; janet_vm_thread_decode = NULL;
janet_vm_thread_current = NULL; janet_vm_thread_current = NULL;
@@ -529,7 +548,6 @@ static Janet cfun_thread_current(int32_t argc, Janet *argv) {
janet_fixarity(argc, 0); janet_fixarity(argc, 0);
if (NULL == janet_vm_thread_current) { if (NULL == janet_vm_thread_current) {
janet_vm_thread_current = janet_make_thread(janet_vm_mailbox, janet_get_core_table("make-image-dict")); janet_vm_thread_current = janet_make_thread(janet_vm_mailbox, janet_get_core_table("make-image-dict"));
janet_mailbox_ref(janet_vm_mailbox, 1);
janet_gcroot(janet_wrap_abstract(janet_vm_thread_current)); janet_gcroot(janet_wrap_abstract(janet_vm_thread_current));
} }
return janet_wrap_abstract(janet_vm_thread_current); return janet_wrap_abstract(janet_vm_thread_current);
@@ -544,15 +562,11 @@ static Janet cfun_thread_new(int32_t argc, Janet *argv) {
janet_panicf("bad slot #1, expected integer in range [1, 65535], got %d", cap); janet_panicf("bad slot #1, expected integer in range [1, 65535], got %d", cap);
} }
JanetTable *encode = janet_get_core_table("make-image-dict"); JanetTable *encode = janet_get_core_table("make-image-dict");
JanetMailbox *mailbox = janet_mailbox_create(janet_vm_mailbox, 2, (uint16_t) cap);
/* one for created thread, one for ->parent reference in new mailbox */ JanetMailboxPair *pair = make_mailbox_pair(janet_vm_mailbox);
janet_mailbox_ref(janet_vm_mailbox, 2); JanetThread *thread = janet_make_thread(pair->newbox, encode);
if (janet_thread_start_child(pair)) {
JanetThread *thread = janet_make_thread(mailbox, encode); destory_mailbox_pair(pair);
if (janet_thread_start_child(thread)) {
janet_mailbox_ref(mailbox, -1); /* mailbox reference */
janet_mailbox_ref(janet_vm_mailbox, -1); /* ->parent reference */
janet_panic("could not start thread"); janet_panic("could not start thread");
} }