github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/testdata/goroutines.go (about) 1 package main 2 3 import ( 4 "runtime" 5 "sync" 6 "time" 7 ) 8 9 func init() { 10 println("init") 11 go println("goroutine in init") 12 time.Sleep(1 * time.Millisecond) 13 } 14 15 func main() { 16 println("main 1") 17 go sub() 18 time.Sleep(1 * time.Millisecond) 19 println("main 2") 20 time.Sleep(2 * time.Millisecond) 21 println("main 3") 22 23 // Await a blocking call. 24 println("wait:") 25 wait() 26 println("end waiting") 27 28 value := delayedValue() 29 println("value produced after some time:", value) 30 31 // Run a non-blocking call in a goroutine. This should be turned into a 32 // regular call, so should be equivalent to calling nowait() without 'go' 33 // prefix. 34 go nowait() 35 time.Sleep(time.Millisecond) 36 println("done with non-blocking goroutine") 37 38 var printer Printer 39 printer = &myPrinter{} 40 printer.Print() 41 42 sleepFuncValue(func(x int) { 43 time.Sleep(1 * time.Millisecond) 44 println("slept inside func pointer", x) 45 }) 46 time.Sleep(1 * time.Millisecond) 47 n := 20 48 sleepFuncValue(func(x int) { 49 time.Sleep(1 * time.Millisecond) 50 println("slept inside closure, with value:", n, x) 51 }) 52 53 time.Sleep(2 * time.Millisecond) 54 55 var x int 56 go func() { 57 time.Sleep(2 * time.Millisecond) 58 x = 1 59 }() 60 time.Sleep(time.Second / 2) 61 println("closure go call result:", x) 62 63 time.Sleep(2 * time.Millisecond) 64 65 var m sync.Mutex 66 m.Lock() 67 println("pre-acquired mutex") 68 go acquire(&m) 69 time.Sleep(2 * time.Millisecond) 70 println("releasing mutex") 71 m.Unlock() 72 time.Sleep(2 * time.Millisecond) 73 m.Lock() 74 println("re-acquired mutex") 75 m.Unlock() 76 println("done") 77 78 startSimpleFunc(emptyFunc) 79 80 time.Sleep(2 * time.Millisecond) 81 82 testGoOnBuiltins() 83 84 testGoOnInterface(Foo(0)) 85 86 testCond() 87 88 testIssue1790() 89 } 90 91 func acquire(m *sync.Mutex) { 92 m.Lock() 93 println("acquired mutex from goroutine") 94 time.Sleep(2 * time.Millisecond) 95 m.Unlock() 96 println("released mutex from goroutine") 97 } 98 99 func sub() { 100 println("sub 1") 101 time.Sleep(2 * time.Millisecond) 102 println("sub 2") 103 } 104 105 func wait() { 106 println(" wait start") 107 time.Sleep(time.Millisecond) 108 println(" wait end") 109 } 110 111 func delayedValue() int { 112 time.Sleep(time.Millisecond) 113 return 42 114 } 115 116 func sleepFuncValue(fn func(int)) { 117 go fn(8) 118 } 119 120 func startSimpleFunc(fn simpleFunc) { 121 // Test that named function types don't crash the compiler. 122 go fn() 123 } 124 125 func nowait() { 126 println("non-blocking goroutine") 127 } 128 129 type Printer interface { 130 Print() 131 } 132 133 type myPrinter struct { 134 } 135 136 func (i *myPrinter) Print() { 137 time.Sleep(time.Millisecond) 138 println("async interface method call") 139 } 140 141 type simpleFunc func() 142 143 func emptyFunc() { 144 } 145 146 func testGoOnBuiltins() { 147 // Test copy builtin (there is no non-racy practical use of this). 148 go copy(make([]int, 8), []int{2, 5, 8, 4}) 149 150 // Test recover builtin (no-op). 151 go recover() 152 153 // Test close builtin. 154 ch := make(chan int) 155 go close(ch) 156 n, ok := <-ch 157 if n != 0 || ok != false { 158 println("error: expected closed channel to return 0, false") 159 } 160 161 // Test delete builtin. 162 m := map[string]int{"foo": 3} 163 go delete(m, "foo") 164 time.Sleep(time.Millisecond) 165 v, ok := m["foo"] 166 if v != 0 || ok != false { 167 println("error: expected deleted map entry to be 0, false") 168 } 169 } 170 171 func testCond() { 172 var cond runtime.Cond 173 go func() { 174 // Wait for the caller to wait on the cond. 175 time.Sleep(time.Millisecond) 176 177 // Notify the caller. 178 ok := cond.Notify() 179 if !ok { 180 panic("notification not sent") 181 } 182 183 // This notification will be buffered inside the cond. 184 ok = cond.Notify() 185 if !ok { 186 panic("notification not queued") 187 } 188 189 // This notification should fail, since there is already one buffered. 190 ok = cond.Notify() 191 if ok { 192 panic("notification double-sent") 193 } 194 }() 195 196 // Verify that the cond has no pending notifications. 197 ok := cond.Poll() 198 if ok { 199 panic("unexpected early notification") 200 } 201 202 // Wait for the goroutine spawned earlier to send a notification. 203 cond.Wait() 204 205 // The goroutine should have also queued a notification in the cond. 206 ok = cond.Poll() 207 if !ok { 208 panic("missing queued notification") 209 } 210 } 211 212 var once sync.Once 213 214 func testGoOnInterface(f Itf) { 215 go f.Nowait() 216 time.Sleep(time.Millisecond) 217 go f.Wait() 218 time.Sleep(time.Millisecond * 2) 219 println("done with 'go on interface'") 220 } 221 222 // This tests a fix for issue 1790: 223 // https://github.com/tinygo-org/tinygo/issues/1790 224 func testIssue1790() *int { 225 once.Do(func() {}) 226 i := 0 227 return &i 228 } 229 230 type Itf interface { 231 Nowait() 232 Wait() 233 } 234 235 type Foo string 236 237 func (f Foo) Nowait() { 238 println("called: Foo.Nowait") 239 } 240 241 func (f Foo) Wait() { 242 println("called: Foo.Wait") 243 time.Sleep(time.Microsecond) 244 println(" ...waited") 245 }