live reload: fix SIGSEGV when calling dlclose, while a live fn is still running.

pull/1270/head
Delyan Angelov 2019-07-22 11:54:13 +03:00 committed by Alexander Medvednikov
parent 913cd2ede4
commit a65ae726ee
2 changed files with 55 additions and 6 deletions

View File

@ -344,6 +344,12 @@ fn (p mut Parser) fn_decl() {
} }
return 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' { if f.name == 'main' || f.name == 'WinMain' {
p.genln('init_consts();') p.genln('init_consts();')
if p.table.imports.contains('os') { 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' { if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
p.error('$f.name must return "$typ"') 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 // {} closed correctly? scope_level should be 0
if p.mod == 'main' { if p.mod == 'main' {
// println(p.cur_fn.scope_level) // println(p.cur_fn.scope_level)

View File

@ -252,6 +252,14 @@ byteptr g_str_buf;
int load_so(byteptr); int load_so(byteptr);
void reload_so(); void reload_so();
void init_consts();') 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') imports_json := v.table.imports.contains('json')
// TODO remove global UI hack // TODO remove global UI hack
if v.os == .mac && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) || 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] vexe := os.args[0]
os.system('$vexe -o $file_base -shared $file') os.system('$vexe -o $file_base -shared $file')
cgen.genln(' 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 <dlfcn.h> #include <dlfcn.h>
void* live_lib; void* live_lib;
int load_so(byteptr path) { int load_so(byteptr path) {
@ -401,20 +418,40 @@ int load_so(byteptr path) {
for so_fn in cgen.so_fns { for so_fn in cgen.so_fns {
cgen.genln('$so_fn = dlsym(live_lib, "$so_fn"); ') cgen.genln('$so_fn = dlsym(live_lib, "$so_fn"); ')
} }
cgen.genln('return 1; }
cgen.genln('return 1;
}
int _live_reloads = 0;
void reload_so() { void reload_so() {
int last = os__file_last_mod_unix(tos2("$file")); int last = os__file_last_mod_unix(tos2("$file"));
while (1) { while (1) {
// TODO use inotify // TODO use inotify
int now = os__file_last_mod_unix(tos2("$file")); int now = os__file_last_mod_unix(tos2("$file"));
if (now != last) { if (now != last) {
//v -o bounce -shared bounce.v
os__system(tos2("$vexe -o $file_base -shared $file"));
last = now; last = now;
load_so("$so_name");
//v -o bounce -shared bounce.v
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);
} }
} }
' ) ' )