diff options
Diffstat (limited to 'src/runtime/testdata')
| -rw-r--r-- | src/runtime/testdata/testprog/coro.go | 185 | ||||
| -rw-r--r-- | src/runtime/testdata/testprogcgo/coro.go | 185 |
2 files changed, 370 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/coro.go b/src/runtime/testdata/testprog/coro.go new file mode 100644 index 0000000000..032215b801 --- /dev/null +++ b/src/runtime/testdata/testprog/coro.go @@ -0,0 +1,185 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build goexperiment.rangefunc + +package main + +import ( + "fmt" + "iter" + "runtime" +) + +func init() { + register("CoroLockOSThreadIterLock", func() { + println("expect: OK") + CoroLockOSThread(callerExhaust, iterLock) + }) + register("CoroLockOSThreadIterLockYield", func() { + println("expect: OS thread locking must match") + CoroLockOSThread(callerExhaust, iterLockYield) + }) + register("CoroLockOSThreadLock", func() { + println("expect: OK") + CoroLockOSThread(callerExhaustLocked, iterSimple) + }) + register("CoroLockOSThreadLockIterNested", func() { + println("expect: OK") + CoroLockOSThread(callerExhaustLocked, iterNested) + }) + register("CoroLockOSThreadLockIterLock", func() { + println("expect: OK") + CoroLockOSThread(callerExhaustLocked, iterLock) + }) + register("CoroLockOSThreadLockIterLockYield", func() { + println("expect: OS thread locking must match") + CoroLockOSThread(callerExhaustLocked, iterLockYield) + }) + register("CoroLockOSThreadLockIterYieldNewG", func() { + println("expect: OS thread locking must match") + CoroLockOSThread(callerExhaustLocked, iterYieldNewG) + }) + register("CoroLockOSThreadLockAfterPull", func() { + println("expect: OS thread locking must match") + CoroLockOSThread(callerLockAfterPull, iterSimple) + }) + register("CoroLockOSThreadStopLocked", func() { + println("expect: OK") + CoroLockOSThread(callerStopLocked, iterSimple) + }) + register("CoroLockOSThreadStopLockedIterNested", func() { + println("expect: OK") + CoroLockOSThread(callerStopLocked, iterNested) + }) +} + +func CoroLockOSThread(driver func(iter.Seq[int]) error, seq iter.Seq[int]) { + if err := driver(seq); err != nil { + println("error:", err.Error()) + return + } + println("OK") +} + +func callerExhaust(i iter.Seq[int]) error { + next, _ := iter.Pull(i) + for { + v, ok := next() + if !ok { + break + } + if v != 5 { + return fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + return nil +} + +func callerExhaustLocked(i iter.Seq[int]) error { + runtime.LockOSThread() + next, _ := iter.Pull(i) + for { + v, ok := next() + if !ok { + break + } + if v != 5 { + return fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + runtime.UnlockOSThread() + return nil +} + +func callerLockAfterPull(i iter.Seq[int]) error { + n := 0 + next, _ := iter.Pull(i) + for { + runtime.LockOSThread() + n++ + v, ok := next() + if !ok { + break + } + if v != 5 { + return fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + for range n { + runtime.UnlockOSThread() + } + return nil +} + +func callerStopLocked(i iter.Seq[int]) error { + runtime.LockOSThread() + next, stop := iter.Pull(i) + v, _ := next() + stop() + if v != 5 { + return fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + runtime.UnlockOSThread() + return nil +} + +func iterSimple(yield func(int) bool) { + for range 3 { + if !yield(5) { + return + } + } +} + +func iterNested(yield func(int) bool) { + next, stop := iter.Pull(iterSimple) + for { + v, ok := next() + if ok { + if !yield(v) { + stop() + } + } else { + return + } + } +} + +func iterLock(yield func(int) bool) { + for range 3 { + runtime.LockOSThread() + runtime.UnlockOSThread() + + if !yield(5) { + return + } + } +} + +func iterLockYield(yield func(int) bool) { + for range 3 { + runtime.LockOSThread() + ok := yield(5) + runtime.UnlockOSThread() + if !ok { + return + } + } +} + +func iterYieldNewG(yield func(int) bool) { + for range 3 { + done := make(chan struct{}) + var ok bool + go func() { + ok = yield(5) + done <- struct{}{} + }() + <-done + if !ok { + return + } + } +} diff --git a/src/runtime/testdata/testprogcgo/coro.go b/src/runtime/testdata/testprogcgo/coro.go new file mode 100644 index 0000000000..e0cb945112 --- /dev/null +++ b/src/runtime/testdata/testprogcgo/coro.go @@ -0,0 +1,185 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build goexperiment.rangefunc && !windows + +package main + +/* +#include <stdint.h> // for uintptr_t + +void go_callback_coro(uintptr_t handle); + +static void call_go(uintptr_t handle) { + go_callback_coro(handle); +} +*/ +import "C" + +import ( + "fmt" + "iter" + "runtime/cgo" +) + +func init() { + register("CoroCgoIterCallback", func() { + println("expect: OK") + CoroCgo(callerExhaust, iterCallback) + }) + register("CoroCgoIterCallbackYield", func() { + println("expect: OS thread locking must match") + CoroCgo(callerExhaust, iterCallbackYield) + }) + register("CoroCgoCallback", func() { + println("expect: OK") + CoroCgo(callerExhaustCallback, iterSimple) + }) + register("CoroCgoCallbackIterNested", func() { + println("expect: OK") + CoroCgo(callerExhaustCallback, iterNested) + }) + register("CoroCgoCallbackIterCallback", func() { + println("expect: OK") + CoroCgo(callerExhaustCallback, iterCallback) + }) + register("CoroCgoCallbackIterCallbackYield", func() { + println("expect: OS thread locking must match") + CoroCgo(callerExhaustCallback, iterCallbackYield) + }) + register("CoroCgoCallbackAfterPull", func() { + println("expect: OS thread locking must match") + CoroCgo(callerCallbackAfterPull, iterSimple) + }) + register("CoroCgoStopCallback", func() { + println("expect: OK") + CoroCgo(callerStopCallback, iterSimple) + }) + register("CoroCgoStopCallbackIterNested", func() { + println("expect: OK") + CoroCgo(callerStopCallback, iterNested) + }) +} + +var toCall func() + +//export go_callback_coro +func go_callback_coro(handle C.uintptr_t) { + h := cgo.Handle(handle) + h.Value().(func())() + h.Delete() +} + +func callFromC(f func()) { + C.call_go(C.uintptr_t(cgo.NewHandle(f))) +} + +func CoroCgo(driver func(iter.Seq[int]) error, seq iter.Seq[int]) { + if err := driver(seq); err != nil { + println("error:", err.Error()) + return + } + println("OK") +} + +func callerExhaust(i iter.Seq[int]) error { + next, _ := iter.Pull(i) + for { + v, ok := next() + if !ok { + break + } + if v != 5 { + return fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + return nil +} + +func callerExhaustCallback(i iter.Seq[int]) (err error) { + callFromC(func() { + next, _ := iter.Pull(i) + for { + v, ok := next() + if !ok { + break + } + if v != 5 { + err = fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + }) + return err +} + +func callerStopCallback(i iter.Seq[int]) (err error) { + callFromC(func() { + next, stop := iter.Pull(i) + v, _ := next() + stop() + if v != 5 { + err = fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + }) + return err +} + +func callerCallbackAfterPull(i iter.Seq[int]) (err error) { + next, _ := iter.Pull(i) + callFromC(func() { + for { + v, ok := next() + if !ok { + break + } + if v != 5 { + err = fmt.Errorf("bad iterator: wanted value %d, got %d", 5, v) + } + } + }) + return err +} + +func iterSimple(yield func(int) bool) { + for range 3 { + if !yield(5) { + return + } + } +} + +func iterNested(yield func(int) bool) { + next, stop := iter.Pull(iterSimple) + for { + v, ok := next() + if ok { + if !yield(v) { + stop() + } + } else { + return + } + } +} + +func iterCallback(yield func(int) bool) { + for range 3 { + callFromC(func() {}) + if !yield(5) { + return + } + } +} + +func iterCallbackYield(yield func(int) bool) { + for range 3 { + var ok bool + callFromC(func() { + ok = yield(5) + }) + if !ok { + return + } + } +} |
