cgen: add support for shared arrays (#5721)

pull/5746/head
Uwe Krüger 2020-07-08 11:05:43 +02:00 committed by GitHub
parent 38000f8622
commit 88248b1b66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 29 deletions

View File

@ -2376,10 +2376,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
if g.is_assign_lhs && !is_selector && node.is_setter {
g.is_array_set = true
g.write('array_set(')
if !left_is_ptr {
if !left_is_ptr || node.left_type.has_flag(.shared_f) {
g.write('&')
}
g.expr(node.left)
if node.left_type.has_flag(.shared_f) {
if left_is_ptr {
g.write('->val')
} else {
g.write('.val')
}
}
g.write(', ')
g.expr(node.index)
mut need_wrapper := true
@ -2404,10 +2411,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
info.elem_type != table.string_type {
// TODO move this
g.write('*($elem_type_str*)array_get(')
if left_is_ptr {
if left_is_ptr && !node.left_type.has_flag(.shared_f) {
g.write('*')
}
g.expr(node.left)
if node.left_type.has_flag(.shared_f) {
if left_is_ptr {
g.write('->val')
} else {
g.write('.val')
}
}
g.write(', ')
g.expr(node.index)
g.write(') ')
@ -2428,10 +2442,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
}
} else {
g.write('(*($elem_type_str*)array_get(')
if left_is_ptr {
if left_is_ptr && !node.left_type.has_flag(.shared_f) {
g.write('*')
}
g.expr(node.left)
if node.left_type.has_flag(.shared_f) {
if left_is_ptr {
g.write('->val')
} else {
g.write('.val')
}
}
g.write(', ')
g.expr(node.index)
g.write('))')
@ -4497,6 +4518,24 @@ _Interface* I_${cctype}_to_Interface_${interface_name}_ptr($cctype* x) {
fn (mut g Gen) array_init(it ast.ArrayInit) {
type_sym := g.table.get_type_symbol(it.typ)
styp := g.typ(it.typ)
mut shared_styp := '' // only needed for shared &[]{...}
is_amp := g.is_amp
g.is_amp = false
if is_amp {
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
if g.is_shared {
mut shared_typ := it.typ.set_flag(.shared_f)
shared_styp = g.typ(shared_typ)
g.writeln('($shared_styp*)memdup(&($shared_styp){.val = ')
} else {
g.write('($styp*)memdup(&') // TODO: doesn't work with every compiler
}
} else {
if g.is_shared {
g.writeln('{.val = ($styp*)')
}
}
if type_sym.kind == .array_fixed {
g.write('{')
for i, expr in it.exprs {
@ -4568,6 +4607,14 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
}
}
g.write('}))')
if g.is_shared {
g.write(', .mtx = sync__new_rwmutex()}')
if is_amp {
g.write(', sizeof($shared_styp))')
}
} else if is_amp {
g.write(', sizeof($styp))')
}
}
// `ui.foo(button)` =>

View File

@ -0,0 +1,41 @@
import sync
import time
fn incr(shared foo []int, index int) {
for _ in 0 .. 100000 {
lock foo {
foo[index] = foo[index] + 1
}
}
lock foo {
foo[2]++
}
}
fn test_shared_array() {
shared foo := &[10, 20, 0]
go incr(shared foo, 0)
go incr(shared foo, 1)
go incr(shared foo, 0)
go incr(shared foo, 1)
for _ in 0 .. 50000 {
lock foo {
foo[0] -= 2
foo[1] += 3
}
}
mut finished_threads := 0
for {
rlock foo {
finished_threads = foo[2]
}
if finished_threads == 4 {
break
}
time.sleep_ms(100)
}
rlock foo {
assert foo[0] == 100010
assert foo[1] == 350020
}
}

View File

@ -38,8 +38,8 @@ fn test_shared_receiver_lock() {
}
}
// the following would be a good application for a channel
for finished := false; ; {
lock z {
for finished := false; true; {
rlock z {
finished = z.a == 0
}
if finished {
@ -47,7 +47,7 @@ fn test_shared_receiver_lock() {
}
time.sleep_ms(100)
}
lock x, y {
rlock x, y {
assert x.a == 7 && y.a == 5
}
}

View File

@ -44,9 +44,9 @@ fn test_shared_lock() {
time.sleep_ms(20)
}
// wait until all read threads are finished
for finished := false; ; {
for finished := false; true; {
mut rr := 0
lock z {
rlock z {
rr = z.a
finished = z.a == 0
}

View File

@ -44,9 +44,9 @@ fn test_shared_lock() {
time.sleep_ms(20)
}
// wait until all read threads are finished
for finished := false; ; {
for finished := false; true; {
mut rr := 0
lock z {
rlock z {
rr = z.a
finished = z.a == 0
}

View File

@ -38,8 +38,8 @@ fn test_shared_lock() {
}
}
// the following would be a good application for a channel
for finished := false; ; {
lock z {
for finished := false; true; {
rlock z {
finished = z.a == 0
}
if finished {
@ -47,7 +47,7 @@ fn test_shared_lock() {
}
time.sleep_ms(100)
}
lock x, y {
rlock x, y {
assert x.a == 7 && y.a == 5
}
}