| // 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 | |
| } | |
| } | |
| } |