mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: make [live] fn unlock its mutex on early return
This commit is contained in:
parent
26374971ab
commit
4838dda59a
@ -56,6 +56,9 @@ fn main() {
|
|||||||
println('Starting the game loop...')
|
println('Starting the game loop...')
|
||||||
go game.run()
|
go game.run()
|
||||||
for {
|
for {
|
||||||
|
if window.should_close() {
|
||||||
|
break
|
||||||
|
}
|
||||||
gl.clear()
|
gl.clear()
|
||||||
gl.clear_color(255, 255, 255, 255)
|
gl.clear_color(255, 255, 255, 255)
|
||||||
game.draw()
|
game.draw()
|
||||||
@ -101,5 +104,3 @@ fn (game mut Game) run() {
|
|||||||
time.sleep_ms(17)
|
time.sleep_ms(17)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
go update() // update the scene in the background in case the window isn't focused
|
go update() // update the scene in the background in case the window isn't focused
|
||||||
for {
|
for {
|
||||||
|
if ctx.gg.window.should_close() {
|
||||||
|
break
|
||||||
|
}
|
||||||
gg.clear(gx.White)
|
gg.clear(gx.White)
|
||||||
ctx.draw()
|
ctx.draw()
|
||||||
ctx.gg.render()
|
ctx.gg.render()
|
||||||
|
@ -225,10 +225,8 @@ fn (p mut Parser) fn_decl() {
|
|||||||
is_deprecated: p.attr == 'deprecated'
|
is_deprecated: p.attr == 'deprecated'
|
||||||
comptime_define: if p.attr.starts_with('if ') { p.attr[3..] } else { '' }
|
comptime_define: if p.attr.starts_with('if ') { p.attr[3..] } else { '' }
|
||||||
}
|
}
|
||||||
is_live := p.attr == 'live' && !p.pref.is_so && p.pref.is_live
|
is_live := p.pref.is_live && p.attr == 'live'
|
||||||
if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so {
|
is_solive := p.pref.is_solive && p.attr == 'live'
|
||||||
println('INFO: run `v -live program.v` if you want to use [live] functions')
|
|
||||||
}
|
|
||||||
if is_pub {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
p.fspace()
|
p.fspace()
|
||||||
@ -488,6 +486,7 @@ fn (p mut Parser) fn_decl() {
|
|||||||
if is_c {
|
if is_c {
|
||||||
p.fgen_nl()
|
p.fgen_nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the method
|
// Register the method
|
||||||
if receiver_typ != '' {
|
if receiver_typ != '' {
|
||||||
mut receiver_t := p.table.find_type(receiver_typ)
|
mut receiver_t := p.table.find_type(receiver_typ)
|
||||||
@ -509,6 +508,11 @@ fn (p mut Parser) fn_decl() {
|
|||||||
// '$p.file_name')
|
// '$p.file_name')
|
||||||
p.table.register_fn(f)
|
p.table.register_fn(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.first_pass() && p.attr == 'live' && !(is_live || is_solive) {
|
||||||
|
println('INFO: run `v -live $p.v.dir `, if you want to use [live] function $f.name .')
|
||||||
|
}
|
||||||
|
|
||||||
if p.is_vh || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
|
if p.is_vh || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
|
||||||
// First pass? Skip the body for now
|
// First pass? Skip the body for now
|
||||||
// Look for generic calls.
|
// Look for generic calls.
|
||||||
@ -532,10 +536,34 @@ fn (p mut Parser) fn_decl() {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if p.attr == 'live' && p.pref.is_so {
|
|
||||||
// p.genln('// live_function body start')
|
if is_solive {
|
||||||
p.genln('pthread_mutex_lock(&live_fn_mutex);')
|
// Live functions are protected by a mutex, because otherwise they
|
||||||
|
// can be changed by the live reload thread, *while* they are
|
||||||
|
// running, with unpredictable results (usually just crashing).
|
||||||
|
// For this purpose, the actual body of the live function,
|
||||||
|
// is put under a non publicly accessible function, that is prefixed
|
||||||
|
// with 'impl_live_' .
|
||||||
|
// The live function just calls its implementation dual, while ensuring
|
||||||
|
// that the call is wrapped by the mutex lock & unlock calls.
|
||||||
|
// Adding the mutex lock/unlock inside the body of the implementation
|
||||||
|
// function is not reliable, because the implementation function can do
|
||||||
|
// an early exit, which will leave the mutex locked.
|
||||||
|
function_args := f.str_args_without_types(p.table)
|
||||||
|
mut live_fncall := 'impl_live_${fn_name_cgen}(${function_args});'
|
||||||
|
mut live_fnreturn := ''
|
||||||
|
if typ != 'void' {
|
||||||
|
live_fncall = '$typ res = $live_fncall'
|
||||||
|
live_fnreturn = 'return res;'
|
||||||
|
}
|
||||||
|
p.genln(' pthread_mutex_lock(&live_fn_mutex);')
|
||||||
|
p.genln(' $live_fncall')
|
||||||
|
p.genln(' pthread_mutex_unlock(&live_fn_mutex);')
|
||||||
|
p.genln(' $live_fnreturn')
|
||||||
|
p.genln('}')
|
||||||
|
p.genln('$typ impl_live_${fn_name_cgen} ($str_args){')
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.name in ['main__main', 'main', 'WinMain'] {
|
if f.name in ['main__main', 'main', 'WinMain'] {
|
||||||
if p.pref.is_test {
|
if p.pref.is_test {
|
||||||
p.error_with_token_index('tests cannot have function `main`', f.fn_name_token_idx)
|
p.error_with_token_index('tests cannot have function `main`', f.fn_name_token_idx)
|
||||||
@ -569,10 +597,6 @@ fn (p mut Parser) fn_decl() {
|
|||||||
if typ != 'void' && !p.returns {
|
if typ != 'void' && !p.returns {
|
||||||
p.error_with_token_index('$f.name must return "$typ"', f.fn_name_token_idx)
|
p.error_with_token_index('$f.name must return "$typ"', f.fn_name_token_idx)
|
||||||
}
|
}
|
||||||
if p.attr == 'live' && p.pref.is_so {
|
|
||||||
// p.genln('// live_function body end')
|
|
||||||
p.genln('pthread_mutex_unlock(&live_fn_mutex);')
|
|
||||||
}
|
|
||||||
if p.pref.x64 && f.name == 'main__main' && !p.first_pass() {
|
if p.pref.x64 && f.name == 'main__main' && !p.first_pass() {
|
||||||
//p.x64.gen_exit()
|
//p.x64.gen_exit()
|
||||||
}
|
}
|
||||||
@ -1611,6 +1635,16 @@ fn (f &Fn) str_args(table &Table) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// f.args => "a, b, c"
|
||||||
|
fn (f &Fn) str_args_without_types(table &Table) string {
|
||||||
|
mut res := []string
|
||||||
|
for arg in f.args {
|
||||||
|
res << arg.name
|
||||||
|
}
|
||||||
|
return res.join(', ')
|
||||||
|
}
|
||||||
|
|
||||||
// find local function variable with closest name to `name`
|
// find local function variable with closest name to `name`
|
||||||
fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string {
|
fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string {
|
||||||
mut closest := f32(0)
|
mut closest := f32(0)
|
||||||
|
@ -54,6 +54,11 @@ fn (p mut Parser) gen_fn_decl(f Fn, typ, str_args string) {
|
|||||||
dll_export_linkage := if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so { '__declspec(dllexport) ' } else if p.attr == 'inline' { 'static inline ' } else { '' }
|
dll_export_linkage := if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so { '__declspec(dllexport) ' } else if p.attr == 'inline' { 'static inline ' } else { '' }
|
||||||
fn_name_cgen := p.table.fn_gen_name(f)
|
fn_name_cgen := p.table.fn_gen_name(f)
|
||||||
// str_args := f.str_args(p.table)
|
// str_args := f.str_args(p.table)
|
||||||
|
|
||||||
|
if p.attr == 'live' && p.pref.is_so {
|
||||||
|
// See fn.v for details about impl_live_ functions
|
||||||
|
p.genln('$typ impl_live_${fn_name_cgen} ($str_args);')
|
||||||
|
}
|
||||||
p.genln('$dll_export_linkage$typ $fn_name_cgen ($str_args) {')
|
p.genln('$dll_export_linkage$typ $fn_name_cgen ($str_args) {')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,9 +100,11 @@ fn (v &V) generate_hot_reload_code() {
|
|||||||
}
|
}
|
||||||
ticks := time.ticks()
|
ticks := time.ticks()
|
||||||
os.system(cmd_compile_shared_library)
|
os.system(cmd_compile_shared_library)
|
||||||
diff := time.ticks() - ticks
|
if v.pref.is_verbose {
|
||||||
println('compiling shared library took $diff ms')
|
diff := time.ticks() - ticks
|
||||||
println('=========\n')
|
println('compiling shared library took $diff ms')
|
||||||
|
println('=========\n')
|
||||||
|
}
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
|
|
||||||
void lfnmutex_print(char *s){
|
void lfnmutex_print(char *s){
|
||||||
|
@ -472,7 +472,7 @@ fn (v mut V) generate_init() {
|
|||||||
}
|
}
|
||||||
')
|
')
|
||||||
}
|
}
|
||||||
if !v.pref.is_bare {
|
if !v.pref.is_bare && !v.pref.is_so {
|
||||||
// vlib can't have `init_consts()`
|
// vlib can't have `init_consts()`
|
||||||
v.cgen.genln('void init() {
|
v.cgen.genln('void init() {
|
||||||
#if VPREALLOC
|
#if VPREALLOC
|
||||||
@ -581,7 +581,7 @@ pub fn (v mut V) generate_main() {
|
|||||||
}
|
}
|
||||||
v.gen_main_end('return g_test_fails > 0')
|
v.gen_main_end('return g_test_fails > 0')
|
||||||
}
|
}
|
||||||
else if v.table.main_exists() {
|
else if v.table.main_exists() && !v.pref.is_so {
|
||||||
v.gen_main_start(true)
|
v.gen_main_start(true)
|
||||||
cgen.genln(' main__main();')
|
cgen.genln(' main__main();')
|
||||||
if !v.pref.is_bare {
|
if !v.pref.is_bare {
|
||||||
|
Loading…
Reference in New Issue
Block a user