|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
println("main 1")
|
|
|
|
go sub()
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
println("main 2")
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
println("main 3")
|
|
|
|
|
|
|
|
// Await a blocking call. This must create a new coroutine.
|
|
|
|
println("wait:")
|
|
|
|
wait()
|
|
|
|
println("end waiting")
|
|
|
|
|
|
|
|
value := delayedValue()
|
|
|
|
println("value produced after some time:", value)
|
|
|
|
|
|
|
|
// Run a non-blocking call in a goroutine. This should be turned into a
|
|
|
|
// regular call, so should be equivalent to calling nowait() without 'go'
|
|
|
|
// prefix.
|
|
|
|
go nowait()
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
println("done with non-blocking goroutine")
|
|
|
|
|
|
|
|
var printer Printer
|
|
|
|
printer = &myPrinter{}
|
|
|
|
printer.Print()
|
|
|
|
|
|
|
|
sleepFuncValue(func(x int) {
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
println("slept inside func pointer", x)
|
|
|
|
})
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
n := 20
|
|
|
|
sleepFuncValue(func(x int) {
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
println("slept inside closure, with value:", n, x)
|
|
|
|
})
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
|
|
|
|
var x int
|
|
|
|
go func() {
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
x = 1
|
|
|
|
}()
|
|
|
|
time.Sleep(time.Second / 2)
|
|
|
|
println("closure go call result:", x)
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
|
|
|
|
var m sync.Mutex
|
|
|
|
m.Lock()
|
|
|
|
println("pre-acquired mutex")
|
|
|
|
go acquire(&m)
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
println("releasing mutex")
|
|
|
|
m.Unlock()
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
m.Lock()
|
|
|
|
println("re-acquired mutex")
|
|
|
|
m.Unlock()
|
|
|
|
println("done")
|
|
|
|
|
|
|
|
startSimpleFunc(emptyFunc)
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
|
|
|
|
testGoOnBuiltins()
|
|
|
|
|
|
|
|
testCond()
|
|
|
|
|
|
|
|
testIssue1790()
|
|
|
|
}
|
|
|
|
|
|
|
|
func acquire(m *sync.Mutex) {
|
|
|
|
m.Lock()
|
|
|
|
println("acquired mutex from goroutine")
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
m.Unlock()
|
|
|
|
println("released mutex from goroutine")
|
|
|
|
}
|
|
|
|
|
|
|
|
func sub() {
|
|
|
|
println("sub 1")
|
|
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
println("sub 2")
|
|
|
|
}
|
|
|
|
|
|
|
|
func wait() {
|
|
|
|
println(" wait start")
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
println(" wait end")
|
|
|
|
}
|
|
|
|
|
|
|
|
func delayedValue() int {
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
return 42
|
|
|
|
}
|
|
|
|
|
|
|
|
func sleepFuncValue(fn func(int)) {
|
|
|
|
go fn(8)
|
|
|
|
}
|
|
|
|
|
|
|
|
func startSimpleFunc(fn simpleFunc) {
|
|
|
|
// Test that named function types don't crash the compiler.
|
|
|
|
go fn()
|
|
|
|
}
|
|
|
|
|
|
|
|
func nowait() {
|
|
|
|
println("non-blocking goroutine")
|
|
|
|
}
|
|
|
|
|
|
|
|
type Printer interface {
|
|
|
|
Print()
|
|
|
|
}
|
|
|
|
|
|
|
|
type myPrinter struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *myPrinter) Print() {
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
println("async interface method call")
|
|
|
|
}
|
|
|
|
|
|
|
|
type simpleFunc func()
|
|
|
|
|
|
|
|
func emptyFunc() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func testGoOnBuiltins() {
|
|
|
|
// Test copy builtin (there is no non-racy practical use of this).
|
|
|
|
go copy(make([]int, 8), []int{2, 5, 8, 4})
|
|
|
|
|
|
|
|
// Test recover builtin (no-op).
|
|
|
|
go recover()
|
|
|
|
|
|
|
|
// Test close builtin.
|
|
|
|
ch := make(chan int)
|
|
|
|
go close(ch)
|
|
|
|
n, ok := <-ch
|
|
|
|
if n != 0 || ok != false {
|
|
|
|
println("error: expected closed channel to return 0, false")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test delete builtin.
|
|
|
|
m := map[string]int{"foo": 3}
|
|
|
|
go delete(m, "foo")
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
v, ok := m["foo"]
|
|
|
|
if v != 0 || ok != false {
|
|
|
|
println("error: expected deleted map entry to be 0, false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCond() {
|
|
|
|
var cond runtime.Cond
|
|
|
|
go func() {
|
|
|
|
// Wait for the caller to wait on the cond.
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
|
|
|
|
// Notify the caller.
|
|
|
|
ok := cond.Notify()
|
|
|
|
if !ok {
|
|
|
|
panic("notification not sent")
|
|
|
|
}
|
|
|
|
|
|
|
|
// This notification will be buffered inside the cond.
|
|
|
|
ok = cond.Notify()
|
|
|
|
if !ok {
|
|
|
|
panic("notification not queued")
|
|
|
|
}
|
|
|
|
|
|
|
|
// This notification should fail, since there is already one buffered.
|
|
|
|
ok = cond.Notify()
|
|
|
|
if ok {
|
|
|
|
panic("notification double-sent")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Verify that the cond has no pending notifications.
|
|
|
|
ok := cond.Poll()
|
|
|
|
if ok {
|
|
|
|
panic("unexpected early notification")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for the goroutine spawned earlier to send a notification.
|
|
|
|
cond.Wait()
|
|
|
|
|
|
|
|
// The goroutine should have also queued a notification in the cond.
|
|
|
|
ok = cond.Poll()
|
|
|
|
if !ok {
|
|
|
|
panic("missing queued notification")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var once sync.Once
|
|
|
|
|
|
|
|
// This tests a fix for issue 1790:
|
|
|
|
// https://github.com/tinygo-org/tinygo/issues/1790
|
|
|
|
func testIssue1790() *int {
|
|
|
|
once.Do(func() {})
|
|
|
|
i := 0
|
|
|
|
return &i
|
|
|
|
}
|