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  }