From a65ae726eee4aeddf8e00515e7c7d95daa614b08 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 22 Jul 2019 11:54:13 +0300 Subject: [PATCH] live reload: fix SIGSEGV when calling dlclose, while a live fn is still running. --- compiler/fn.v | 12 ++++++++++++ compiler/main.v | 49 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 8f5dde0e18..7dc2cf5001 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -344,6 +344,12 @@ fn (p mut Parser) fn_decl() { } return } + + if p.attr == 'live' && p.pref.is_so { + //p.genln('// live_function body start') + p.genln('pthread_mutex_lock(&live_fn_mutex);') + } + if f.name == 'main' || f.name == 'WinMain' { p.genln('init_consts();') if p.table.imports.contains('os') { @@ -388,6 +394,12 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ') if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' { p.error('$f.name must return "$typ"') } + + if p.attr == 'live' && p.pref.is_so { + //p.genln('// live_function body end') + p.genln('pthread_mutex_unlock(&live_fn_mutex);') + } + // {} closed correctly? scope_level should be 0 if p.mod == 'main' { // println(p.cur_fn.scope_level) diff --git a/compiler/main.v b/compiler/main.v index 1faf8efd6e..a5144aa08e 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -252,6 +252,14 @@ byteptr g_str_buf; int load_so(byteptr); void reload_so(); void init_consts();') + + if v.pref.is_so { + cgen.genln('extern pthread_mutex_t live_fn_mutex;') + } + if v.pref.is_live { + cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;') + } + imports_json := v.table.imports.contains('json') // TODO remove global UI hack if v.os == .mac && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) || @@ -388,6 +396,15 @@ string _STR_TMP(const char *fmt, ...) { vexe := os.args[0] os.system('$vexe -o $file_base -shared $file') cgen.genln(' + +void lfnmutex_print(char *s){ + if(0){ + fflush(stderr); + fprintf(stderr,">> live_fn_mutex: %p | %s\\n", &live_fn_mutex, s); + fflush(stderr); + } +} + #include void* live_lib; int load_so(byteptr path) { @@ -401,20 +418,40 @@ int load_so(byteptr path) { for so_fn in cgen.so_fns { cgen.genln('$so_fn = dlsym(live_lib, "$so_fn"); ') } - cgen.genln('return 1; } - + + cgen.genln('return 1; +} + +int _live_reloads = 0; void reload_so() { int last = os__file_last_mod_unix(tos2("$file")); while (1) { // TODO use inotify int now = os__file_last_mod_unix(tos2("$file")); if (now != last) { + last = now; + //v -o bounce -shared bounce.v - os__system(tos2("$vexe -o $file_base -shared $file")); - last = now; - load_so("$so_name"); + lfnmutex_print("compiling tmp.${file_base} ..."); + os__system(tos2("$vexe -o tmp.${file_base} -shared $file")); + lfnmutex_print("tmp.${file_base}.so compiled. reloading ..."); + + lfnmutex_print("reload_so locking..."); + pthread_mutex_lock(&live_fn_mutex); + lfnmutex_print("reload_so locked"); + + if(0 == rename("tmp.${file_base}.so", "${so_name}")){ + load_so("$so_name"); + lfnmutex_print("loaded ${so_name}"); + } + + lfnmutex_print("reload_so unlocking..."); + pthread_mutex_unlock(&live_fn_mutex); + lfnmutex_print("reload_so unlocked"); + + _live_reloads++; } - time__sleep_ms(400); + time__sleep_ms(100); } } ' )