checker, cgen: implement auto-lock for `a[i]++`, `a[i]--` (#5817)

pull/5820/head
Uwe Krüger 2020-07-13 14:01:32 +02:00 committed by GitHub
parent b04fff272e
commit 6e6010d198
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 2 deletions

View File

@ -404,6 +404,8 @@ pub:
op token.Kind op token.Kind
expr Expr expr Expr
pos token.Position pos token.Position
pub mut:
auto_locked string
} }
pub struct PrefixExpr { pub struct PrefixExpr {

View File

@ -2855,7 +2855,7 @@ fn (c Checker) has_return(stmts []ast.Stmt) ?bool {
return none return none
} }
pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type { pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
typ := c.expr(node.expr) typ := c.expr(node.expr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
// if !typ.is_number() { // if !typ.is_number() {
@ -2864,7 +2864,7 @@ pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type {
c.error('invalid operation: $node.op.str() (non-numeric type `$typ_sym.name`)', c.error('invalid operation: $node.op.str() (non-numeric type `$typ_sym.name`)',
node.pos) node.pos)
} else { } else {
c.fail_if_immutable(node.expr) node.auto_locked, _ = c.fail_if_immutable(node.expr)
} }
if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe { if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe {
c.error('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) c.error('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)

View File

@ -1745,10 +1745,17 @@ fn (mut g Gen) expr(node ast.Expr) {
g.write(')') g.write(')')
} }
ast.PostfixExpr { ast.PostfixExpr {
if node.auto_locked != '' {
g.writeln('sync__RwMutex_w_lock($node.auto_locked->mtx);')
}
g.inside_map_postfix = true g.inside_map_postfix = true
g.expr(node.expr) g.expr(node.expr)
g.inside_map_postfix = false g.inside_map_postfix = false
g.write(node.op.str()) g.write(node.op.str())
if node.auto_locked != '' {
g.writeln(';')
g.write('sync__RwMutex_w_unlock($node.auto_locked->mtx)')
}
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.op == .amp { if node.op == .amp {

View File

@ -0,0 +1,49 @@
import sync
import time
const (
iterations_per_thread = 100000
)
fn add_elements(shared foo []int, n int) {
for _ in 0 .. iterations_per_thread {
foo << n
}
foo[0]++
}
fn test_autolocked_array() {
shared abc := &[0]
go add_elements(shared abc, 1)
go add_elements(shared abc, 3)
for _ in 0 .. iterations_per_thread {
abc << 0
}
// wait for coroutines to finish - that should really be
// done by channels, yield, semaphore...
for {
mut finished_threads := 0
rlock abc {
finished_threads = abc[0]
}
if finished_threads == 2 {
break
}
time.sleep_ms(100)
}
// create histogram of results
mut result := [0, 0, 0, 0]
rlock abc {
// automatic rlock for iteration is also not implemented, yet
for v in abc {
if v > 3 {
panic('unexpected element on array')
}
result[v]++
}
}
assert result[0] == iterations_per_thread
assert result[1] == iterations_per_thread
assert result[2] == 1 // number of non-main threads
assert result[3] == iterations_per_thread
}

View File

@ -0,0 +1,38 @@
import sync
import time
const (
iterations_per_thread2 = 100000
)
fn inc_elements(shared foo []int, n int) {
for _ in 0 .. iterations_per_thread2 {
foo[n]++
}
foo[0]++ // indicat that thread is finished
}
fn test_autolocked_array_2() {
shared abc := &[0, 0, 0]
go inc_elements(shared abc, 1)
go inc_elements(shared abc, 2)
for _ in 0 .. iterations_per_thread2 {
abc[2]++
}
// wait for coroutines to finish - that should really be
// done by channels, yield, semaphore...
for {
mut finished_threads := 0
rlock abc {
finished_threads = abc[0]
}
if finished_threads == 2 {
break
}
time.sleep_ms(100)
}
rlock abc {
assert abc[1] == iterations_per_thread2
assert abc[2] == 2 * iterations_per_thread2
}
}