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() testGoOnInterface(Foo(0)) 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 func testGoOnInterface(f Itf) { go f.Nowait() time.Sleep(time.Millisecond) go f.Wait() time.Sleep(time.Millisecond * 2) println("done with 'go on interface'") } // 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 } type Itf interface { Nowait() Wait() } type Foo string func (f Foo) Nowait() { println("called: Foo.Nowait") } func (f Foo) Wait() { println("called: Foo.Wait") time.Sleep(time.Microsecond) println(" ...waited") }