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

// Package synctest provides support for testing concurrent code. // // See the testing/synctest package for function documentation.
package synctest import ( ) //go:linkname Run func ( func()) //go:linkname Wait func () // IsInBubble reports whether the current goroutine is in a bubble. // //go:linkname IsInBubble func () bool // Association is the state of a pointer's bubble association. type Association int const ( Unbubbled = Association(iota) // not associated with any bubble CurrentBubble // associated with the current bubble OtherBubble // associated with a different bubble ) // Associate attempts to associate p with the current bubble. // It returns the new association status of p. func [ any]( *) Association { // Ensure p escapes to permit us to attach a special to it. := abi.Escape() return Association(associate(unsafe.Pointer())) } //go:linkname associate func associate( unsafe.Pointer) int // Disassociate disassociates p from any bubble. func [ any]( *) { disassociate(unsafe.Pointer()) } //go:linkname disassociate func disassociate( unsafe.Pointer) // IsAssociated reports whether p is associated with the current bubble. func [ any]( *) bool { return isAssociated(unsafe.Pointer()) } //go:linkname isAssociated func isAssociated( unsafe.Pointer) bool //go:linkname acquire func acquire() any //go:linkname release func release(any) //go:linkname inBubble func inBubble(any, func()) // A Bubble is a synctest bubble. // // Not a public API. Used by syscall/js to propagate bubble membership through syscalls. type Bubble struct { b any } // Acquire returns a reference to the current goroutine's bubble. // The bubble will not become idle until Release is called. func () *Bubble { if := acquire(); != nil { return &Bubble{} } return nil } // Release releases the reference to the bubble, // allowing it to become idle again. func ( *Bubble) () { if == nil { return } release(.b) .b = nil } // Run executes f in the bubble. // The current goroutine must not be part of a bubble. func ( *Bubble) ( func()) { if == nil { () } else { inBubble(.b, ) } }