瀏覽代碼

share common GC thread structure, implement thread-safe error handling

Nicolas Cannasse 7 年之前
父節點
當前提交
1f7eda2224
共有 4 個文件被更改,包括 80 次插入79 次删除
  1. 36 41
      src/alloc.c
  2. 25 5
      src/hl.h
  3. 1 1
      src/module.c
  4. 18 32
      src/std/error.c

+ 36 - 41
src/alloc.c

@@ -146,22 +146,14 @@ static gc_pheader *gc_level1_null[1<<GC_LEVEL1_BITS] = {NULL};
 static gc_pheader **hl_gc_page_map[1<<GC_LEVEL0_BITS] = {NULL};
 static void (*gc_track_callback)(hl_type *,int,int,void*) = NULL;
 
-
-typedef struct {
-	void *stack_top;
-	void *stack_cur;
-	jmp_buf regs;
-	volatile int blocking;
-} gc_thread;
-
 static struct {
 	int count;
 	bool stopping_world;
-	gc_thread **threads;
+	hl_thread_info **threads;
 	hl_mutex *global_lock;
 } gc_threads;
 
-HL_THREAD_VAR static gc_thread *current_thread;
+HL_THREAD_VAR static hl_thread_info *current_thread;
 
 static struct {
 	int64 total_requested;
@@ -197,12 +189,12 @@ static void ***gc_roots = NULL;
 static int gc_roots_count = 0;
 static int gc_roots_max = 0;
 
-static gc_thread *gc_get_thread() {
+HL_API hl_thread_info *hl_get_thread() {
 	return current_thread;
 }
 
-static void gc_save_context( gc_thread *t ) {
-	setjmp(t->regs);
+static void gc_save_context(hl_thread_info *t ) {
+	setjmp(t->gc_regs);
 	t->stack_cur = &t;
 }
 
@@ -210,15 +202,15 @@ static void gc_save_context( gc_thread *t ) {
 #	define gc_global_lock(_)
 #else
 static void gc_global_lock( bool lock ) {
-	gc_thread *t = gc_get_thread();
+	hl_thread_info *t = current_thread;
 	if( lock ) {
-		if( t->blocking ) 
+		if( t->gc_blocking )
 			hl_fatal("Can't lock GC in hl_blocking section");
 		gc_save_context(t);
-		t->blocking++;
+		t->gc_blocking++;
 		hl_mutex_acquire(gc_threads.global_lock);
 	} else {
-		t->blocking--;
+		t->gc_blocking--;
 		hl_mutex_release(gc_threads.global_lock);
 	}
 }
@@ -265,17 +257,22 @@ HL_PRIM gc_pheader *hl_gc_get_page( void *v ) {
 
 // -------------------------  THREADS ----------------------------------------------------------
 
+HL_API int hl_thread_id();
+
 HL_API void hl_register_thread( void *stack_top ) {
-	if( gc_get_thread() )
+	if( hl_get_thread() )
 		hl_fatal("Thread already registered");
 
-	gc_thread *t = (gc_thread*)malloc(sizeof(gc_thread));
-	t->blocking = 0;
+	hl_thread_info *t = (hl_thread_info*)malloc(sizeof(hl_thread_info));
+	t->thread_id = hl_thread_id();
+	t->gc_blocking = 0;
 	t->stack_top = stack_top;
 	current_thread = t;
+	hl_add_root(&t->exc_value);
+	hl_add_root(&t->exc_handler);
 
 	gc_global_lock(true);
-	gc_thread **all = (gc_thread**)malloc(sizeof(void*) * (gc_threads.count + 1));
+	hl_thread_info **all = (hl_thread_info**)malloc(sizeof(void*) * (gc_threads.count + 1));
 	memcpy(all,gc_threads.threads,sizeof(void*)*gc_threads.count);
 	gc_threads.threads = all;
 	all[gc_threads.count++] = t;
@@ -284,7 +281,7 @@ HL_API void hl_register_thread( void *stack_top ) {
 
 HL_API void hl_unregister_thread() {
 	int i;
-	gc_thread *t = gc_get_thread();
+	hl_thread_info *t = hl_get_thread();
 	if( !t )
 		hl_fatal("Thread not registered");
 	gc_global_lock(true);
@@ -292,18 +289,16 @@ HL_API void hl_unregister_thread() {
 		if( gc_threads.threads[i] == t ) {
 			memmove(gc_threads.threads + i, gc_threads.threads + i + 1, sizeof(void*) * (gc_threads.count - i - 1));
 			gc_threads.count--;
-			free(t);
 			break;
 		}
+	hl_remove_root(&t->exc_value);
+	hl_remove_root(&t->exc_handler);
+	free(t);
 	current_thread = NULL;
 	// don't use gc_global_lock(false)
 	hl_mutex_release(gc_threads.global_lock);
 }
 
-HL_API void *hl_gc_stack_top() {
-	return gc_get_thread()->stack_top;
-}
-
 HL_API void *hl_gc_threads_info() {
 	return &gc_threads;
 }
@@ -314,15 +309,15 @@ static void gc_stop_world( bool b ) {
 		int i;
 		gc_threads.stopping_world = true;
 		for(i=0;i<gc_threads.count;i++) {
-			gc_thread *t = gc_threads.threads[i];
-			while( t->blocking == 0 ) {}; // spinwait
+			hl_thread_info *t = gc_threads.threads[i];
+			while( t->gc_blocking == 0 ) {}; // spinwait
 		}
 	} else {
 		// releasing global lock will release all threads
 		gc_threads.stopping_world = false;
 	}
 #	else
-	if( b ) gc_save_context(gc_get_thread());
+	if( b ) gc_save_context(current_thread);
 #	endif
 }
 
@@ -948,10 +943,10 @@ static void gc_mark() {
 
 	// scan threads stacks & registers
 	for(i=0;i<gc_threads.count;i++) {
-		gc_thread *t = gc_threads.threads[i];
+		hl_thread_info *t = gc_threads.threads[i];
 		cur_mark_stack = mark_stack;
 		gc_mark_stack(t->stack_cur,t->stack_top);
-		gc_mark_stack(&t->regs,(void**)&t->regs + (sizeof(jmp_buf) / sizeof(void*) - 1));
+		gc_mark_stack(&t->gc_regs,(void**)&t->gc_regs + (sizeof(jmp_buf) / sizeof(void*) - 1));
 		mark_stack = cur_mark_stack;
 	}
 
@@ -1039,30 +1034,30 @@ static void hl_gc_init() {
 // ---- UTILITIES ----------------------
 
 HL_API bool hl_is_blocking() {
-	gc_thread *t = gc_get_thread();
+	hl_thread_info *t = current_thread;
 	// when called from a non GC thread, tells if the main thread is blocking
 	if( t == NULL ) {
 		if( gc_threads.count == 0 )
 			return false;
 		t = gc_threads.threads[0];
 	}
-	return t->blocking > 0;
+	return t->gc_blocking > 0;
 }
 
 HL_API void hl_blocking( bool b ) {
-	gc_thread *t = gc_get_thread();
+	hl_thread_info *t = current_thread;
 	if( !t ) hl_error("Unregistered thread");
 	if( b ) {
 #		ifdef HL_THREADS
-		if( t->blocking == 0 )
+		if( t->gc_blocking == 0 )
 			gc_save_context(t);
 #		endif
-		t->blocking++; 
-	} else if( t->blocking == 0 ) 
+		t->gc_blocking++;
+	} else if( t->gc_blocking == 0 )
 		hl_error("Unblocked thread");
 	else {
-		t->blocking--;
-		if( t->blocking == 0 && gc_threads.stopping_world ) {
+		t->gc_blocking--;
+		if( t->gc_blocking == 0 && gc_threads.stopping_world ) {
 			gc_global_lock(true);
 			gc_global_lock(false);
 		}
@@ -1343,7 +1338,7 @@ HL_API void hl_gc_dump_memory( const char *filename ) {
 	// stacks
 	fdump_i(gc_threads.count);
 	for(i=0;i<gc_threads.count;i++) {
-		gc_thread *t = gc_threads.threads[i];
+		hl_thread_info *t = gc_threads.threads[i];
 		fdump_p(t->stack_top);
 		int size = (int)((void**)t->stack_top - (void**)t->stack_cur);
 		fdump_i(size);

+ 25 - 5
src/hl.h

@@ -636,7 +636,6 @@ HL_API hl_thread *hl_thread_start( void *callback, void *param, bool withGC );
 HL_API hl_thread *hl_thread_current( void );
 HL_API void hl_register_thread( void *stack_top );
 HL_API void hl_unregister_thread( void );
-HL_API void *hl_gc_stack_top( void );
 
 HL_API hl_mutex *hl_mutex_alloc( void );
 HL_API void hl_mutex_acquire( hl_mutex *l );
@@ -785,10 +784,31 @@ struct _hl_trap_ctx {
 	jmp_buf buf;
 	hl_trap_ctx *prev;
 };
-HL_API hl_trap_ctx *hl_current_trap;
-HL_API vdynamic *hl_current_exc;
-#define hl_trap(ctx,r,label) { ctx.prev = hl_current_trap; hl_current_trap = &ctx; if( setjmp(ctx.buf) ) { r = hl_current_exc; goto label; } }
-#define hl_endtrap(ctx)	hl_current_trap = ctx.prev
+#define hl_trap(ctx,r,label) { hl_thread_info *__tinf = hl_get_thread(); ctx.prev = __tinf->trap_current; __tinf->trap_current = &ctx; if( setjmp(ctx.buf) ) { r = __tinf->exc_value; goto label; } }
+#define hl_endtrap(ctx)	hl_get_thread()->current_trap = ctx.prev
+
+#define HL_EXC_MAX_STACK	0x100
+#define HL_EXC_RETHROW		1
+#define HL_EXC_CATCH_ALL	2
+
+typedef struct {
+	int thread_id;
+	// gc vars
+	void *stack_top;
+	void *stack_cur;
+	jmp_buf gc_regs;
+	volatile int gc_blocking;
+	// exception handling
+	hl_trap_ctx *trap_current;
+	hl_trap_ctx *trap_uncaught;
+	vclosure *exc_handler;
+	vdynamic *exc_value;
+	int exc_flags;
+	int exc_stack_count;
+	void *exc_stack_trace[HL_EXC_MAX_STACK];
+} hl_thread_info;
+
+HL_API hl_thread_info *hl_get_thread();
 
 C_FUNCTION_END
 

+ 1 - 1
src/module.c

@@ -99,7 +99,7 @@ static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 static int module_capture_stack( void **stack, int size ) {
 	void **stack_ptr = (void**)&stack;
 	void *stack_bottom = stack_ptr;
-	void *stack_top = hl_gc_stack_top();
+	void *stack_top = hl_get_thread()->stack_top;
 	int count = 0;
 	unsigned char *code = cur_module->jit_code;
 	int code_size = cur_module->codesize;

+ 18 - 32
src/std/error.c

@@ -27,15 +27,6 @@
 #include <posix/posix.h>
 #endif
 
-HL_PRIM hl_trap_ctx *hl_current_trap = NULL;
-HL_PRIM vdynamic *hl_current_exc = NULL;
-HL_PRIM vdynamic **hl_debug_exc = NULL;
-HL_PRIM bool hl_debug_catch_all = false;
-static hl_trap_ctx *hl_trap_root = NULL;
-static void *stack_trace[0x1000];
-static int stack_count = 0;
-static bool exc_rethrow = false;
-
 HL_PRIM void *hl_fatal_error( const char *msg, const char *file, int line ) {
 	hl_blocking(true);
 #	ifdef HL_WIN_DESKTOP
@@ -56,7 +47,6 @@ typedef int (*capture_stack_type)( void **stack, int size );
 
 static resolve_symbol_type resolve_symbol_func = NULL;
 static capture_stack_type capture_stack_func = NULL;
-static vclosure *hl_error_handler = NULL;
 
 int hl_internal_capture_stack( void **stack, int size ) {
 	return capture_stack_func(stack,size);
@@ -78,31 +68,26 @@ HL_PRIM void hl_setup_exception( void *resolve_symbol, void *capture_stack ) {
 }
 
 HL_PRIM void hl_set_error_handler( vclosure *d ) {
-	hl_trap_root = hl_current_trap;
-	if( d == hl_error_handler )
-		return;
-	hl_error_handler = d;
-	hl_remove_root(&hl_error_handler);
-	if( d )
-		hl_add_root(&hl_error_handler);
+	hl_thread_info *t = hl_get_thread();
+	t->trap_uncaught = t->trap_current;
+	t->exc_handler = d;
 }
 
 HL_PRIM void hl_throw( vdynamic *v ) {
-	hl_trap_ctx *t = hl_current_trap;
-	if( exc_rethrow )
-		exc_rethrow = false;
+	hl_thread_info *t = hl_get_thread();
+	hl_trap_ctx *trap = t->trap_current;
+	if( t->exc_flags & HL_EXC_RETHROW )
+		t->exc_flags &= ~HL_EXC_RETHROW;
 	else
-		stack_count = capture_stack_func(stack_trace, 0x1000);
-	hl_current_exc = v;
-	hl_current_trap = t->prev;
-	if( t == hl_trap_root || hl_current_trap == NULL || hl_debug_catch_all ) {
-		hl_debug_exc = &v;
+		t->exc_stack_count = capture_stack_func(t->exc_stack_trace, HL_EXC_MAX_STACK);
+	t->exc_value = v;
+	t->trap_current = trap->prev;
+	if( trap == t->trap_uncaught || t->trap_current == NULL || (t->exc_flags&HL_EXC_CATCH_ALL) ) {
 		hl_debug_break();
-		hl_debug_exc = NULL;
-		if( hl_error_handler ) hl_dyn_call(hl_error_handler,&v,1);
+		if( t->exc_handler ) hl_dyn_call(t->exc_handler,&v,1);
 	}
 	if( throw_jump == NULL ) throw_jump = longjmp;
-	throw_jump(t->buf,1);
+	throw_jump(trap->buf,1);
 }
 
 HL_PRIM void hl_dump_stack() {
@@ -124,10 +109,11 @@ HL_PRIM void hl_dump_stack() {
 }
 
 HL_PRIM varray *hl_exception_stack() {
-	varray *a = hl_alloc_array(&hlt_bytes, stack_count);
+	hl_thread_info *t = hl_get_thread();
+	varray *a = hl_alloc_array(&hlt_bytes, t->exc_stack_count);
 	int i;
-	for(i=0;i<stack_count;i++) {
-		void *addr = stack_trace[i];
+	for(i=0;i<t->exc_stack_count;i++) {
+		void *addr = t->exc_stack_trace[i];
 		uchar sym[512];
 		int size = 512;
 		uchar *str = resolve_symbol_func(addr, sym, &size);
@@ -142,7 +128,7 @@ HL_PRIM varray *hl_exception_stack() {
 }
 
 HL_PRIM void hl_rethrow( vdynamic *v ) {
-	exc_rethrow = true;
+	hl_get_thread()->exc_flags |= HL_EXC_RETHROW;
 	hl_throw(v);
 }