checker, cgen: implement auto-lock for `a[i]++`, `a[i]--` (#5817)
parent
b04fff272e
commit
6e6010d198
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue