From 21bd9608650132e3cbd0f176e7b10dcca4be63ca Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 29 Jun 2017 21:57:09 -0400 Subject: [PATCH] Add more tests Reuse threads on gst_run when possible change name of getline to gst_getline --- Makefile | 7 +++++-- client/main.c | 10 +++++----- core/stl.c | 30 +++++++++++++++++++++++------- core/thread.c | 12 ++++++++---- core/vm.c | 24 ++++++++++++++++++------ gsttests/basic.gst | 13 ++++++++++++- include/gst/gst.h | 3 ++- 7 files changed, 73 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 2e58e05e..329810e3 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ debug: $(GST_TARGET) gdb $(GST_TARGET) valgrind: $(GST_TARGET) - valgrind --leak-check=full ./$(GST_TARGET) + valgrind --leak-check=full -v ./$(GST_TARGET) clean: rm $(GST_TARGET) || true @@ -51,4 +51,7 @@ clean: test: $(GST_TARGET) $(GST_TARGET) gsttests/basic.gst -.PHONY: clean install run debug valgrind +valtest: $(GST_TARGET) + valgrind --leak-check=full -v ./$(GST_TARGET) gsttests/basic.gst + +.PHONY: clean install run debug valgrind test valtest diff --git a/client/main.c b/client/main.c index a4e5a5e6..9debadfc 100644 --- a/client/main.c +++ b/client/main.c @@ -25,7 +25,7 @@ #include /* Simple read line functionality */ -char *getline() { +static char *gst_getline() { char *line = malloc(100); char *linep = line; size_t lenmax = 100; @@ -55,7 +55,7 @@ char *getline() { } /* Compile and run an ast */ -int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) { +static int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) { GstCompiler c; GstValue func; /* Try to compile generated AST */ @@ -80,7 +80,7 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) { } /* Parse a file and execute it */ -int debug_run(Gst *vm, FILE *in) { +static int debug_run(Gst *vm, FILE *in) { char buffer[2048] = {0}; const char *reader = buffer; GstParser p; @@ -123,7 +123,7 @@ int debug_run(Gst *vm, FILE *in) { } /* A simple repl */ -int debug_repl(Gst *vm) { +static int debug_repl(Gst *vm) { char *buffer, *reader; GstParser p; buffer = reader = NULL; @@ -138,7 +138,7 @@ int debug_repl(Gst *vm) { printf("\x1B[32m>>\x1B[0m "); if (buffer) free(buffer); - buffer = getline(); + buffer = gst_getline(); if (!buffer || *buffer == '\0') return 0; reader = buffer; diff --git a/core/stl.c b/core/stl.c index 4017937f..750baec4 100644 --- a/core/stl.c +++ b/core/stl.c @@ -450,13 +450,16 @@ int gst_stl_thread(Gst *vm) { t->parent = parent.data.thread; } else if (parent.type != GST_NIL) { gst_c_throwc(vm, "expected thread/nil as parent"); + } else { + t->parent = vm->thread; } if (errorParent.type == GST_THREAD) { t->errorParent = errorParent.data.thread; } else if (errorParent.type != GST_NIL) { gst_c_throwc(vm, "expected thread/nil as error parent"); + } else { + t->errorParent = vm->thread; } - t->parent = vm->thread; gst_c_return(vm, gst_wrap_thread(t)); } @@ -830,9 +833,12 @@ int gst_stl_gcollect(Gst *vm) { } /* Static debug print helper */ -static GstInteger gst_stl_debugp_helper(Gst *vm, GstBuffer *b, GstTable *seen, GstValue x, GstInteger next) { +static GstInteger gst_stl_debugp_helper(Gst *vm, GstBuffer *b, GstTable *seen, GstValue x, GstInteger next, int depth) { GstValue check = gst_table_get(seen, x); const uint8_t *str; + /* Prevent a stack overflow */ + if (depth++ > GST_RECURSION_GUARD) + return -1; if (check.type == GST_INTEGER) { str = gst_to_string(vm, check); gst_buffer_append_cstring(vm, b, "data = gst_alloc(vm, sizeof(GstValue) * capacity); thread->capacity = capacity; + return gst_thread_reset(vm, thread, callee); +} + +/* Clear a thread (reset it) */ +GstThread *gst_thread_reset(Gst *vm, GstThread *thread, GstValue callee) { + GstValue *stack; thread->count = GST_FRAME_SIZE; - thread->data = data; thread->status = GST_THREAD_PENDING; - stack = data + GST_FRAME_SIZE; + stack = thread->data + GST_FRAME_SIZE; gst_frame_size(stack) = 0; gst_frame_prevsize(stack) = 0; gst_frame_ret(stack) = 0; diff --git a/core/vm.c b/core/vm.c index 9cf021eb..a434a938 100644 --- a/core/vm.c +++ b/core/vm.c @@ -299,7 +299,6 @@ int gst_continue(Gst *vm) { temp = vm->ret; goto vm_return; } else { - stack = gst_thread_popframe(vm, vm->thread); goto vm_error; } } else { @@ -377,7 +376,9 @@ int gst_continue(Gst *vm) { /* Handle returning from stack frame. Expect return value in temp. */ vm_return: stack = gst_thread_popframe(vm, vm->thread); - while (vm->thread->count < GST_FRAME_SIZE) { + while (vm->thread->count < GST_FRAME_SIZE || + vm->thread->status == GST_THREAD_DEAD || + vm->thread->status == GST_THREAD_ERROR) { vm->thread->status = GST_THREAD_DEAD; if (vm->thread->parent) { vm->thread = vm->thread->parent; @@ -387,6 +388,7 @@ int gst_continue(Gst *vm) { return GST_RETURN_OK; } } + vm->thread->status = GST_THREAD_ALIVE; pc = gst_frame_pc(stack); stack[gst_frame_ret(stack)] = temp; continue; @@ -394,9 +396,14 @@ int gst_continue(Gst *vm) { /* Handle errors from c functions and vm opcodes */ vm_error: vm->thread->status = GST_THREAD_ERROR; - if (vm->thread->errorParent == NULL) - return GST_RETURN_ERROR; - vm->thread = vm->thread->errorParent; + while (vm->thread->count < GST_FRAME_SIZE || + vm->thread->status == GST_THREAD_DEAD || + vm->thread->status == GST_THREAD_ERROR) { + if (vm->thread->errorParent == NULL) + return GST_RETURN_ERROR; + vm->thread = vm->thread->errorParent; + } + vm->thread->status = GST_THREAD_ALIVE; stack = vm->thread->data + vm->thread->count; stack[gst_frame_ret(stack)] = vm->ret; pc = gst_frame_pc(stack); @@ -416,7 +423,12 @@ int gst_continue(Gst *vm) { /* Run the vm with a given function. This function is * called to start the vm. */ int gst_run(Gst *vm, GstValue callee) { - vm->thread = gst_thread(vm, callee, 64); + if (vm->thread == NULL) { + vm->thread = gst_thread(vm, callee, 64); + } else { + /* Reuse old thread */ + gst_thread_reset(vm, vm->thread, callee); + } if (vm->thread == NULL) return GST_RETURN_CRASH; if (callee.type == GST_CFUNCTION) { diff --git a/gsttests/basic.gst b/gsttests/basic.gst index e3ce60bf..fdce7ab0 100644 --- a/gsttests/basic.gst +++ b/gsttests/basic.gst @@ -48,6 +48,8 @@ (assert (= accum 65536) "loop") +(assert (= (struct 1 2 3 4 5 6 7 8) (struct 7 8 5 6 3 4 1 2)) "struct order does not matter") + "Serialization tests" (def scheck (fn [x] (def dat (serialize x)) @@ -64,7 +66,16 @@ (scheck (tuple 1 2 3)) (scheck 123412.12) (scheck (struct (struct 1 2 3 "a") (struct 1 2 3 "a") false 1 "asdasd" (tuple "a" "b"))) -(scheck "psdafoilasdfbiusbdfliasbldfiubaslidufbliausdbfiluasbdfiulbasldiufbalisudhfiasudbfaisuldfbl") +(scheck "qwertyuiopasdfghjklzxcvbnm123456789") +(scheck "qwertyuiopasdfghjklzxcvbnm1234567890!@#$%^&*()") + +(def athread (thread (fn [x] + (error (string "hello, " x))))) + +(def athread-result (tran athread "world!")) + +(assert (= athread-result "hello, world!") "thread error result") +(assert (= (status athread) "error") "thread error status") "All tests passed" diff --git a/include/gst/gst.h b/include/gst/gst.h index ffa33491..6946c2ec 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -488,7 +488,8 @@ GstValue gst_table_next(GstTable *o, GstValue key); /****/ #define gst_thread_stack(t) ((t)->data + (t)->count) -GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity); +GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity); +GstThread *gst_thread_reset(Gst *vm, GstThread *thread, GstValue callee); void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra); void gst_thread_push(Gst *vm, GstThread *thread, GstValue x); void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n);