cgen: fix deadlock when returning multiple values in lock (#14014)

pull/14016/head
crthpl 2022-04-11 23:21:27 -07:00 committed by GitHub
parent 3e3b2e25db
commit afb07e0e16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 38 deletions

View File

@ -3902,6 +3902,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
tmpvar := g.new_tmp_var() tmpvar := g.new_tmp_var()
ret_typ := g.typ(g.unwrap_generic(g.fn_decl.return_type)) ret_typ := g.typ(g.unwrap_generic(g.fn_decl.return_type))
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0 mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|| g.cur_lock.lockeds.len > 0
// handle promoting none/error/function returning 'Option' // handle promoting none/error/function returning 'Option'
if fn_return_is_optional { if fn_return_is_optional {
optional_none := node.exprs[0] is ast.None optional_none := node.exprs[0] is ast.None

View File

@ -1,4 +1,3 @@
// vtest retry: 3
import time import time
struct AA { struct AA {
@ -6,49 +5,42 @@ mut:
b string b string
} }
const (
run_time = time.millisecond * 200 // must be big enough to ensure threads have started
sleep_time = time.millisecond * 250 // some tolerance added
)
fn test_return_lock() { fn test_return_lock() {
start := time.now() start := time.now()
shared s := AA{'3'} shared s := AA{'3'}
go printer(shared s, start) reader(shared s)
go fn (shared s AA, start time.Time) { lock s {
for { assert s.b == '5'
reader(shared s) s.b = '4'
if time.now() - start > run_time { }
exit(0) rlock s {
} assert s.b == '4'
}
}(shared s, start)
time.sleep(sleep_time)
assert false
}
fn printer(shared s AA, start time.Time) {
for {
lock s {
assert s.b in ['0', '1', '2', '3', '4', '5']
}
if time.now() - start > run_time {
exit(0)
}
} }
} }
fn reader(shared s AA) { fn reader(shared s AA) {
mut i := 0 lock s {
for { assert s.b == '3'
i++ s.b = '5'
x := i.str() // this test checks if cgen unlocks the mutex here
lock s { return
s.b = x
if s.b == '5' {
// this test checks if cgen unlocks the mutex here
return
}
}
} }
} }
fn test_multi_return_lock() {
shared s := AA{'3'}
reti, retb := printer2(shared s)
lock s {
assert s.b == '3'
assert reti == 4
assert retb == true
}
}
fn printer2(shared s AA) (int, bool) {
rlock s {
assert s.b == '3'
return 4, true
}
return 5, false
}