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  

View as plain text