Source file src/internal/synctest/synctest.go
1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package synctest provides support for testing concurrent code. 6 // 7 // See the testing/synctest package for function documentation. 8 package synctest 9 10 import ( 11 "internal/abi" 12 "unsafe" 13 ) 14 15 //go:linkname Run 16 func Run(f func()) 17 18 //go:linkname Wait 19 func Wait() 20 21 // IsInBubble reports whether the current goroutine is in a bubble. 22 // 23 //go:linkname IsInBubble 24 func IsInBubble() bool 25 26 // Association is the state of a pointer's bubble association. 27 type Association int 28 29 const ( 30 Unbubbled = Association(iota) // not associated with any bubble 31 CurrentBubble // associated with the current bubble 32 OtherBubble // associated with a different bubble 33 ) 34 35 // Associate attempts to associate p with the current bubble. 36 // It returns the new association status of p. 37 func Associate[T any](p *T) Association { 38 // Ensure p escapes to permit us to attach a special to it. 39 escapedP := abi.Escape(p) 40 return Association(associate(unsafe.Pointer(escapedP))) 41 } 42 43 //go:linkname associate 44 func associate(p unsafe.Pointer) int 45 46 // Disassociate disassociates p from any bubble. 47 func Disassociate[T any](p *T) { 48 disassociate(unsafe.Pointer(p)) 49 } 50 51 //go:linkname disassociate 52 func disassociate(b unsafe.Pointer) 53 54 // IsAssociated reports whether p is associated with the current bubble. 55 func IsAssociated[T any](p *T) bool { 56 return isAssociated(unsafe.Pointer(p)) 57 } 58 59 //go:linkname isAssociated 60 func isAssociated(p unsafe.Pointer) bool 61 62 //go:linkname acquire 63 func acquire() any 64 65 //go:linkname release 66 func release(any) 67 68 //go:linkname inBubble 69 func inBubble(any, func()) 70 71 // A Bubble is a synctest bubble. 72 // 73 // Not a public API. Used by syscall/js to propagate bubble membership through syscalls. 74 type Bubble struct { 75 b any 76 } 77 78 // Acquire returns a reference to the current goroutine's bubble. 79 // The bubble will not become idle until Release is called. 80 func Acquire() *Bubble { 81 if b := acquire(); b != nil { 82 return &Bubble{b} 83 } 84 return nil 85 } 86 87 // Release releases the reference to the bubble, 88 // allowing it to become idle again. 89 func (b *Bubble) Release() { 90 if b == nil { 91 return 92 } 93 release(b.b) 94 b.b = nil 95 } 96 97 // Run executes f in the bubble. 98 // The current goroutine must not be part of a bubble. 99 func (b *Bubble) Run(f func()) { 100 if b == nil { 101 f() 102 } else { 103 inBubble(b.b, f) 104 } 105 } 106