diff --git a/api/go1.25.txt b/api/go1.25.txt new file mode 100644 index 0000000000..cb3900bf46 --- /dev/null +++ b/api/go1.25.txt @@ -0,0 +1,110 @@ +pkg crypto, func SignMessage(Signer, io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 +pkg crypto, type MessageSigner interface { Public, Sign, SignMessage } #63405 +pkg crypto, type MessageSigner interface, Public() PublicKey #63405 +pkg crypto, type MessageSigner interface, Sign(io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 +pkg crypto, type MessageSigner interface, SignMessage(io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 +pkg crypto/ecdsa, func ParseRawPrivateKey(elliptic.Curve, []uint8) (*PrivateKey, error) #63963 +pkg crypto/ecdsa, func ParseUncompressedPublicKey(elliptic.Curve, []uint8) (*PublicKey, error) #63963 +pkg crypto/ecdsa, method (*PrivateKey) Bytes() ([]uint8, error) #63963 +pkg crypto/ecdsa, method (*PublicKey) Bytes() ([]uint8, error) #63963 +pkg crypto/sha3, method (*SHA3) Clone() (hash.Cloner, error) #69521 +pkg crypto/tls, type Config struct, GetEncryptedClientHelloKeys func(*ClientHelloInfo) ([]EncryptedClientHelloKey, error) #71920 +pkg crypto/tls, type ConnectionState struct, CurveID CurveID #67516 +pkg debug/elf, const PT_RISCV_ATTRIBUTES = 1879048195 #72843 +pkg debug/elf, const PT_RISCV_ATTRIBUTES ProgType #72843 +pkg debug/elf, const SHT_RISCV_ATTRIBUTES = 1879048195 #72843 +pkg debug/elf, const SHT_RISCV_ATTRIBUTES SectionType #72843 +pkg go/ast, const FilterFuncDuplicates //deprecated #73088 +pkg go/ast, const FilterImportDuplicates //deprecated #73088 +pkg go/ast, const FilterUnassociatedComments //deprecated #73088 +pkg go/ast, func FilterPackage //deprecated #73088 +pkg go/ast, func MergePackageFiles //deprecated #73088 +pkg go/ast, func PackageExports //deprecated #73088 +pkg go/ast, func PreorderStack(Node, []Node, func(Node, []Node) bool) #73319 +pkg go/ast, type MergeMode //deprecated #73088 +pkg go/parser, func ParseDir //deprecated #71122 +pkg go/token, method (*FileSet) AddExistingFiles(...*File) #73205 +pkg go/types, const FieldVar = 6 #70250 +pkg go/types, const FieldVar VarKind #70250 +pkg go/types, const LocalVar = 2 #70250 +pkg go/types, const LocalVar VarKind #70250 +pkg go/types, const PackageVar = 1 #70250 +pkg go/types, const PackageVar VarKind #70250 +pkg go/types, const ParamVar = 4 #70250 +pkg go/types, const ParamVar VarKind #70250 +pkg go/types, const RecvVar = 3 #70250 +pkg go/types, const RecvVar VarKind #70250 +pkg go/types, const ResultVar = 5 #70250 +pkg go/types, const ResultVar VarKind #70250 +pkg go/types, func LookupSelection(Type, bool, *Package, string) (Selection, bool) #70737 +pkg go/types, method (*Var) Kind() VarKind #70250 +pkg go/types, method (*Var) SetKind(VarKind) #70250 +pkg go/types, method (VarKind) String() string #70250 +pkg go/types, type VarKind uint8 #70250 +pkg hash, type Cloner interface { BlockSize, Clone, Reset, Size, Sum, Write } #69521 +pkg hash, type Cloner interface, BlockSize() int #69521 +pkg hash, type Cloner interface, Clone() (Cloner, error) #69521 +pkg hash, type Cloner interface, Reset() #69521 +pkg hash, type Cloner interface, Size() int #69521 +pkg hash, type Cloner interface, Sum([]uint8) []uint8 #69521 +pkg hash, type Cloner interface, Write([]uint8) (int, error) #69521 +pkg hash, type XOF interface { BlockSize, Read, Reset, Write } #69518 +pkg hash, type XOF interface, BlockSize() int #69518 +pkg hash, type XOF interface, Read([]uint8) (int, error) #69518 +pkg hash, type XOF interface, Reset() #69518 +pkg hash, type XOF interface, Write([]uint8) (int, error) #69518 +pkg hash/maphash, method (*Hash) Clone() (hash.Cloner, error) #69521 +pkg io/fs, func Lstat(FS, string) (FileInfo, error) #49580 +pkg io/fs, func ReadLink(FS, string) (string, error) #49580 +pkg io/fs, type ReadLinkFS interface { Lstat, Open, ReadLink } #49580 +pkg io/fs, type ReadLinkFS interface, Lstat(string) (FileInfo, error) #49580 +pkg io/fs, type ReadLinkFS interface, Open(string) (File, error) #49580 +pkg io/fs, type ReadLinkFS interface, ReadLink(string) (string, error) #49580 +pkg log/slog, func GroupAttrs(string, ...Attr) Attr #66365 +pkg log/slog, method (Record) Source() *Source #70280 +pkg mime/multipart, func FileContentDisposition(string, string) string #46771 +pkg net/http, func NewCrossOriginProtection() *CrossOriginProtection #73626 +pkg net/http, method (*CrossOriginProtection) AddInsecureBypassPattern(string) #73626 +pkg net/http, method (*CrossOriginProtection) AddTrustedOrigin(string) error #73626 +pkg net/http, method (*CrossOriginProtection) Check(*Request) error #73626 +pkg net/http, method (*CrossOriginProtection) Handler(Handler) Handler #73626 +pkg net/http, method (*CrossOriginProtection) SetDenyHandler(Handler) #73626 +pkg net/http, type CrossOriginProtection struct #73626 +pkg os, method (*Root) Chmod(string, fs.FileMode) error #67002 +pkg os, method (*Root) Chown(string, int, int) error #67002 +pkg os, method (*Root) Chtimes(string, time.Time, time.Time) error #67002 +pkg os, method (*Root) Lchown(string, int, int) error #67002 +pkg os, method (*Root) Link(string, string) error #67002 +pkg os, method (*Root) MkdirAll(string, fs.FileMode) error #67002 +pkg os, method (*Root) ReadFile(string) ([]uint8, error) #73126 +pkg os, method (*Root) Readlink(string) (string, error) #67002 +pkg os, method (*Root) RemoveAll(string) error #67002 +pkg os, method (*Root) Rename(string, string) error #67002 +pkg os, method (*Root) Symlink(string, string) error #67002 +pkg os, method (*Root) WriteFile(string, []uint8, fs.FileMode) error #73126 +pkg reflect, func TypeAssert[$0 interface{}](Value) ($0, bool) #62121 +pkg runtime, func SetDefaultGOMAXPROCS() #73193 +pkg runtime/trace, func NewFlightRecorder(FlightRecorderConfig) *FlightRecorder #63185 +pkg runtime/trace, method (*FlightRecorder) Enabled() bool #63185 +pkg runtime/trace, method (*FlightRecorder) Start() error #63185 +pkg runtime/trace, method (*FlightRecorder) Stop() #63185 +pkg runtime/trace, method (*FlightRecorder) WriteTo(io.Writer) (int64, error) #63185 +pkg runtime/trace, type FlightRecorder struct #63185 +pkg runtime/trace, type FlightRecorderConfig struct #63185 +pkg runtime/trace, type FlightRecorderConfig struct, MaxBytes uint64 #63185 +pkg runtime/trace, type FlightRecorderConfig struct, MinAge time.Duration #63185 +pkg sync, method (*WaitGroup) Go(func()) #63796 +pkg testing, method (*B) Attr(string, string) #43936 +pkg testing, method (*B) Output() io.Writer #59928 +pkg testing, method (*F) Attr(string, string) #43936 +pkg testing, method (*F) Output() io.Writer #59928 +pkg testing, method (*T) Attr(string, string) #43936 +pkg testing, method (*T) Output() io.Writer #59928 +pkg testing, type TB interface, Attr(string, string) #43936 +pkg testing/fstest, method (MapFS) Lstat(string) (fs.FileInfo, error) #49580 +pkg testing/fstest, method (MapFS) ReadLink(string) (string, error) #49580 +pkg testing/synctest, func Test(*testing.T, func(*testing.T)) #67434 +pkg testing/synctest, func Wait() #67434 +pkg unicode, var CategoryAliases map[string]string #70780 +pkg unicode, var Cn *RangeTable #70780 +pkg unicode, var LC *RangeTable #70780 diff --git a/api/next/43936.txt b/api/next/43936.txt deleted file mode 100644 index e32bd75ed9..0000000000 --- a/api/next/43936.txt +++ /dev/null @@ -1,4 +0,0 @@ -pkg testing, method (*B) Attr(string, string) #43936 -pkg testing, method (*F) Attr(string, string) #43936 -pkg testing, method (*T) Attr(string, string) #43936 -pkg testing, type TB interface, Attr(string, string) #43936 diff --git a/api/next/46771.txt b/api/next/46771.txt deleted file mode 100644 index f7aad4b04a..0000000000 --- a/api/next/46771.txt +++ /dev/null @@ -1 +0,0 @@ -pkg mime/multipart, func FileContentDisposition(string, string) string #46771 diff --git a/api/next/49580.txt b/api/next/49580.txt deleted file mode 100644 index ce213cc9ca..0000000000 --- a/api/next/49580.txt +++ /dev/null @@ -1,8 +0,0 @@ -pkg io/fs, func Lstat(FS, string) (FileInfo, error) #49580 -pkg io/fs, func ReadLink(FS, string) (string, error) #49580 -pkg io/fs, type ReadLinkFS interface { Lstat, Open, ReadLink } #49580 -pkg io/fs, type ReadLinkFS interface, Lstat(string) (FileInfo, error) #49580 -pkg io/fs, type ReadLinkFS interface, Open(string) (File, error) #49580 -pkg io/fs, type ReadLinkFS interface, ReadLink(string) (string, error) #49580 -pkg testing/fstest, method (MapFS) Lstat(string) (fs.FileInfo, error) #49580 -pkg testing/fstest, method (MapFS) ReadLink(string) (string, error) #49580 diff --git a/api/next/59928.txt b/api/next/59928.txt deleted file mode 100644 index 375c7c0e90..0000000000 --- a/api/next/59928.txt +++ /dev/null @@ -1,3 +0,0 @@ -pkg testing, method (*B) Output() io.Writer #59928 -pkg testing, method (*F) Output() io.Writer #59928 -pkg testing, method (*T) Output() io.Writer #59928 diff --git a/api/next/62121.txt b/api/next/62121.txt deleted file mode 100644 index bb220a619a..0000000000 --- a/api/next/62121.txt +++ /dev/null @@ -1 +0,0 @@ -pkg reflect, func TypeAssert[$0 interface{}](Value) ($0, bool) #62121 diff --git a/api/next/63185.txt b/api/next/63185.txt deleted file mode 100644 index b5127ff8b2..0000000000 --- a/api/next/63185.txt +++ /dev/null @@ -1,9 +0,0 @@ -pkg runtime/trace, func NewFlightRecorder(FlightRecorderConfig) *FlightRecorder #63185 -pkg runtime/trace, method (*FlightRecorder) Enabled() bool #63185 -pkg runtime/trace, method (*FlightRecorder) Start() error #63185 -pkg runtime/trace, method (*FlightRecorder) Stop() #63185 -pkg runtime/trace, method (*FlightRecorder) WriteTo(io.Writer) (int64, error) #63185 -pkg runtime/trace, type FlightRecorder struct #63185 -pkg runtime/trace, type FlightRecorderConfig struct #63185 -pkg runtime/trace, type FlightRecorderConfig struct, MaxBytes uint64 #63185 -pkg runtime/trace, type FlightRecorderConfig struct, MinAge time.Duration #63185 diff --git a/api/next/63405.txt b/api/next/63405.txt deleted file mode 100644 index 5892ef4adc..0000000000 --- a/api/next/63405.txt +++ /dev/null @@ -1,5 +0,0 @@ -pkg crypto, func SignMessage(Signer, io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 -pkg crypto, type MessageSigner interface { Public, Sign, SignMessage } #63405 -pkg crypto, type MessageSigner interface, Public() PublicKey #63405 -pkg crypto, type MessageSigner interface, Sign(io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 -pkg crypto, type MessageSigner interface, SignMessage(io.Reader, []uint8, SignerOpts) ([]uint8, error) #63405 diff --git a/api/next/63796.txt b/api/next/63796.txt deleted file mode 100644 index bb1a4b4858..0000000000 --- a/api/next/63796.txt +++ /dev/null @@ -1 +0,0 @@ -pkg sync, method (*WaitGroup) Go(func()) #63796 diff --git a/api/next/63963.txt b/api/next/63963.txt deleted file mode 100644 index f64f214c10..0000000000 --- a/api/next/63963.txt +++ /dev/null @@ -1,4 +0,0 @@ -pkg crypto/ecdsa, func ParseRawPrivateKey(elliptic.Curve, []uint8) (*PrivateKey, error) #63963 -pkg crypto/ecdsa, func ParseUncompressedPublicKey(elliptic.Curve, []uint8) (*PublicKey, error) #63963 -pkg crypto/ecdsa, method (*PrivateKey) Bytes() ([]uint8, error) #63963 -pkg crypto/ecdsa, method (*PublicKey) Bytes() ([]uint8, error) #63963 diff --git a/api/next/66365.txt b/api/next/66365.txt deleted file mode 100644 index 52f1c7ea8e..0000000000 --- a/api/next/66365.txt +++ /dev/null @@ -1 +0,0 @@ -pkg log/slog, func GroupAttrs(string, ...Attr) Attr #66365 diff --git a/api/next/67002.txt b/api/next/67002.txt deleted file mode 100644 index 2a442fd6a4..0000000000 --- a/api/next/67002.txt +++ /dev/null @@ -1,10 +0,0 @@ -pkg os, method (*Root) Chmod(string, fs.FileMode) error #67002 -pkg os, method (*Root) Chown(string, int, int) error #67002 -pkg os, method (*Root) Chtimes(string, time.Time, time.Time) error #67002 -pkg os, method (*Root) Lchown(string, int, int) error #67002 -pkg os, method (*Root) Link(string, string) error #67002 -pkg os, method (*Root) MkdirAll(string, fs.FileMode) error #67002 -pkg os, method (*Root) Readlink(string) (string, error) #67002 -pkg os, method (*Root) RemoveAll(string) error #67002 -pkg os, method (*Root) Rename(string, string) error #67002 -pkg os, method (*Root) Symlink(string, string) error #67002 diff --git a/api/next/67434.txt b/api/next/67434.txt deleted file mode 100644 index 203c55e2a6..0000000000 --- a/api/next/67434.txt +++ /dev/null @@ -1,2 +0,0 @@ -pkg testing/synctest, func Test(*testing.T, func(*testing.T)) #67434 -pkg testing/synctest, func Wait() #67434 diff --git a/api/next/67516.txt b/api/next/67516.txt deleted file mode 100644 index a9b6007d06..0000000000 --- a/api/next/67516.txt +++ /dev/null @@ -1 +0,0 @@ -pkg crypto/tls, type ConnectionState struct, CurveID CurveID #67516 diff --git a/api/next/69518.txt b/api/next/69518.txt deleted file mode 100644 index b70fcc13fb..0000000000 --- a/api/next/69518.txt +++ /dev/null @@ -1,5 +0,0 @@ -pkg hash, type XOF interface { BlockSize, Read, Reset, Write } #69518 -pkg hash, type XOF interface, BlockSize() int #69518 -pkg hash, type XOF interface, Read([]uint8) (int, error) #69518 -pkg hash, type XOF interface, Reset() #69518 -pkg hash, type XOF interface, Write([]uint8) (int, error) #69518 diff --git a/api/next/69521.txt b/api/next/69521.txt deleted file mode 100644 index 6974226086..0000000000 --- a/api/next/69521.txt +++ /dev/null @@ -1,9 +0,0 @@ -pkg crypto/sha3, method (*SHA3) Clone() (hash.Cloner, error) #69521 -pkg hash, type Cloner interface { BlockSize, Clone, Reset, Size, Sum, Write } #69521 -pkg hash, type Cloner interface, BlockSize() int #69521 -pkg hash, type Cloner interface, Clone() (Cloner, error) #69521 -pkg hash, type Cloner interface, Reset() #69521 -pkg hash, type Cloner interface, Size() int #69521 -pkg hash, type Cloner interface, Sum([]uint8) []uint8 #69521 -pkg hash, type Cloner interface, Write([]uint8) (int, error) #69521 -pkg hash/maphash, method (*Hash) Clone() (hash.Cloner, error) #69521 diff --git a/api/next/70250.txt b/api/next/70250.txt deleted file mode 100644 index faad356cef..0000000000 --- a/api/next/70250.txt +++ /dev/null @@ -1,17 +0,0 @@ -pkg go/types, const FieldVar = 6 #70250 -pkg go/types, const FieldVar VarKind #70250 -pkg go/types, const LocalVar = 2 #70250 -pkg go/types, const LocalVar VarKind #70250 -pkg go/types, const PackageVar = 1 #70250 -pkg go/types, const PackageVar VarKind #70250 -pkg go/types, const ParamVar = 4 #70250 -pkg go/types, const ParamVar VarKind #70250 -pkg go/types, const RecvVar = 3 #70250 -pkg go/types, const RecvVar VarKind #70250 -pkg go/types, const ResultVar = 5 #70250 -pkg go/types, const ResultVar VarKind #70250 -pkg go/types, func LookupSelection(Type, bool, *Package, string) (Selection, bool) #70737 -pkg go/types, method (*Var) Kind() VarKind #70250 -pkg go/types, method (*Var) SetKind(VarKind) #70250 -pkg go/types, method (VarKind) String() string #70250 -pkg go/types, type VarKind uint8 #70250 diff --git a/api/next/70280.txt b/api/next/70280.txt deleted file mode 100644 index f2dd74af48..0000000000 --- a/api/next/70280.txt +++ /dev/null @@ -1 +0,0 @@ -pkg log/slog, method (Record) Source() *Source #70280 diff --git a/api/next/70780.txt b/api/next/70780.txt deleted file mode 100644 index 2843836ac8..0000000000 --- a/api/next/70780.txt +++ /dev/null @@ -1,3 +0,0 @@ -pkg unicode, var CategoryAliases map[string]string #70780 -pkg unicode, var Cn *RangeTable #70780 -pkg unicode, var LC *RangeTable #70780 diff --git a/api/next/71122.txt b/api/next/71122.txt deleted file mode 100644 index a679899e0c..0000000000 --- a/api/next/71122.txt +++ /dev/null @@ -1 +0,0 @@ -pkg go/parser, func ParseDir //deprecated #71122 diff --git a/api/next/71920.txt b/api/next/71920.txt deleted file mode 100644 index c15759f45f..0000000000 --- a/api/next/71920.txt +++ /dev/null @@ -1 +0,0 @@ -pkg crypto/tls, type Config struct, GetEncryptedClientHelloKeys func(*ClientHelloInfo) ([]EncryptedClientHelloKey, error) #71920 diff --git a/api/next/72843.txt b/api/next/72843.txt deleted file mode 100644 index efd45ccc6f..0000000000 --- a/api/next/72843.txt +++ /dev/null @@ -1,4 +0,0 @@ -pkg debug/elf, const PT_RISCV_ATTRIBUTES = 1879048195 #72843 -pkg debug/elf, const PT_RISCV_ATTRIBUTES ProgType #72843 -pkg debug/elf, const SHT_RISCV_ATTRIBUTES = 1879048195 #72843 -pkg debug/elf, const SHT_RISCV_ATTRIBUTES SectionType #72843 diff --git a/api/next/73088.txt b/api/next/73088.txt deleted file mode 100644 index 2d15b83816..0000000000 --- a/api/next/73088.txt +++ /dev/null @@ -1,7 +0,0 @@ -pkg go/ast, const FilterFuncDuplicates //deprecated #73088 -pkg go/ast, const FilterImportDuplicates //deprecated #73088 -pkg go/ast, const FilterUnassociatedComments //deprecated #73088 -pkg go/ast, func FilterPackage //deprecated #73088 -pkg go/ast, func MergePackageFiles //deprecated #73088 -pkg go/ast, func PackageExports //deprecated #73088 -pkg go/ast, type MergeMode //deprecated #73088 diff --git a/api/next/73126.txt b/api/next/73126.txt deleted file mode 100644 index 9392448c02..0000000000 --- a/api/next/73126.txt +++ /dev/null @@ -1,2 +0,0 @@ -pkg os, method (*Root) ReadFile(string) ([]uint8, error) #73126 -pkg os, method (*Root) WriteFile(string, []uint8, fs.FileMode) error #73126 diff --git a/api/next/73193.txt b/api/next/73193.txt deleted file mode 100644 index f2b6ea748c..0000000000 --- a/api/next/73193.txt +++ /dev/null @@ -1 +0,0 @@ -pkg runtime, func SetDefaultGOMAXPROCS() #73193 diff --git a/api/next/73205.txt b/api/next/73205.txt deleted file mode 100644 index 3cc2c09543..0000000000 --- a/api/next/73205.txt +++ /dev/null @@ -1 +0,0 @@ -pkg go/token, method (*FileSet) AddExistingFiles(...*File) #73205 diff --git a/api/next/73319.txt b/api/next/73319.txt deleted file mode 100644 index 39a3ece5f8..0000000000 --- a/api/next/73319.txt +++ /dev/null @@ -1 +0,0 @@ -pkg go/ast, func PreorderStack(Node, []Node, func(Node, []Node) bool) #73319 diff --git a/api/next/73626.txt b/api/next/73626.txt deleted file mode 100644 index ef4d0683b2..0000000000 --- a/api/next/73626.txt +++ /dev/null @@ -1,7 +0,0 @@ -pkg net/http, func NewCrossOriginProtection() *CrossOriginProtection #73626 -pkg net/http, method (*CrossOriginProtection) AddInsecureBypassPattern(string) #73626 -pkg net/http, method (*CrossOriginProtection) AddTrustedOrigin(string) error #73626 -pkg net/http, method (*CrossOriginProtection) Check(*Request) error #73626 -pkg net/http, method (*CrossOriginProtection) Handler(Handler) Handler #73626 -pkg net/http, method (*CrossOriginProtection) SetDenyHandler(Handler) #73626 -pkg net/http, type CrossOriginProtection struct #73626 diff --git a/doc/next/1-intro.md b/doc/next/1-intro.md deleted file mode 100644 index 77a9aed59f..0000000000 --- a/doc/next/1-intro.md +++ /dev/null @@ -1,8 +0,0 @@ - - -## DRAFT RELEASE NOTES — Introduction to Go 1.N {#introduction} - -**Go 1.25 is not yet released. These are work-in-progress release notes. -Go 1.25 is expected to be released in August 2025.** diff --git a/doc/next/2-language.md b/doc/next/2-language.md deleted file mode 100644 index 61030bd676..0000000000 --- a/doc/next/2-language.md +++ /dev/null @@ -1,3 +0,0 @@ -## Changes to the language {#language} - - diff --git a/doc/next/3-tools.md b/doc/next/3-tools.md deleted file mode 100644 index b61848bca7..0000000000 --- a/doc/next/3-tools.md +++ /dev/null @@ -1,42 +0,0 @@ -## Tools {#tools} - -### Go command {#go-command} - -The `go build` `-asan` option now defaults to doing leak detection at -program exit. -This will report an error if memory allocated by C is not freed and is -not referenced by any other memory allocated by either C or Go. -These new error reports may be disabled by setting -`ASAN_OPTIONS=detect_leaks=0` in the environment when running the -program. - - - -The new `work` package pattern matches all packages in the work (formerly called main) -modules: either the single work module in module mode or the set of workspace modules -in workspace mode. - - - -When the go command updates the `go` line in a `go.mod` or `go.work` file, -it [no longer](/ref/mod#go-mod-file-toolchain) adds a toolchain line -specifying the command's current version. - -### Cgo {#cgo} - -### Vet {#vet} - -The `go vet` command includes new analyzers: - - - -- [waitgroup](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup), - which reports misplaced calls to [sync.WaitGroup.Add]; and - - - -- [hostport](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/hostport), - which reports uses of `fmt.Sprintf("%s:%d", host, port)` to - construct addresses for [net.Dial], as these will not work with - IPv6; instead it suggests using [net.JoinHostPort]. - diff --git a/doc/next/4-runtime.md b/doc/next/4-runtime.md deleted file mode 100644 index 67c1cee401..0000000000 --- a/doc/next/4-runtime.md +++ /dev/null @@ -1,63 +0,0 @@ -## Runtime {#runtime} - - - -The message printed when a program exits due to an unhandled panic -that was recovered and repanicked no longer repeats the text of -the panic value. - -Previously, a program which panicked with `panic("PANIC")`, -recovered the panic, and then repanicked with the original -value would print: - - panic: PANIC [recovered] - panic: PANIC - -This program will now print: - - panic: PANIC [recovered, repanicked] - - - -The default behavior of the `GOMAXPROCS` has changed. In prior versions of Go, -`GOMAXPROCS` defaults to the number of logical CPUs available at startup -([runtime.NumCPU]). Go 1.25 introduces two changes: - -1. On Linux, the runtime considers the CPU bandwidth limit of the cgroup - containing the process, if any. If the CPU bandwidth limit is lower than the - number of logical CPUs available, `GOMAXPROCS` will default to the lower - limit. In container runtime systems like Kubernetes, cgroup CPU bandwidth - limits generally correspond to the "CPU limit" option. The Go runtime does - not consider the "CPU requests" option. - -2. On all OSes, the runtime periodically updates `GOMAXPROCS` if the number - of logical CPUs available or the cgroup CPU bandwidth limit change. - -Both of these behaviors are automatically disabled if `GOMAXPROCS` is set -manually via the `GOMAXPROCS` environment variable or a call to -[runtime.GOMAXPROCS]. They can also be disabled explicitly with the [GODEBUG -settings](/doc/godebug) `containermaxprocs=0` and `updatemaxprocs=0`, -respectively. - -In order to support reading updated cgroup limits, the runtime will keep cached -file descriptors for the cgroup files for the duration of the process lifetime. - - - -On Linux systems with kernel support for anonymous VMA names -(`CONFIG_ANON_VMA_NAME`), the Go runtime will annotate anonymous memory -mappings with context about their purpose. e.g., `[anon: Go: heap]` for heap -memory. This can be disabled with the [GODEBUG setting](/doc/godebug) -`decoratemappings=0`. - - - -A new experimental garbage collector is now available as an experiment. The -new design aims to improve the efficiency of garbage collection through better -locality and CPU scalability in the mark algorithm. Benchmark result vary, but -we expect somewhere between a 10—40% reduction in garbage collection overhead -in real-world programs that heavily use the garbage collector. - -The new garbage collector may be enabled by setting `GOEXPERIMENT=greenteagc` -at build time. See the [GitHub issue](/issue/73581) for more details on the design -and instructions on how to report feedback. diff --git a/doc/next/5-toolchain.md b/doc/next/5-toolchain.md deleted file mode 100644 index 84a7624bb5..0000000000 --- a/doc/next/5-toolchain.md +++ /dev/null @@ -1,56 +0,0 @@ -## Compiler {#compiler} - - - -The compiler and linker in Go 1.25 now generate debug information -using [DWARF version 5](https://dwarfstd.org/dwarf5std.html); the -newer DWARF version reduces the space required for debugging -information in Go binaries. -DWARF 5 generation is gated by the "dwarf5" GOEXPERIMENT; this -functionality can be disabled (for now) using GOEXPERIMENT=nodwarf5. - - - -The compiler [has been fixed](/cl/657715) -to ensure that nil pointer checks are performed promptly. Programs like the following, -which used to execute successfully, will now panic with a nil-pointer exception: - -``` -package main - -import "os" - -func main() { - f, err := os.Open("nonExistentFile") - name := f.Name() - if err != nil { - return - } - println(name) -} -``` - -This program is incorrect in that it uses the result of `os.Open` before checking -the error. The main result of `os.Open` can be a nil pointer if the error result is non-nil. -But because of [a compiler bug](/issue/72860), this program ran successfully under -Go versions 1.21 through 1.24 (in violation of the Go spec). It will no longer run -successfully in Go 1.25. If this change is affecting your code, the solution is to put -the non-nil error check earlier in your code, preferably immediately after -the error-generating statement. - - - -The compiler can now allocate the backing store for slices on the -stack in more situations, which improves performance. This change has -the potential to amplify the effects of incorrect -[unsafe.Pointer](/pkg/unsafe#Pointer) usage, see for example [issue -73199](/issue/73199). In order to track down these problems, the -[bisect tool](https://pkg.go.dev/golang.org/x/tools/cmd/bisect) can be -used to find the allocation causing trouble using the -`-compile=variablemake` flag. All such new stack allocations can also -be turned off using `-gcflags=all=-d=variablemakehash=n`. - -## Assembler {#assembler} - -## Linker {#linker} - diff --git a/doc/next/6-stdlib/0-heading.md b/doc/next/6-stdlib/0-heading.md deleted file mode 100644 index a992170d43..0000000000 --- a/doc/next/6-stdlib/0-heading.md +++ /dev/null @@ -1,2 +0,0 @@ -## Standard library {#library} - diff --git a/doc/next/6-stdlib/1-synctest.md b/doc/next/6-stdlib/1-synctest.md deleted file mode 100644 index 0a34930470..0000000000 --- a/doc/next/6-stdlib/1-synctest.md +++ /dev/null @@ -1,12 +0,0 @@ -### New testing/synctest package - - -The new [testing/synctest](/pkg/testing/synctest) package -provides support for testing concurrent code. - -The [synctest.Test] function runs a test function in an isolated -"bubble". Within the bubble, [time](/pkg/time) package functions -operate on a fake clock. - -The [synctest.Wait] function waits for all goroutines in the -current bubble to block. diff --git a/doc/next/6-stdlib/99-minor/0-heading.md b/doc/next/6-stdlib/99-minor/0-heading.md deleted file mode 100644 index a98105e8cc..0000000000 --- a/doc/next/6-stdlib/99-minor/0-heading.md +++ /dev/null @@ -1,3 +0,0 @@ -### Minor changes to the library {#minor_library_changes} - - diff --git a/doc/next/6-stdlib/99-minor/README b/doc/next/6-stdlib/99-minor/README deleted file mode 100644 index fac778de05..0000000000 --- a/doc/next/6-stdlib/99-minor/README +++ /dev/null @@ -1 +0,0 @@ -API changes and other small changes to the standard library go here. diff --git a/doc/next/6-stdlib/99-minor/archive/tar/49580.md b/doc/next/6-stdlib/99-minor/archive/tar/49580.md deleted file mode 100644 index 8fa43681fa..0000000000 --- a/doc/next/6-stdlib/99-minor/archive/tar/49580.md +++ /dev/null @@ -1,2 +0,0 @@ -The [*Writer.AddFS] implementation now supports symbolic links -for filesystems that implement [io/fs.ReadLinkFS]. diff --git a/doc/next/6-stdlib/99-minor/crypto/63405.md b/doc/next/6-stdlib/99-minor/crypto/63405.md deleted file mode 100644 index d16dc5ab00..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/63405.md +++ /dev/null @@ -1 +0,0 @@ -[MessageSigner] is a new signing interface that can be implemented by signers that wish to hash the message to be signed themselves. A new function is also introduced, [SignMessage] which attempts to update a [Signer] interface to [MessageSigner], using the [MessageSigner.SignMessage] method if successful, and [Signer.Sign] if not. This can be used when code wishes to support both [Signer] and [MessageSigner]. \ No newline at end of file diff --git a/doc/next/6-stdlib/99-minor/crypto/ecdsa/63963.md b/doc/next/6-stdlib/99-minor/crypto/ecdsa/63963.md deleted file mode 100644 index 5c329c7d51..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/ecdsa/63963.md +++ /dev/null @@ -1,3 +0,0 @@ -The new [ParseRawPrivateKey], [ParseUncompressedPublicKey], [PrivateKey.Bytes], -and [PublicKey.Bytes] functions and methods implement low-level encodings, -replacing the need to use crypto/elliptic or math/big functions and methods. diff --git a/doc/next/6-stdlib/99-minor/crypto/elliptic/hidden.md b/doc/next/6-stdlib/99-minor/crypto/elliptic/hidden.md deleted file mode 100644 index eb3bef50d3..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/elliptic/hidden.md +++ /dev/null @@ -1,2 +0,0 @@ -The hidden and undocumented `Inverse` and `CombinedMult` methods on some [Curve] -implementations have been removed. diff --git a/doc/next/6-stdlib/99-minor/crypto/sha3/69521.md b/doc/next/6-stdlib/99-minor/crypto/sha3/69521.md deleted file mode 100644 index 2af674dcb4..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/sha3/69521.md +++ /dev/null @@ -1 +0,0 @@ -The new [SHA3.Clone] method implements [hash.Cloner](/pkg/hash#Cloner). diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/67516.md b/doc/next/6-stdlib/99-minor/crypto/tls/67516.md deleted file mode 100644 index 3790533d16..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/tls/67516.md +++ /dev/null @@ -1,2 +0,0 @@ -The new [ConnectionState.CurveID] field exposes the key exchange mechanism used -to establish the connection. diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/71920.md b/doc/next/6-stdlib/99-minor/crypto/tls/71920.md deleted file mode 100644 index 848211751a..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/tls/71920.md +++ /dev/null @@ -1,3 +0,0 @@ -The new [Config.GetEncryptedClientHelloKeys] callback can be used to set the -[EncryptedClientHelloKey]s for a server to use when a client sends an Encrypted -Client Hello extension. \ No newline at end of file diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/72883.md b/doc/next/6-stdlib/99-minor/crypto/tls/72883.md deleted file mode 100644 index 70e06192a3..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/tls/72883.md +++ /dev/null @@ -1,3 +0,0 @@ -SHA-1 signature algorithms are now disallowed in TLS 1.2 handshakes, per -[RFC 9155](https://www.rfc-editor.org/rfc/rfc9155.html). -They can be re-enabled with the `tlssha1=1` GODEBUG option. diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/fips.md b/doc/next/6-stdlib/99-minor/crypto/tls/fips.md deleted file mode 100644 index 0f0c9459ce..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/tls/fips.md +++ /dev/null @@ -1,2 +0,0 @@ -When [FIPS 140-3 mode](/doc/security/fips140) is enabled, Extended Master Secret -is now required in TLS 1.2, and Ed25519 and X25519MLKEM768 are now allowed. diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/version_pref.md b/doc/next/6-stdlib/99-minor/crypto/tls/version_pref.md deleted file mode 100644 index 5686f3ca0a..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/tls/version_pref.md +++ /dev/null @@ -1 +0,0 @@ -TLS servers now prefer the highest supported protocol version, even if it isn't the client's most preferred protocol version. diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/63405.md b/doc/next/6-stdlib/99-minor/crypto/x509/63405.md deleted file mode 100644 index 4c3a1750da..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/x509/63405.md +++ /dev/null @@ -1 +0,0 @@ -[CreateCertificate], [CreateCertificateRequest], and [CreateRevocationList] can now accept a [crypto.MessageSigner] signing interface as well as [crypto.Signer]. This allows these functions to use signers which implement "one-shot" signing interfaces, where hashing is done as part of the signing operation, instead of by the caller. \ No newline at end of file diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/71746.md b/doc/next/6-stdlib/99-minor/crypto/x509/71746.md deleted file mode 100644 index 44e60293d3..0000000000 --- a/doc/next/6-stdlib/99-minor/crypto/x509/71746.md +++ /dev/null @@ -1,2 +0,0 @@ -[CreateCertificate] now uses truncated SHA-256 to populate the `SubjectKeyId` if -it is missing. The GODEBUG setting `x509sha256skid=0` reverts to SHA-1. diff --git a/doc/next/6-stdlib/99-minor/debug/elf/72843.md b/doc/next/6-stdlib/99-minor/debug/elf/72843.md deleted file mode 100644 index 491c2dc1a1..0000000000 --- a/doc/next/6-stdlib/99-minor/debug/elf/72843.md +++ /dev/null @@ -1,4 +0,0 @@ -The [debug/elf] package adds two new constants: -- [PT_RISCV_ATTRIBUTES] -- [SHT_RISCV_ATTRIBUTES] -for RISC-V ELF parsing. diff --git a/doc/next/6-stdlib/99-minor/go/ast/73088.md b/doc/next/6-stdlib/99-minor/go/ast/73088.md deleted file mode 100644 index e7035a7047..0000000000 --- a/doc/next/6-stdlib/99-minor/go/ast/73088.md +++ /dev/null @@ -1,4 +0,0 @@ -The [ast.FilterPackage], [ast.PackageExports], and -[ast.MergePackageFiles] functions, and the [MergeMode] type and its -constants, are all deprecated, as they are for use only with the -long-deprecated [ast.Object] and [ast.Package] machinery. diff --git a/doc/next/6-stdlib/99-minor/go/ast/73319.md b/doc/next/6-stdlib/99-minor/go/ast/73319.md deleted file mode 100644 index b99e20e316..0000000000 --- a/doc/next/6-stdlib/99-minor/go/ast/73319.md +++ /dev/null @@ -1,4 +0,0 @@ -The new [PreorderStack] function, like [Inspect], traverses a syntax -tree and provides control over descent into subtrees, but as a -convenience it also provides the stack of enclosing nodes at each -point. diff --git a/doc/next/6-stdlib/99-minor/go/parser/71122.md b/doc/next/6-stdlib/99-minor/go/parser/71122.md deleted file mode 100644 index 2043d30403..0000000000 --- a/doc/next/6-stdlib/99-minor/go/parser/71122.md +++ /dev/null @@ -1 +0,0 @@ -The [ParseDir] function is deprecated. diff --git a/doc/next/6-stdlib/99-minor/go/token/73205.md b/doc/next/6-stdlib/99-minor/go/token/73205.md deleted file mode 100644 index d743663736..0000000000 --- a/doc/next/6-stdlib/99-minor/go/token/73205.md +++ /dev/null @@ -1,4 +0,0 @@ -The new [FileSet.AddExistingFiles] method enables existing Files to be -added to a FileSet, or a FileSet to be constructed for an arbitrary -set of Files, alleviating the problems associated with a single global -FileSet in long-lived applications. diff --git a/doc/next/6-stdlib/99-minor/go/types/70250.md b/doc/next/6-stdlib/99-minor/go/types/70250.md deleted file mode 100644 index 49fbdadfe9..0000000000 --- a/doc/next/6-stdlib/99-minor/go/types/70250.md +++ /dev/null @@ -1,3 +0,0 @@ -[Var] now has a [Var.Kind] method that classifies the variable as one -of: package-level, receiver, parameter, result, or local variable, or -a struct field. diff --git a/doc/next/6-stdlib/99-minor/go/types/70737.md b/doc/next/6-stdlib/99-minor/go/types/70737.md deleted file mode 100644 index 6d1b4136bf..0000000000 --- a/doc/next/6-stdlib/99-minor/go/types/70737.md +++ /dev/null @@ -1,3 +0,0 @@ -The new [LookupSelection] function looks up the field or method of a -given name and receiver type, like the existing [LookupFieldOrMethod] -function, but returns the result in the form of a [Selection]. diff --git a/doc/next/6-stdlib/99-minor/hash/69518.md b/doc/next/6-stdlib/99-minor/hash/69518.md deleted file mode 100644 index ae9e133cd7..0000000000 --- a/doc/next/6-stdlib/99-minor/hash/69518.md +++ /dev/null @@ -1,3 +0,0 @@ -The new [XOF](/pkg/hash#XOF) interface can be implemented by "extendable output -functions", which are hash functions with arbitrary or unlimited output length -such as [SHAKE](https://pkg.go.dev/crypto/sha3#SHAKE). diff --git a/doc/next/6-stdlib/99-minor/hash/69521.md b/doc/next/6-stdlib/99-minor/hash/69521.md deleted file mode 100644 index a8d58e3074..0000000000 --- a/doc/next/6-stdlib/99-minor/hash/69521.md +++ /dev/null @@ -1,2 +0,0 @@ -Hashes implementing the new [Cloner] interface can return a copy of their state. -All standard library [Hash] implementations now implement [Cloner]. diff --git a/doc/next/6-stdlib/99-minor/hash/maphash/69521.md b/doc/next/6-stdlib/99-minor/hash/maphash/69521.md deleted file mode 100644 index 497df8b6aa..0000000000 --- a/doc/next/6-stdlib/99-minor/hash/maphash/69521.md +++ /dev/null @@ -1 +0,0 @@ -The new [Hash.Clone] method implements [hash.Cloner](/pkg/hash#Cloner). diff --git a/doc/next/6-stdlib/99-minor/io/fs/49580.md b/doc/next/6-stdlib/99-minor/io/fs/49580.md deleted file mode 100644 index c1cba5a395..0000000000 --- a/doc/next/6-stdlib/99-minor/io/fs/49580.md +++ /dev/null @@ -1 +0,0 @@ -A new [ReadLinkFS] interface provides the ability to read symbolic links in a filesystem. diff --git a/doc/next/6-stdlib/99-minor/log/slog/66365.md b/doc/next/6-stdlib/99-minor/log/slog/66365.md deleted file mode 100644 index b6b0c81fe5..0000000000 --- a/doc/next/6-stdlib/99-minor/log/slog/66365.md +++ /dev/null @@ -1 +0,0 @@ -[GroupAttrs] creates a group [Attr] from a slice of [Attr] values. diff --git a/doc/next/6-stdlib/99-minor/log/slog/70280.md b/doc/next/6-stdlib/99-minor/log/slog/70280.md deleted file mode 100644 index 7f1b734d4f..0000000000 --- a/doc/next/6-stdlib/99-minor/log/slog/70280.md +++ /dev/null @@ -1 +0,0 @@ -[Record] now has a Source() method, returning its source location or nil if unavailable. diff --git a/doc/next/6-stdlib/99-minor/mime/multipart/46771.md b/doc/next/6-stdlib/99-minor/mime/multipart/46771.md deleted file mode 100644 index b8b8641b78..0000000000 --- a/doc/next/6-stdlib/99-minor/mime/multipart/46771.md +++ /dev/null @@ -1,2 +0,0 @@ -The new helper function [FieldContentDisposition] builds multipart -Content-Disposition header fields. \ No newline at end of file diff --git a/doc/next/6-stdlib/99-minor/net/10350.md b/doc/next/6-stdlib/99-minor/net/10350.md deleted file mode 100644 index 7290112f41..0000000000 --- a/doc/next/6-stdlib/99-minor/net/10350.md +++ /dev/null @@ -1,3 +0,0 @@ -On Windows, the [TCPConn.File], [UDPConn.File], [UnixConn.File], -[IPConn.File], [TCPListener.File], and [UnixListener.File] -methods are now supported. \ No newline at end of file diff --git a/doc/next/6-stdlib/99-minor/net/56025.md b/doc/next/6-stdlib/99-minor/net/56025.md deleted file mode 100644 index 2e3b230ef0..0000000000 --- a/doc/next/6-stdlib/99-minor/net/56025.md +++ /dev/null @@ -1,5 +0,0 @@ -[LookupMX] and [*Resolver.LookupMX] now return DNS names that look -like valid IP address, as well as valid domain names. -Previously if a name server returned an IP address as a DNS name, -LookupMX would discard it, as required by the RFCs. -However, name servers in practice do sometimes return IP addresses. diff --git a/doc/next/6-stdlib/99-minor/net/63529.md b/doc/next/6-stdlib/99-minor/net/63529.md deleted file mode 100644 index 4cf05c90cd..0000000000 --- a/doc/next/6-stdlib/99-minor/net/63529.md +++ /dev/null @@ -1 +0,0 @@ -On Windows, the [ListenMulticastUDP] now supports IPv6 addresses. diff --git a/doc/next/6-stdlib/99-minor/net/9503.md b/doc/next/6-stdlib/99-minor/net/9503.md deleted file mode 100644 index d2aef10132..0000000000 --- a/doc/next/6-stdlib/99-minor/net/9503.md +++ /dev/null @@ -1,2 +0,0 @@ -On Windows, the [FileConn], [FilePacketConn], [FileListener] -functions are now supported. diff --git a/doc/next/6-stdlib/99-minor/net/http/73626.md b/doc/next/6-stdlib/99-minor/net/http/73626.md deleted file mode 100644 index 88a204b8a4..0000000000 --- a/doc/next/6-stdlib/99-minor/net/http/73626.md +++ /dev/null @@ -1,7 +0,0 @@ -The new [CrossOriginProtection] implements protections against [Cross-Site -Request Forgery (CSRF)][] by rejecting non-safe cross-origin browser requests. -It uses [modern browser Fetch metadata][Sec-Fetch-Site], doesn't require tokens -or cookies, and supports origin-based and pattern-based bypasses. - -[Sec-Fetch-Site]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Site -[Cross-Site Request Forgery (CSRF)]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF diff --git a/doc/next/6-stdlib/99-minor/os/15388.md b/doc/next/6-stdlib/99-minor/os/15388.md deleted file mode 100644 index 04b3e91d8b..0000000000 --- a/doc/next/6-stdlib/99-minor/os/15388.md +++ /dev/null @@ -1,14 +0,0 @@ -On Windows, [NewFile] now supports handles opened for asynchronous I/O (that is, -[syscall.FILE_FLAG_OVERLAPPED] is specified in the [syscall.CreateFile] call). -These handles are associated with the Go runtime's I/O completion port, -which provides the following benefits for the resulting [File]: - -- I/O methods ([File.Read], [File.Write], [File.ReadAt], and [File.WriteAt]) do not block an OS thread. -- Deadline methods ([File.SetDeadline], [File.SetReadDeadline], and [File.SetWriteDeadline]) are supported. - -This enhancement is especially beneficial for applications that communicate via named pipes on Windows. - -Note that a handle can only be associated with one completion port at a time. -If the handle provided to [NewFile] is already associated with a completion port, -the returned [File] is downgraded to synchronous I/O mode. -In this case, I/O methods will block an OS thread, and the deadline methods have no effect. diff --git a/doc/next/6-stdlib/99-minor/os/49580.md b/doc/next/6-stdlib/99-minor/os/49580.md deleted file mode 100644 index 18d8831e7b..0000000000 --- a/doc/next/6-stdlib/99-minor/os/49580.md +++ /dev/null @@ -1,2 +0,0 @@ -The filesystem returned by [DirFS] implements the new [io/fs.ReadLinkFS] interface. -[CopyFS] supports symlinks when copying filesystems that implement [io/fs.ReadLinkFS]. diff --git a/doc/next/6-stdlib/99-minor/os/67002.md b/doc/next/6-stdlib/99-minor/os/67002.md deleted file mode 100644 index 481a2c171c..0000000000 --- a/doc/next/6-stdlib/99-minor/os/67002.md +++ /dev/null @@ -1,14 +0,0 @@ -The [os.Root] type supports the following additional methods: - - * [os.Root.Chmod] - * [os.Root.Chown] - * [os.Root.Chtimes] - * [os.Root.Lchown] - * [os.Root.Link] - * [os.Root.MkdirAll] - * [os.Root.ReadFile] - * [os.Root.Readlink] - * [os.Root.RemoveAll] - * [os.Root.Rename] - * [os.Root.Symlink] - * [os.Root.WriteFile] diff --git a/doc/next/6-stdlib/99-minor/os/73126.md b/doc/next/6-stdlib/99-minor/os/73126.md deleted file mode 100644 index 1cd40d79ee..0000000000 --- a/doc/next/6-stdlib/99-minor/os/73126.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/next/6-stdlib/99-minor/reflect/62121.md b/doc/next/6-stdlib/99-minor/reflect/62121.md deleted file mode 100644 index f6148ceb60..0000000000 --- a/doc/next/6-stdlib/99-minor/reflect/62121.md +++ /dev/null @@ -1,3 +0,0 @@ -The new [TypeAssert] function permits converting a [Value] directly to a Go value -of the given type. This is like using a type assertion on the result of [Value.Interface], -but avoids unnecessary memory allocations. diff --git a/doc/next/6-stdlib/99-minor/regexp/syntax/70781.md b/doc/next/6-stdlib/99-minor/regexp/syntax/70781.md deleted file mode 100644 index 63794b4671..0000000000 --- a/doc/next/6-stdlib/99-minor/regexp/syntax/70781.md +++ /dev/null @@ -1,4 +0,0 @@ -The `\p{name}` and `\P{name}` character class syntaxes now accept the names -Any, ASCII, Assigned, Cn, and LC, as well as Unicode category aliases like `\p{Letter}` for `\pL`. -Following [Unicode TR18](https://unicode.org/reports/tr18/), they also now use -case-insensitive name lookups, ignoring spaces, underscores, and hyphens. diff --git a/doc/next/6-stdlib/99-minor/runtime/71825.md b/doc/next/6-stdlib/99-minor/runtime/71825.md deleted file mode 100644 index 156d244643..0000000000 --- a/doc/next/6-stdlib/99-minor/runtime/71825.md +++ /dev/null @@ -1,5 +0,0 @@ -Cleanup functions scheduled by [AddCleanup] are now executed -concurrently and in parallel, making cleanups more viable for heavy -use like the [unique] package. Note that individual cleanups should -still shunt their work to a new goroutine if they must execute or -block for a long time to avoid blocking the cleanup queue. diff --git a/doc/next/6-stdlib/99-minor/runtime/72949.md b/doc/next/6-stdlib/99-minor/runtime/72949.md deleted file mode 100644 index 6bab38d94c..0000000000 --- a/doc/next/6-stdlib/99-minor/runtime/72949.md +++ /dev/null @@ -1,8 +0,0 @@ -When `GODEBUG=checkfinalizers=1` is set, the runtime will run -diagnostics on each garbage collection cycle to find common issues -with how the program might use finalizers and cleanups, such as those -described [in the GC -guide](/doc/gc-guide#Finalizers_cleanups_and_weak_pointers). In this -mode, the runtime will also regularly report the finalizer and -cleanup queue lengths to stderr to help identify issues with -long-running finalizers and/or cleanups. diff --git a/doc/next/6-stdlib/99-minor/runtime/73193.md b/doc/next/6-stdlib/99-minor/runtime/73193.md deleted file mode 100644 index a729f6a3c4..0000000000 --- a/doc/next/6-stdlib/99-minor/runtime/73193.md +++ /dev/null @@ -1,5 +0,0 @@ -The new [SetDefaultGOMAXPROCS] function sets `GOMAXPROCS` to the runtime -default value, as if the `GOMAXPROCS` environment variable is not set. This is -useful for enabling the [new `GOMAXPROCS` default](#runtime) if it has been -disabled by the `GOMAXPROCS` environment variable or a prior call to -[GOMAXPROCS]. diff --git a/doc/next/6-stdlib/99-minor/runtime/pprof/66999.md b/doc/next/6-stdlib/99-minor/runtime/pprof/66999.md deleted file mode 100644 index f222628aae..0000000000 --- a/doc/next/6-stdlib/99-minor/runtime/pprof/66999.md +++ /dev/null @@ -1,6 +0,0 @@ -The mutex profile for contention on runtime-internal locks now correctly points -to the end of the critical section that caused the delay. This matches the -profile's behavior for contention on `sync.Mutex` values. The -`runtimecontentionstacks` setting for `GODEBUG`, which allowed opting in to the -unusual behavior of Go 1.22 through 1.24 for this part of the profile, is now -gone. diff --git a/doc/next/6-stdlib/99-minor/runtime/trace/63185.md b/doc/next/6-stdlib/99-minor/runtime/trace/63185.md deleted file mode 100644 index 80ba088b75..0000000000 --- a/doc/next/6-stdlib/99-minor/runtime/trace/63185.md +++ /dev/null @@ -1,2 +0,0 @@ - -TODO The flight recorder has been added to the runtime/trace package. diff --git a/doc/next/6-stdlib/99-minor/sync/63796.md b/doc/next/6-stdlib/99-minor/sync/63796.md deleted file mode 100644 index 60d91a949a..0000000000 --- a/doc/next/6-stdlib/99-minor/sync/63796.md +++ /dev/null @@ -1,2 +0,0 @@ -[WaitGroup] has added a new method [WaitGroup.Go], -that makes the common pattern of creating and counting goroutines more convenient. diff --git a/doc/next/6-stdlib/99-minor/testing/43936.md b/doc/next/6-stdlib/99-minor/testing/43936.md deleted file mode 100644 index 5be98d5db8..0000000000 --- a/doc/next/6-stdlib/99-minor/testing/43936.md +++ /dev/null @@ -1,10 +0,0 @@ -The new methods [T.Attr], [B.Attr], and [F.Attr] emit an -attribute to the test log. An attribute is an arbitrary -key and value associated with a test. - -For example, in a test named `TestAttr`, -`t.Attr("key", "value")` emits: - -``` -=== ATTR TestAttr key value -``` diff --git a/doc/next/6-stdlib/99-minor/testing/59928.md b/doc/next/6-stdlib/99-minor/testing/59928.md deleted file mode 100644 index 6879a10d63..0000000000 --- a/doc/next/6-stdlib/99-minor/testing/59928.md +++ /dev/null @@ -1,4 +0,0 @@ - - -The new [Output] method of [testing.T], [testing.B] and [testing.F] provides a Writer -that writes to the same test output stream as [TB.Log], but omits the file and line number. diff --git a/doc/next/6-stdlib/99-minor/testing/fstest/49580.md b/doc/next/6-stdlib/99-minor/testing/fstest/49580.md deleted file mode 100644 index 5b3c0d6a84..0000000000 --- a/doc/next/6-stdlib/99-minor/testing/fstest/49580.md +++ /dev/null @@ -1,3 +0,0 @@ -[MapFS] implements the new [io/fs.ReadLinkFS] interface. -[TestFS] will verify the functionality of the [io/fs.ReadLinkFS] interface if implemented. -[TestFS] will no longer follow symlinks to avoid unbounded recursion. diff --git a/doc/next/6-stdlib/99-minor/testing/synctest/67434.md b/doc/next/6-stdlib/99-minor/testing/synctest/67434.md deleted file mode 100644 index d36a55111c..0000000000 --- a/doc/next/6-stdlib/99-minor/testing/synctest/67434.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/next/6-stdlib/99-minor/unicode/70780.md b/doc/next/6-stdlib/99-minor/unicode/70780.md deleted file mode 100644 index d799ca0c35..0000000000 --- a/doc/next/6-stdlib/99-minor/unicode/70780.md +++ /dev/null @@ -1,4 +0,0 @@ -The new [CategoryAliases] map provides access to category alias names, such as “Letter” for “L”. -The new categories [Cn] and [LC] define unassigned codepoints and cased letters, respectively. -These have always been defined by Unicode but were inadvertently omitted in earlier versions of Go. -The [C] category now includes [Cn], meaning it has added all unassigned code points. diff --git a/doc/next/6-stdlib/99-minor/unique/71772.md b/doc/next/6-stdlib/99-minor/unique/71772.md deleted file mode 100644 index 5b789446ae..0000000000 --- a/doc/next/6-stdlib/99-minor/unique/71772.md +++ /dev/null @@ -1,4 +0,0 @@ -The [unique] package now reclaims interned values more eagerly, -more efficiently, and in parallel. As a consequence, applications using -[Make] are now less likely to experience memory blow-up when lots of -truly unique values are interned. diff --git a/doc/next/6-stdlib/99-minor/unique/71846.md b/doc/next/6-stdlib/99-minor/unique/71846.md deleted file mode 100644 index b1f86f0739..0000000000 --- a/doc/next/6-stdlib/99-minor/unique/71846.md +++ /dev/null @@ -1,4 +0,0 @@ -Values passed to [Make] containing [Handle]s previously required multiple -garbage collection cycles to collect, proportional to the depth of the chain -of [Handle] values. Now, they are collected promptly in a single cycle, once -unused. diff --git a/doc/next/7-ports.md b/doc/next/7-ports.md deleted file mode 100644 index eb4f0d5a97..0000000000 --- a/doc/next/7-ports.md +++ /dev/null @@ -1,11 +0,0 @@ -## Ports {#ports} - -### Darwin - - -As [announced](/doc/go1.24#darwin) in the Go 1.24 release notes, Go 1.25 requires macOS 12 Monterey or later; support for previous versions has been discontinued. - -### Windows - - -Go 1.25 is the last release that contains the [broken](/doc/go1.24#windows) 32-bit windows/arm port (`GOOS=windows` `GOARCH=arm`). It will be removed in Go 1.26. diff --git a/doc/next/9-todo.md b/doc/next/9-todo.md deleted file mode 100644 index fa1c71084f..0000000000 --- a/doc/next/9-todo.md +++ /dev/null @@ -1,206 +0,0 @@ - - -### TODO - -**Please turn these into proper release notes** - - -all: implement plugin build mode for riscv64 - - -cmd/link/internal/ld: introduce -funcalign=N option -This patch adds linker option -funcalign=N that allows to set alignment -for function entries. -For \#72130. - - -cmd/fix: automate migrations for simple deprecations - - -cmd/go: allow serving module under the subdirectory of git repository -cmd/go: add subdirectory support to go-import meta tag -This CL adds ability to specify a subdirectory in the go-import meta tag. -A go-import meta tag now will support: -\ -Fixes: \#34055 - - -cmd/go: add global ignore mechanism for Go tooling ecosystem - - -cmd/cover: extend coverage testing to include applications - - -all: add GOARM64=v8.1 and so on -runtime: check LSE support on ARM64 at runtime init -Check presence of LSE support on ARM64 chip if we targeted it at compile -time. -Related to \#69124 -Updates \#60905 -Fixes \#71411 - - -all: add GORISCV64 environment variable -cmd/go: add rva23u64 as a valid value for GORISCV64 -The RVA23 profile was ratified on the 21st of October 2024. -https://riscv.org/announcements/2024/10/risc-v-announces-ratification-of-the-rva23-profile-standard/ -Now that it's ratified we can add rva23u64 as a valid value for the -GORISCV64 environment variable. This will allow the compiler and -assembler to generate instructions made mandatory by the new profile -without a runtime check. Examples of such instructions include those -introduced by the Vector and Zicond extensions. -Setting GORISCV64=rva23u64 defines the riscv64.rva20u64, -riscv64.rva22u64 and riscv64.rva23u64 build tags, sets the internal -variable buildcfg.GORISCV64 to 23 and defines the macros -GORISCV64_rva23u64, hasV, hasZba, hasZbb, hasZbs, hasZfa, and -hasZicond for use in assembly language code. -Updates \#61476 - - -math/rand/v2: revised API for math/rand -rand: deprecate in favor of math/rand/v2 -For golang/go#61716 -Fixes golang/go#71373 - - -cmd/go: enable GOCACHEPROG by default -cmd/go/internal/cacheprog: drop Request.ObjectID -ObjectID was a misnaming of OutputID from cacheprog's initial -implementation. It was maintained for compatibility with existing -cacheprog users in 1.24 but can be removed in 1.25. - - -cmd/go: doc -http should start a pkgsite instance and open a browser - - -cmd/go: -json flag for go version -m -cmd/go: support -json flag in go version -It supports features described in the issue: -- add -json flag for 'go version -m' to print json encoding of - runtime/debug.BuildSetting to standard output. -- report an error when specifying -json flag without -m. -- print build settings on seperated line for each binary -Fixes \#69712 - - -crypto: mechanism to enable FIPS mode - - -spec: remove notion of core types - - -cmd/go: add fips140 module selection mechanism -lib/fips140: set inprocess.txt to v1.0.0 - - -testing: panic in AllocsPerRun during parallel test -testing: panic in AllocsPerRun if parallel tests are running -If other tests are running, AllocsPerRun's result will be inherently flaky. -Saw this with CL 630136 and \#70327. -Proposed in \#70464. -Fixes \#70464. - - -encoding/json/v2: add new JSON API behind a GOEXPERIMENT=jsonv2 guard - - -cmd/go, cmd/distpack: build and run tools that are not necessary for builds as needed and don't include in binary distribution - - diff --git a/lib/time/update.bash b/lib/time/update.bash index 940596fb11..66494752ea 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -24,8 +24,8 @@ # in the CL match the update.bash in the CL. # Versions to use. -CODE=2025a -DATA=2025a +CODE=2025b +DATA=2025b set -e diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index f8099b1b49..b107695d1e 100644 Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ diff --git a/src/cmd/compile/default.pgo b/src/cmd/compile/default.pgo index 65c28706ea..2c2588704f 100644 Binary files a/src/cmd/compile/default.pgo and b/src/cmd/compile/default.pgo differ diff --git a/src/cmd/compile/internal/noder/doc.go b/src/cmd/compile/internal/noder/doc.go index f76e5723b7..baf7c67463 100644 --- a/src/cmd/compile/internal/noder/doc.go +++ b/src/cmd/compile/internal/noder/doc.go @@ -39,8 +39,7 @@ kind. Go constructs are mapped onto (potentially multiple) elements. Elements are accessed using an index relative to the start of the section. - // TODO(markfreeman): Rename to SectionIndex. - RelIndex = Uint64 . + RelElemIdx = Uint64 . ## String Section String values are stored as elements in the string section. Elements @@ -147,7 +146,7 @@ referenced element. . RefTableEntry = [ Sync ] SectionKind - RelIndex + RelElemIdx . Elements encode references to other elements as an index in the @@ -155,7 +154,7 @@ reference table — not the location of the referenced element directly. // TODO(markfreeman): Rename to RefUse. UseReloc = [ Sync ] - RelIndex + RelElemIdx . # Primitives diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index a8ec2a278c..0f17843565 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -897,8 +897,8 @@ func init() { inputs: []regMask{buildReg("DI")}, clobbers: buildReg("DI"), }, - faultOnNilArg0: true, - unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts + //faultOnNilArg0: true, // Note: removed for 73748. TODO: reenable at some point + unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts }, // arg0 = address of memory to zero @@ -935,10 +935,10 @@ func init() { inputs: []regMask{buildReg("DI"), buildReg("SI")}, clobbers: buildReg("DI SI X0"), // uses X0 as a temporary }, - clobberFlags: true, - faultOnNilArg0: true, - faultOnNilArg1: true, - unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts + clobberFlags: true, + //faultOnNilArg0: true, // Note: removed for 73748. TODO: reenable at some point + //faultOnNilArg1: true, + unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts }, // arg0 = destination pointer diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go index 8ebbd7e95e..ebb7ed5299 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go @@ -554,8 +554,8 @@ func init() { inputs: []regMask{buildReg("R20")}, clobbers: buildReg("R16 R17 R20 R30"), }, - faultOnNilArg0: true, - unsafePoint: true, // FP maintenance around DUFFZERO can be clobbered by interrupts + //faultOnNilArg0: true, // Note: removed for 73748. TODO: reenable at some point + unsafePoint: true, // FP maintenance around DUFFZERO can be clobbered by interrupts }, // large zeroing @@ -595,9 +595,9 @@ func init() { inputs: []regMask{buildReg("R21"), buildReg("R20")}, clobbers: buildReg("R16 R17 R20 R21 R26 R30"), }, - faultOnNilArg0: true, - faultOnNilArg1: true, - unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts + //faultOnNilArg0: true, // Note: removed for 73748. TODO: reenable at some point + //faultOnNilArg1: true, + unsafePoint: true, // FP maintenance around DUFFCOPY can be clobbered by interrupts }, // large move diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 90a38c783a..5d13f81841 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -13874,11 +13874,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFZERO", - auxType: auxInt64, - argLen: 2, - faultOnNilArg0: true, - unsafePoint: true, + name: "DUFFZERO", + auxType: auxInt64, + argLen: 2, + unsafePoint: true, reg: regInfo{ inputs: []inputInfo{ {0, 128}, // DI @@ -13948,13 +13947,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFCOPY", - auxType: auxInt64, - argLen: 3, - clobberFlags: true, - faultOnNilArg0: true, - faultOnNilArg1: true, - unsafePoint: true, + name: "DUFFCOPY", + auxType: auxInt64, + argLen: 3, + clobberFlags: true, + unsafePoint: true, reg: regInfo{ inputs: []inputInfo{ {0, 128}, // DI @@ -23039,11 +23036,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFZERO", - auxType: auxInt64, - argLen: 2, - faultOnNilArg0: true, - unsafePoint: true, + name: "DUFFZERO", + auxType: auxInt64, + argLen: 2, + unsafePoint: true, reg: regInfo{ inputs: []inputInfo{ {0, 524288}, // R20 @@ -23065,12 +23061,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFCOPY", - auxType: auxInt64, - argLen: 3, - faultOnNilArg0: true, - faultOnNilArg1: true, - unsafePoint: true, + name: "DUFFCOPY", + auxType: auxInt64, + argLen: 3, + unsafePoint: true, reg: regInfo{ inputs: []inputInfo{ {0, 1048576}, // R21 diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index d262ab9f85..31a1aa2abe 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -11,6 +11,7 @@ import ( "fmt" "go/constant" . "internal/types/errors" + "os" "sync/atomic" ) @@ -419,7 +420,24 @@ func (check *Checker) handleBailout(err *error) { // normal return or early exit *err = check.firstErr default: - // TODO(markfreeman): dump posStack if available + if len(check.posStack) > 0 { + doPrint := func(ps []syntax.Pos) { + for i := len(ps) - 1; i >= 0; i-- { + fmt.Fprintf(os.Stderr, "\t%v\n", ps[i]) + } + } + + fmt.Fprintln(os.Stderr, "The following panic happened checking types near:") + if len(check.posStack) <= 10 { + doPrint(check.posStack) + } else { + // if it's long, truncate the middle; it's least likely to help + doPrint(check.posStack[len(check.posStack)-5:]) + fmt.Fprintln(os.Stderr, "\t...") + doPrint(check.posStack[:5]) + } + } + // re-panic panic(p) } diff --git a/src/cmd/distpack/pack.go b/src/cmd/distpack/pack.go index 8e0b58af21..4f14210e5f 100644 --- a/src/cmd/distpack/pack.go +++ b/src/cmd/distpack/pack.go @@ -171,7 +171,7 @@ func main() { switch strings.TrimSuffix(path.Base(name), ".exe") { default: return false - case "asm", "cgo", "compile", "cover", "link", "pack", "preprofile", "vet": + case "asm", "cgo", "compile", "cover", "link", "preprofile", "vet": } } return true diff --git a/src/cmd/distpack/test.go b/src/cmd/distpack/test.go index 4f260cb0df..7479bd77f5 100644 --- a/src/cmd/distpack/test.go +++ b/src/cmd/distpack/test.go @@ -66,6 +66,8 @@ var zipRules = []testRule{ {name: "go/pkg/tool/*/compile", goos: "darwin"}, {name: "go/pkg/tool/*/compile", goos: "windows", exclude: true}, {name: "go/pkg/tool/*/compile.exe", goos: "windows"}, + {name: "go/pkg/tool/*/pack", exclude: true}, + {name: "go/pkg/tool/*/pack.exe", exclude: true}, } var modRules = []testRule{ @@ -100,6 +102,8 @@ var modRules = []testRule{ {name: "golang.org/toolchain@*/pkg/tool/*/compile", goos: "darwin"}, {name: "golang.org/toolchain@*/pkg/tool/*/compile", goos: "windows", exclude: true}, {name: "golang.org/toolchain@*/pkg/tool/*/compile.exe", goos: "windows"}, + {name: "golang.org/toolchain@*/pkg/tool/*/pack", exclude: true}, + {name: "golang.org/toolchain@*/pkg/tool/*/pack.exe", exclude: true}, // go.mod are renamed to _go.mod. {name: "**/go.mod", exclude: true}, diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 70d22580a3..39a1f5f74c 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -482,7 +482,7 @@ func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) er p := a.Package sh := b.Shell(a) if cfg.BuildN || cfg.BuildX { - cmdline := str.StringList(base.Tool("pack"), "r", absAfile, absOfiles) + cmdline := str.StringList("go", "tool", "pack", "r", absAfile, absOfiles) sh.ShowCmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) } if cfg.BuildN { diff --git a/src/cmd/internal/obj/s390x/condition_code.go b/src/cmd/internal/obj/s390x/condition_code.go index f498fd6f77..3330d1310d 100644 --- a/src/cmd/internal/obj/s390x/condition_code.go +++ b/src/cmd/internal/obj/s390x/condition_code.go @@ -122,7 +122,7 @@ func (c CCMask) String() string { } // invalid - return fmt.Sprintf("Invalid (%#x)", c) + return fmt.Sprintf("Invalid (%#x)", uint8(c)) } func (CCMask) CanBeAnSSAAux() {} diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 128173b8cf..6561362210 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -452,33 +452,50 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in if oldsym.Dupok() { return oldi } - // If one is a DATA symbol (i.e. has content, DataSize != 0) - // and the other is BSS, the one with content wins. + // If one is a DATA symbol (i.e. has content, DataSize != 0, + // including RODATA) and the other is BSS, the one with content wins. // If both are BSS, the one with larger size wins. - // Specifically, the "overwrite" variable and the final result are // - // new sym old sym overwrite + // For a special case, we allow a TEXT symbol overwrites a BSS symbol + // even if the BSS symbol has larger size. This is because there is + // code like below to take the address of a function + // + // //go:linkname fn + // var fn uintptr + // var fnAddr = uintptr(unsafe.Pointer(&fn)) + // + // TODO: maybe limit this case to just pointer sized variable? + // + // In summary, the "overwrite" variable and the final result are + // + // new sym old sym result // --------------------------------------------- - // DATA DATA true => ERROR - // DATA lg/eq BSS sm/eq true => new wins - // DATA small BSS large true => ERROR - // BSS large DATA small true => ERROR - // BSS large BSS small true => new wins - // BSS sm/eq D/B lg/eq false => old wins - overwrite := r.DataSize(li) != 0 || oldsz < sz - if overwrite { + // TEXT BSS new wins + // DATA DATA ERROR + // DATA lg/eq BSS sm/eq new wins + // DATA small BSS large ERROR + // BSS large DATA small ERROR + // BSS large BSS small new wins + // BSS sm/eq D/B lg/eq old wins + // BSS TEXT old wins + oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] + newtyp := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())] + oldIsText := oldtyp.IsText() + newIsText := newtyp.IsText() + oldHasContent := oldr.DataSize(oldli) != 0 + newHasContent := r.DataSize(li) != 0 + oldIsBSS := oldtyp.IsData() && !oldHasContent + newIsBSS := newtyp.IsData() && !newHasContent + switch { + case newIsText && oldIsBSS, + newHasContent && oldIsBSS && sz >= oldsz, + newIsBSS && oldIsBSS && sz > oldsz: // new symbol overwrites old symbol. - oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] - if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) || oldsz > sz { - log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg) - } l.objSyms[oldi] = objSym{r.objidx, li} - } else { - // old symbol overwrites new symbol. - typ := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())] - if !typ.IsData() { // only allow overwriting data symbol - log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg) - } + case newIsBSS && (oldsz >= sz || oldIsText): + // old win, just ignore the new symbol. + default: + log.Fatalf("duplicated definition of symbol %s, from %s (type %s size %d) and %s (type %s size %d)", name, r.unit.Lib.Pkg, newtyp, sz, oldr.unit.Lib.Pkg, oldtyp, oldsz) } return oldi } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 7c3ca427ed..2fe32600f1 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -1601,6 +1601,9 @@ func TestCheckLinkname(t *testing.T) { {"ok.go", true}, // push linkname is ok {"push.go", true}, + // using a linknamed variable to reference an assembly + // function in the same package is ok + {"textvar", true}, // pull linkname of blocked symbol is not ok {"coro.go", false}, {"coro_var.go", false}, @@ -1618,7 +1621,7 @@ func TestCheckLinkname(t *testing.T) { test := test t.Run(test.src, func(t *testing.T) { t.Parallel() - src := filepath.Join("testdata", "linkname", test.src) + src := "./testdata/linkname/" + test.src exe := filepath.Join(tmpdir, test.src+".exe") cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src) out, err := cmd.CombinedOutput() diff --git a/src/cmd/link/testdata/linkname/textvar/asm.s b/src/cmd/link/testdata/linkname/textvar/asm.s new file mode 100644 index 0000000000..332dcdb4e7 --- /dev/null +++ b/src/cmd/link/testdata/linkname/textvar/asm.s @@ -0,0 +1,6 @@ +// 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. + +TEXT ·asmfunc(SB),0,$0-0 + RET diff --git a/src/cmd/link/testdata/linkname/textvar/main.go b/src/cmd/link/testdata/linkname/textvar/main.go new file mode 100644 index 0000000000..b38995e706 --- /dev/null +++ b/src/cmd/link/testdata/linkname/textvar/main.go @@ -0,0 +1,17 @@ +// 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. + +// Using a linknamed variable to reference an assembly +// function in the same package is ok. + +package main + +import _ "unsafe" + +func main() { + println(&asmfunc) +} + +//go:linkname asmfunc +var asmfunc uintptr diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index b2668a3d7d..6d92542e31 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -103,6 +103,7 @@ var depsRules = ` < sync/atomic < internal/sync < weak + < internal/synctest < sync < internal/bisect < internal/godebug @@ -136,9 +137,6 @@ var depsRules = ` unicode !< path; - RUNTIME - < internal/synctest; - # SYSCALL is RUNTIME plus the packages necessary for basic system calls. RUNTIME, unicode/utf8, unicode/utf16, internal/synctest < internal/syscall/windows/sysdll, syscall/js diff --git a/src/go/doc/doc.go b/src/go/doc/doc.go index 4d01ae458b..f7e3c1bad8 100644 --- a/src/go/doc/doc.go +++ b/src/go/doc/doc.go @@ -188,6 +188,7 @@ func (p *Package) collectFuncs(funcs []*Func) { // // The package is specified by a list of *ast.Files and corresponding // file set, which must not be nil. +// // NewFromFiles uses all provided files when computing documentation, // so it is the caller's responsibility to provide only the files that // match the desired build context. "go/build".Context.MatchFile can @@ -226,49 +227,38 @@ func NewFromFiles(fset *token.FileSet, files []*ast.File, importPath string, opt // Collect .go and _test.go files. var ( + pkgName string goFiles = make(map[string]*ast.File) testGoFiles []*ast.File ) - for i := range files { - f := fset.File(files[i].Pos()) + for i, file := range files { + f := fset.File(file.Pos()) if f == nil { return nil, fmt.Errorf("file files[%d] is not found in the provided file set", i) } - switch name := f.Name(); { - case strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go"): - goFiles[name] = files[i] - case strings.HasSuffix(name, "_test.go"): - testGoFiles = append(testGoFiles, files[i]) + switch filename := f.Name(); { + case strings.HasSuffix(filename, "_test.go"): + testGoFiles = append(testGoFiles, file) + case strings.HasSuffix(filename, ".go"): + pkgName = file.Name.Name + goFiles[filename] = file default: - return nil, fmt.Errorf("file files[%d] filename %q does not have a .go extension", i, name) + return nil, fmt.Errorf("file files[%d] filename %q does not have a .go extension", i, filename) } } - // TODO(dmitshur,gri): A relatively high level call to ast.NewPackage with a simpleImporter - // ast.Importer implementation is made below. It might be possible to short-circuit and simplify. - // Compute package documentation. - pkg, _ := ast.NewPackage(fset, goFiles, simpleImporter, nil) // Ignore errors that can happen due to unresolved identifiers. + // + // Since this package doesn't need Package.{Scope,Imports}, or + // handle errors, and ast.File's Scope field is unset in files + // parsed with parser.SkipObjectResolution, we construct the + // Package directly instead of calling [ast.NewPackage]. + pkg := &ast.Package{Name: pkgName, Files: goFiles} p := New(pkg, importPath, mode) classifyExamples(p, Examples(testGoFiles...)) return p, nil } -// simpleImporter returns a (dummy) package object named by the last path -// component of the provided package path (as is the convention for packages). -// This is sufficient to resolve package identifiers without doing an actual -// import. It never returns an error. -func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) { - pkg := imports[path] - if pkg == nil { - // note that strings.LastIndex returns -1 if there is no "/" - pkg = ast.NewObj(ast.Pkg, path[strings.LastIndex(path, "/")+1:]) - pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import - imports[path] = pkg - } - return pkg, nil -} - // lookupSym reports whether the package has a given symbol or method. // // If recv == "", HasSym reports whether the package has a top-level diff --git a/src/go/doc/example_test.go b/src/go/doc/example_test.go index 7919c3a2c0..2fd54f8abb 100644 --- a/src/go/doc/example_test.go +++ b/src/go/doc/example_test.go @@ -328,7 +328,7 @@ func exampleNames(exs []*doc.Example) (out []string) { } func mustParse(fset *token.FileSet, filename, src string) *ast.File { - f, err := parser.ParseFile(fset, filename, src, parser.ParseComments) + f, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.SkipObjectResolution) if err != nil { panic(err) } diff --git a/src/go/types/check.go b/src/go/types/check.go index 77bff811b9..e4e8e95c99 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -13,6 +13,7 @@ import ( "go/token" "internal/godebug" . "internal/types/errors" + "os" "sync/atomic" ) @@ -444,7 +445,24 @@ func (check *Checker) handleBailout(err *error) { // normal return or early exit *err = check.firstErr default: - // TODO(markfreeman): dump posStack if available + if len(check.posStack) > 0 { + doPrint := func(ps []positioner) { + for i := len(ps) - 1; i >= 0; i-- { + fmt.Fprintf(os.Stderr, "\t%v\n", check.fset.Position(ps[i].Pos())) + } + } + + fmt.Fprintln(os.Stderr, "The following panic happened checking types near:") + if len(check.posStack) <= 10 { + doPrint(check.posStack) + } else { + // if it's long, truncate the middle; it's least likely to help + doPrint(check.posStack[len(check.posStack)-5:]) + fmt.Fprintln(os.Stderr, "\t...") + doPrint(check.posStack[:5]) + } + } + // re-panic panic(p) } diff --git a/src/internal/pkgbits/reloc.go b/src/internal/pkgbits/reloc.go index 5f6ec2ab79..6074296d9e 100644 --- a/src/internal/pkgbits/reloc.go +++ b/src/internal/pkgbits/reloc.go @@ -37,7 +37,68 @@ type AbsElemIdx = uint32 // relative to some other index, such as the start of a section. type RelElemIdx = Index -// TODO(markfreeman): Isn't this strictly less efficient than an AbsElemIdx? +/* +All elements are preceded by a reference table. Reference tables provide an +additional indirection layer for element references. That is, for element A to +reference element B, A encodes the reference table index pointing to B, rather +than the table entry itself. + +# Functional Considerations +Reference table layout is important primarily to the UIR linker. After noding, +the UIR linker sees a UIR file for each package with imported objects +represented as stubs. In a simple sense, the job of the UIR linker is to merge +these "stubbed" UIR files into a single "linked" UIR file for the target package +with stubs replaced by object definitions. + +To do this, the UIR linker walks each stubbed UIR file and pulls in elements in +dependency order; that is, if A references B, then B must be placed into the +linked UIR file first. This depth-first traversal is done by recursing through +each element's reference table. + +When placing A in the linked UIR file, the reference table entry for B must be +updated, since B is unlikely to be at the same relative element index as it was +in the stubbed UIR file. + +Without reference tables, the UIR linker would need to read in the element to +discover its references. Note that the UIR linker cannot jump directly to the +reference locations after discovering merely the type of the element; +variable-width primitives prevent this. + +After updating the reference table, the rest of the element may be copied +directly into the linked UIR file. Note that the UIR linker may decide to read +in the element anyway (for unrelated reasons). + +In short, reference tables provide an efficient mechanism for traversing, +discovering, and updating element references during UIR linking. + +# Storage Considerations +Reference tables also have compactness benefits: + - If A refers to B multiple times, the entry is deduplicated and referred to + more compactly by the index. + - Relative (to a section) element indices are typically smaller than absolute + element indices, and thus fit into smaller varints. + - Most elements do not reference many elements; thus table size indicators and + table indices are typically a byte each. + +Thus, the storage performance is as follows: ++-----------------------------+-----------+--------------+ +| Scenario | Best Case | Typical Case | ++-----------------------------+-----------+--------------+ +| First reference from A to B | 3 Bytes | 4 Bytes | +| Other reference from A to B | 1 Byte | 1 Byte | ++-----------------------------+-----------+--------------+ + +The typical case for the first scenario changes because many sections have more +than 127 (range of a 1-byte uvarint) elements and thus the relative index is +typically 2 bytes, though this depends on the distribution of referenced indices +within the section. + +The second does not because most elements do not reference more than 127 +elements and the table index can thus keep to 1 byte. + +Typically, A will only reference B once, so most references are 4 bytes. +*/ + // A RefTableEntry is an entry in an element's reference table. All // elements are preceded by a reference table which provides locations // for referenced elements. diff --git a/src/internal/synctest/synctest.go b/src/internal/synctest/synctest.go index 19190d30f1..4d7fa3730c 100644 --- a/src/internal/synctest/synctest.go +++ b/src/internal/synctest/synctest.go @@ -8,7 +8,7 @@ package synctest import ( - _ "unsafe" // for go:linkname + "unsafe" ) //go:linkname Run @@ -17,6 +17,36 @@ func Run(f func()) //go:linkname Wait func Wait() +// IsInBubble reports whether the current goroutine is in a bubble. +// +//go:linkname IsInBubble +func IsInBubble() bool + +// Associate associates p with the current bubble. +// It returns false if p has an existing association with a different bubble. +func Associate[T any](p *T) (ok bool) { + return associate(unsafe.Pointer(p)) +} + +//go:linkname associate +func associate(p unsafe.Pointer) bool + +// Disassociate disassociates p from any bubble. +func Disassociate[T any](p *T) { + disassociate(unsafe.Pointer(p)) +} + +//go:linkname disassociate +func disassociate(b unsafe.Pointer) + +// IsAssociated reports whether p is associated with the current bubble. +func IsAssociated[T any](p *T) bool { + return isAssociated(unsafe.Pointer(p)) +} + +//go:linkname isAssociated +func isAssociated(p unsafe.Pointer) bool + //go:linkname acquire func acquire() any diff --git a/src/internal/synctest/synctest_test.go b/src/internal/synctest/synctest_test.go index 7f71df1710..2e1393591f 100644 --- a/src/internal/synctest/synctest_test.go +++ b/src/internal/synctest/synctest_test.go @@ -7,11 +7,14 @@ package synctest_test import ( "fmt" "internal/synctest" + "internal/testenv" "iter" + "os" "reflect" "runtime" "slices" "strconv" + "strings" "sync" "testing" "time" @@ -523,7 +526,7 @@ func TestReflectFuncOf(t *testing.T) { }) } -func TestWaitGroup(t *testing.T) { +func TestWaitGroupInBubble(t *testing.T) { synctest.Run(func() { var wg sync.WaitGroup wg.Add(1) @@ -540,6 +543,83 @@ func TestWaitGroup(t *testing.T) { }) } +func TestWaitGroupOutOfBubble(t *testing.T) { + var wg sync.WaitGroup + wg.Add(1) + donec := make(chan struct{}) + go synctest.Run(func() { + // Since wg.Add was called outside the bubble, Wait is not durably blocking + // and this waits until wg.Done is called below. + wg.Wait() + close(donec) + }) + select { + case <-donec: + t.Fatalf("synctest.Run finished before WaitGroup.Done called") + case <-time.After(1 * time.Millisecond): + } + wg.Done() + <-donec +} + +func TestWaitGroupMovedIntoBubble(t *testing.T) { + wantFatal(t, "fatal error: sync: WaitGroup.Add called from inside and outside synctest bubble", func() { + var wg sync.WaitGroup + wg.Add(1) + synctest.Run(func() { + wg.Add(1) + }) + }) +} + +func TestWaitGroupMovedOutOfBubble(t *testing.T) { + wantFatal(t, "fatal error: sync: WaitGroup.Add called from inside and outside synctest bubble", func() { + var wg sync.WaitGroup + synctest.Run(func() { + wg.Add(1) + }) + wg.Add(1) + }) +} + +func TestWaitGroupMovedBetweenBubblesWithNonZeroCount(t *testing.T) { + wantFatal(t, "fatal error: sync: WaitGroup.Add called from multiple synctest bubbles", func() { + var wg sync.WaitGroup + synctest.Run(func() { + wg.Add(1) + }) + synctest.Run(func() { + wg.Add(1) + }) + }) +} + +func TestWaitGroupMovedBetweenBubblesWithZeroCount(t *testing.T) { + var wg sync.WaitGroup + synctest.Run(func() { + wg.Add(1) + wg.Done() + }) + synctest.Run(func() { + // Reusing the WaitGroup is safe, because its count is zero. + wg.Add(1) + wg.Done() + }) +} + +func TestWaitGroupMovedBetweenBubblesAfterWait(t *testing.T) { + var wg sync.WaitGroup + synctest.Run(func() { + wg.Go(func() {}) + wg.Wait() + }) + synctest.Run(func() { + // Reusing the WaitGroup is safe, because its count is zero. + wg.Go(func() {}) + wg.Wait() + }) +} + func TestHappensBefore(t *testing.T) { // Use two parallel goroutines accessing different vars to ensure that // we correctly account for multiple goroutines in the bubble. @@ -630,7 +710,7 @@ func TestHappensBefore(t *testing.T) { // https://go.dev/issue/73817 func TestWeak(t *testing.T) { synctest.Run(func() { - for range 100 { + for range 5 { runtime.GC() b := make([]byte, 1024) weak.Make(&b) @@ -647,3 +727,23 @@ func wantPanic(t *testing.T, want string) { t.Errorf("got no panic, want one") } } + +func wantFatal(t *testing.T, want string, f func()) { + t.Helper() + + if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { + f() + return + } + + cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$") + cmd = testenv.CleanCmdEnv(cmd) + cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") + out, err := cmd.CombinedOutput() + if err == nil { + t.Errorf("expected test function to panic, but test returned successfully") + } + if !strings.Contains(string(out), want) { + t.Errorf("wanted test output contaiing %q; got %q", want, string(out)) + } +} diff --git a/src/internal/trace/export_reader_test.go b/src/internal/trace/export_reader_test.go new file mode 100644 index 0000000000..042c70864c --- /dev/null +++ b/src/internal/trace/export_reader_test.go @@ -0,0 +1,12 @@ +// Copyright 2025 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 trace + +import "internal/trace/version" + +// GoVersion is the version set in the trace header. +func (r *Reader) GoVersion() version.Version { + return r.version +} diff --git a/src/internal/trace/reader_test.go b/src/internal/trace/reader_test.go index 691cda6688..39ae77471e 100644 --- a/src/internal/trace/reader_test.go +++ b/src/internal/trace/reader_test.go @@ -11,6 +11,7 @@ import ( "io" "os" "path/filepath" + "runtime" "strings" "testing" "time" @@ -109,6 +110,10 @@ func testReader(t *testing.T, tr io.Reader, v *testtrace.Validator, exp *testtra if err == io.EOF { break } + v.GoVersion = r.GoVersion() + if runtime.GOOS == "windows" || runtime.GOARCH == "wasm" { + v.SkipClockSnapshotChecks() + } if err != nil { if err := exp.Check(err); err != nil { t.Error(err) diff --git a/src/os/root.go b/src/os/root.go index 953cd6b9b9..d759727ce7 100644 --- a/src/os/root.go +++ b/src/os/root.go @@ -352,8 +352,8 @@ func splitPathInRoot(s string, prefix, suffix []string) (_ []string, suffixSep s // FS returns a file system (an fs.FS) for the tree of files in the root. // -// The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and -// [io/fs.ReadDirFS]. +// The result implements [io/fs.StatFS], [io/fs.ReadFileFS], +// [io/fs.ReadDirFS], and [io/fs.ReadLinkFS]. func (r *Root) FS() fs.FS { return (*rootFS)(r) } @@ -409,6 +409,14 @@ func (rfs *rootFS) ReadFile(name string) ([]byte, error) { return readFileContents(statOrZero(f), f.Read) } +func (rfs *rootFS) ReadLink(name string) (string, error) { + r := (*Root)(rfs) + if !isValidRootFSPath(name) { + return "", &PathError{Op: "readlink", Path: name, Err: ErrInvalid} + } + return r.Readlink(name) +} + func (rfs *rootFS) Stat(name string) (FileInfo, error) { r := (*Root)(rfs) if !isValidRootFSPath(name) { @@ -417,6 +425,14 @@ func (rfs *rootFS) Stat(name string) (FileInfo, error) { return r.Stat(name) } +func (rfs *rootFS) Lstat(name string) (FileInfo, error) { + r := (*Root)(rfs) + if !isValidRootFSPath(name) { + return nil, &PathError{Op: "lstat", Path: name, Err: ErrInvalid} + } + return r.Lstat(name) +} + // isValidRootFSPath reports whether name is a valid filename to pass a Root.FS method. func isValidRootFSPath(name string) bool { if !fs.ValidPath(name) { diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 221a9a95cc..8696672065 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -1228,3 +1228,20 @@ func TestFinalizerOrCleanupDeadlock(t *testing.T) { }) } } + +func TestSynctestCondSignalFromNoBubble(t *testing.T) { + for _, test := range []string{ + "SynctestCond/signal/no_bubble", + "SynctestCond/broadcast/no_bubble", + "SynctestCond/signal/other_bubble", + "SynctestCond/broadcast/other_bubble", + } { + t.Run(test, func(t *testing.T) { + output := runTestProg(t, "testprog", test) + want := "fatal error: semaphore wake of synctest goroutine from outside bubble" + if !strings.Contains(output, want) { + t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want) + } + }) + } +} diff --git a/src/runtime/debug.go b/src/runtime/debug.go index 94d1dab34d..bdaaa7196d 100644 --- a/src/runtime/debug.go +++ b/src/runtime/debug.go @@ -39,10 +39,18 @@ func GOMAXPROCS(n int) int { lock(&sched.lock) ret := int(gomaxprocs) - unlock(&sched.lock) if n <= 0 || n == ret { + unlock(&sched.lock) return ret } + // Set early so we can wait for sysmon befor STW. See comment on + // computeMaxProcsLock. + sched.customGOMAXPROCS = true + unlock(&sched.lock) + + // Wait for sysmon to complete running defaultGOMAXPROCS. + lock(&computeMaxProcsLock) + unlock(&computeMaxProcsLock) stw := stopTheWorldGC(stwGOMAXPROCS) @@ -51,7 +59,6 @@ func GOMAXPROCS(n int) int { // TODO(prattmic): this could use a nicer API. Perhaps add it to the // stw parameter? newprocs = int32(n) - newprocsCustom = true startTheWorldGC(stw) return ret @@ -91,7 +98,9 @@ func SetDefaultGOMAXPROCS() { // TODO(prattmic): this could use a nicer API. Perhaps add it to the // stw parameter? newprocs = procs - newprocsCustom = false + lock(&sched.lock) + sched.customGOMAXPROCS = false + unlock(&sched.lock) startTheWorldGC(stw) } diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go index 7f32e6397b..44015ce862 100644 --- a/src/runtime/lockrank.go +++ b/src/runtime/lockrank.go @@ -14,7 +14,8 @@ const ( lockRankSysmon lockRankScavenge lockRankForcegc - lockRankUpdateGOMAXPROCS + lockRankComputeMaxProcs + lockRankUpdateMaxProcsG lockRankDefer lockRankSweepWaiters lockRankAssistQueue @@ -23,6 +24,7 @@ const ( lockRankSweep lockRankTestR lockRankTestW + lockRankVgetrandom lockRankTimerSend lockRankAllocmW lockRankExecW @@ -91,7 +93,8 @@ var lockNames = []string{ lockRankSysmon: "sysmon", lockRankScavenge: "scavenge", lockRankForcegc: "forcegc", - lockRankUpdateGOMAXPROCS: "updateGOMAXPROCS", + lockRankComputeMaxProcs: "computeMaxProcs", + lockRankUpdateMaxProcsG: "updateMaxProcsG", lockRankDefer: "defer", lockRankSweepWaiters: "sweepWaiters", lockRankAssistQueue: "assistQueue", @@ -100,6 +103,7 @@ var lockNames = []string{ lockRankSweep: "sweep", lockRankTestR: "testR", lockRankTestW: "testW", + lockRankVgetrandom: "vgetrandom", lockRankTimerSend: "timerSend", lockRankAllocmW: "allocmW", lockRankExecW: "execW", @@ -174,7 +178,8 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankSysmon: {}, lockRankScavenge: {lockRankSysmon}, lockRankForcegc: {lockRankSysmon}, - lockRankUpdateGOMAXPROCS: {lockRankSysmon}, + lockRankComputeMaxProcs: {lockRankSysmon}, + lockRankUpdateMaxProcsG: {lockRankSysmon}, lockRankDefer: {}, lockRankSweepWaiters: {}, lockRankAssistQueue: {}, @@ -183,6 +188,7 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankSweep: {}, lockRankTestR: {}, lockRankTestW: {}, + lockRankVgetrandom: {}, lockRankTimerSend: {}, lockRankAllocmW: {}, lockRankExecW: {}, @@ -191,11 +197,11 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankPollDesc: {}, lockRankWakeableSleep: {}, lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan}, - lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, - lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, - lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR}, - lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR}, + lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, lockRankNotifyList: {}, lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList}, lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers}, @@ -208,29 +214,29 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankUserArenaState: {}, lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, - lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, - lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, - lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, - lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, - lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, + lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, + lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, + lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, + lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, + lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, lockRankPanic: {}, lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, lockRankRaceFini: {lockRankPanic}, - lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR}, - lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankUpdateGOMAXPROCS, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR}, + lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR}, + lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR}, lockRankTestRInternal: {lockRankTestR, lockRankTestW}, } diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 3612d71e66..9361089b80 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -223,6 +223,7 @@ type mheap struct { specialReachableAlloc fixalloc // allocator for specialReachable specialPinCounterAlloc fixalloc // allocator for specialPinCounter specialWeakHandleAlloc fixalloc // allocator for specialWeakHandle + specialBubbleAlloc fixalloc // allocator for specialBubble speciallock mutex // lock for special record allocators. arenaHintAlloc fixalloc // allocator for arenaHints @@ -799,6 +800,7 @@ func (h *mheap) init() { h.specialReachableAlloc.init(unsafe.Sizeof(specialReachable{}), nil, nil, &memstats.other_sys) h.specialPinCounterAlloc.init(unsafe.Sizeof(specialPinCounter{}), nil, nil, &memstats.other_sys) h.specialWeakHandleAlloc.init(unsafe.Sizeof(specialWeakHandle{}), nil, nil, &memstats.gcMiscSys) + h.specialBubbleAlloc.init(unsafe.Sizeof(specialBubble{}), nil, nil, &memstats.other_sys) h.arenaHintAlloc.init(unsafe.Sizeof(arenaHint{}), nil, nil, &memstats.other_sys) // Don't zero mspan allocations. Background sweeping can @@ -2003,6 +2005,8 @@ const ( // _KindSpecialCheckFinalizer adds additional context to a finalizer or cleanup. // Used only if debug.checkfinalizers != 0. _KindSpecialCheckFinalizer = 8 + // _KindSpecialBubble is used to associate objects with synctest bubbles. + _KindSpecialBubble = 9 ) type special struct { @@ -2839,6 +2843,11 @@ func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { lock(&mheap_.speciallock) mheap_.specialTinyBlockAlloc.free(unsafe.Pointer(st)) unlock(&mheap_.speciallock) + case _KindSpecialBubble: + st := (*specialBubble)(unsafe.Pointer(s)) + lock(&mheap_.speciallock) + mheap_.specialBubbleAlloc.free(unsafe.Pointer(st)) + unlock(&mheap_.speciallock) default: throw("bad special kind") panic("not reached") diff --git a/src/runtime/mklockrank.go b/src/runtime/mklockrank.go index 2e3375331a..46a063fdce 100644 --- a/src/runtime/mklockrank.go +++ b/src/runtime/mklockrank.go @@ -41,7 +41,7 @@ const ranks = ` # Sysmon NONE < sysmon -< scavenge, forcegc, updateGOMAXPROCS; +< scavenge, forcegc, computeMaxProcs, updateMaxProcsG; # Defer NONE < defer; @@ -57,6 +57,9 @@ NONE < # Test only NONE < testR, testW; +# vgetrandom +NONE < vgetrandom; + NONE < timerSend; # Scheduler, timers, netpoll @@ -64,9 +67,10 @@ NONE < allocmW, execW, cpuprof, pollCache, pollDesc, wakeableSleep; scavenge, sweep, testR, wakeableSleep, timerSend < hchan; assistQueue, cleanupQueue, + computeMaxProcs, cpuprof, forcegc, - updateGOMAXPROCS, + updateMaxProcsG, hchan, pollDesc, # pollDesc can interact with timers, which can lock sched. scavenge, @@ -134,7 +138,8 @@ allg, reflectOffs, timer, traceStrings, - userArenaState + userArenaState, + vgetrandom # Above MALLOC are things that can allocate memory. < MALLOC # Below MALLOC is the malloc implementation. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 4925528783..5b8db2bee4 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -835,6 +835,7 @@ func schedinit() { lockInit(&reflectOffs.lock, lockRankReflectOffs) lockInit(&finlock, lockRankFin) lockInit(&cpuprof.lock, lockRankCpuprof) + lockInit(&computeMaxProcsLock, lockRankComputeMaxProcs) allocmLock.init(lockRankAllocmR, lockRankAllocmRInternal, lockRankAllocmW) execLock.init(lockRankExecR, lockRankExecRInternal, lockRankExecW) traceLockInit() @@ -1727,7 +1728,6 @@ func startTheWorldWithSema(now int64, w worldStop) int64 { procs := gomaxprocs if newprocs != 0 { procs = newprocs - sched.customGOMAXPROCS = newprocsCustom newprocs = 0 } p1 := procresize(procs) @@ -6546,7 +6546,7 @@ func schedtrace(detailed bool) { unlock(&sched.lock) } -type updateGOMAXPROCSState struct { +type updateMaxProcsGState struct { lock mutex g *g idle atomic.Bool @@ -6556,28 +6556,97 @@ type updateGOMAXPROCSState struct { } var ( - updateGOMAXPROCS updateGOMAXPROCSState - + // GOMAXPROCS update godebug metric. Incremented if automatic + // GOMAXPROCS updates actually change the value of GOMAXPROCS. updatemaxprocs = &godebugInc{name: "updatemaxprocs"} + + // Synchronization and state between updateMaxProcsGoroutine and + // sysmon. + updateMaxProcsG updateMaxProcsGState + + // Synchronization between GOMAXPROCS and sysmon. + // + // Setting GOMAXPROCS via a call to GOMAXPROCS disables automatic + // GOMAXPROCS updates. + // + // We want to make two guarantees to callers of GOMAXPROCS. After + // GOMAXPROCS returns: + // + // 1. The runtime will not make any automatic changes to GOMAXPROCS. + // + // 2. The runtime will not perform any of the system calls used to + // determine the appropriate value of GOMAXPROCS (i.e., it won't + // call defaultGOMAXPROCS). + // + // (1) is the baseline guarantee that everyone needs. The GOMAXPROCS + // API isn't useful to anyone if automatic updates may occur after it + // returns. This is easily achieved by double-checking the state under + // STW before committing an automatic GOMAXPROCS update. + // + // (2) doesn't matter to most users, as it is isn't observable as long + // as (1) holds. However, it can be important to users sandboxing Go. + // They want disable these system calls and need some way to know when + // they are guaranteed the calls will stop. + // + // This would be simple to achieve if we simply called + // defaultGOMAXPROCS under STW in updateMaxProcsGoroutine below. + // However, we would like to avoid scheduling this goroutine every + // second when it will almost never do anything. Instead, sysmon calls + // defaultGOMAXPROCS to decide whether to schedule + // updateMaxProcsGoroutine. Thus we need to synchronize between sysmon + // and GOMAXPROCS calls. + // + // GOMAXPROCS can't hold a runtime mutex across STW. It could hold a + // semaphore, but sysmon cannot take semaphores. Instead, we have a + // more complex scheme: + // + // * sysmon holds computeMaxProcsLock while calling defaultGOMAXPROCS. + // * sysmon skips the current update if sched.customGOMAXPROCS is + // set. + // * GOMAXPROCS sets sched.customGOMAXPROCS once it is committed to + // changing GOMAXPROCS. + // * GOMAXPROCS takes computeMaxProcsLock to wait for outstanding + // defaultGOMAXPROCS calls to complete. + // + // N.B. computeMaxProcsLock could simply be sched.lock, but we want to + // avoid holding that lock during the potentially slow + // defaultGOMAXPROCS. + computeMaxProcsLock mutex ) // Start GOMAXPROCS update helper goroutine. // // This is based on forcegchelper. func defaultGOMAXPROCSUpdateEnable() { - go updateGOMAXPROCSHelper() + if debug.updatemaxprocs == 0 { + // Unconditionally increment the metric when updates are disabled. + // + // It would be more descriptive if we did a dry run of the + // complete update, determining the appropriate value of + // GOMAXPROCS and the bailing out and just incrementing the + // metric if a change would occur. + // + // Not only is that a lot of ongoing work for a disabled + // feature, but some users need to be able to completely + // disable the update system calls (such as sandboxes). + // Currently, updatemaxprocs=0 serves that purpose. + updatemaxprocs.IncNonDefault() + return + } + + go updateMaxProcsGoroutine() } -func updateGOMAXPROCSHelper() { - updateGOMAXPROCS.g = getg() - lockInit(&updateGOMAXPROCS.lock, lockRankUpdateGOMAXPROCS) +func updateMaxProcsGoroutine() { + updateMaxProcsG.g = getg() + lockInit(&updateMaxProcsG.lock, lockRankUpdateMaxProcsG) for { - lock(&updateGOMAXPROCS.lock) - if updateGOMAXPROCS.idle.Load() { - throw("updateGOMAXPROCS: phase error") + lock(&updateMaxProcsG.lock) + if updateMaxProcsG.idle.Load() { + throw("updateMaxProcsGoroutine: phase error") } - updateGOMAXPROCS.idle.Store(true) - goparkunlock(&updateGOMAXPROCS.lock, waitReasonUpdateGOMAXPROCSIdle, traceBlockSystemGoroutine, 1) + updateMaxProcsG.idle.Store(true) + goparkunlock(&updateMaxProcsG.lock, waitReasonUpdateGOMAXPROCSIdle, traceBlockSystemGoroutine, 1) // This goroutine is explicitly resumed by sysmon. stw := stopTheWorldGC(stwGOMAXPROCS) @@ -6595,29 +6664,32 @@ func updateGOMAXPROCSHelper() { // // TODO(prattmic): this could use a nicer API. Perhaps add it to the // stw parameter? - newprocs = updateGOMAXPROCS.procs - newprocsCustom = false + newprocs = updateMaxProcsG.procs + lock(&sched.lock) + sched.customGOMAXPROCS = false + unlock(&sched.lock) startTheWorldGC(stw) - - // We actually changed something. - updatemaxprocs.IncNonDefault() } } func sysmonUpdateGOMAXPROCS() { + // Synchronize with GOMAXPROCS. See comment on computeMaxProcsLock. + lock(&computeMaxProcsLock) + // No update if GOMAXPROCS was set manually. lock(&sched.lock) custom := sched.customGOMAXPROCS curr := gomaxprocs unlock(&sched.lock) if custom { + unlock(&computeMaxProcsLock) return } // Don't hold sched.lock while we read the filesystem. procs := defaultGOMAXPROCS(0) - + unlock(&computeMaxProcsLock) if procs == curr { // Nothing to do. return @@ -6626,14 +6698,14 @@ func sysmonUpdateGOMAXPROCS() { // Sysmon can't directly stop the world. Run the helper to do so on our // behalf. If updateGOMAXPROCS.idle is false, then a previous update is // still pending. - if updateGOMAXPROCS.idle.Load() { - lock(&updateGOMAXPROCS.lock) - updateGOMAXPROCS.procs = procs - updateGOMAXPROCS.idle.Store(false) + if updateMaxProcsG.idle.Load() { + lock(&updateMaxProcsG.lock) + updateMaxProcsG.procs = procs + updateMaxProcsG.idle.Store(false) var list gList - list.push(updateGOMAXPROCS.g) + list.push(updateMaxProcsG.g) injectglist(&list) - unlock(&updateGOMAXPROCS.lock) + unlock(&updateMaxProcsG.lock) } } diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 94ab87f6db..589642efc6 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -1096,6 +1096,7 @@ const ( waitReasonSynctestChanReceive // "chan receive (synctest)" waitReasonSynctestChanSend // "chan send (synctest)" waitReasonSynctestSelect // "select (synctest)" + waitReasonSynctestWaitGroupWait // "sync.WaitGroup.Wait (synctest)" waitReasonCleanupWait // "cleanup wait" ) @@ -1145,6 +1146,7 @@ var waitReasonStrings = [...]string{ waitReasonSynctestChanReceive: "chan receive (synctest)", waitReasonSynctestChanSend: "chan send (synctest)", waitReasonSynctestSelect: "select (synctest)", + waitReasonSynctestWaitGroupWait: "sync.WaitGroup.Wait (synctest)", waitReasonCleanupWait: "cleanup wait", } @@ -1190,18 +1192,18 @@ func (w waitReason) isIdleInSynctest() bool { // isIdleInSynctest indicates that a goroutine is considered idle by synctest.Wait. var isIdleInSynctest = [len(waitReasonStrings)]bool{ - waitReasonChanReceiveNilChan: true, - waitReasonChanSendNilChan: true, - waitReasonSelectNoCases: true, - waitReasonSleep: true, - waitReasonSyncCondWait: true, - waitReasonSyncWaitGroupWait: true, - waitReasonCoroutine: true, - waitReasonSynctestRun: true, - waitReasonSynctestWait: true, - waitReasonSynctestChanReceive: true, - waitReasonSynctestChanSend: true, - waitReasonSynctestSelect: true, + waitReasonChanReceiveNilChan: true, + waitReasonChanSendNilChan: true, + waitReasonSelectNoCases: true, + waitReasonSleep: true, + waitReasonSyncCondWait: true, + waitReasonSynctestWaitGroupWait: true, + waitReasonCoroutine: true, + waitReasonSynctestRun: true, + waitReasonSynctestWait: true, + waitReasonSynctestChanReceive: true, + waitReasonSynctestChanSend: true, + waitReasonSynctestSelect: true, } var ( @@ -1211,7 +1213,6 @@ var ( forcegc forcegcstate sched schedt newprocs int32 - newprocsCustom bool // newprocs value is manually set via runtime.GOMAXPROCS. ) var ( diff --git a/src/runtime/sema.go b/src/runtime/sema.go index 4890df3464..0f029f604f 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -106,8 +106,12 @@ func sync_runtime_SemacquireRWMutex(addr *uint32, lifo bool, skipframes int) { } //go:linkname sync_runtime_SemacquireWaitGroup sync.runtime_SemacquireWaitGroup -func sync_runtime_SemacquireWaitGroup(addr *uint32) { - semacquire1(addr, false, semaBlockProfile, 0, waitReasonSyncWaitGroupWait) +func sync_runtime_SemacquireWaitGroup(addr *uint32, synctestDurable bool) { + reason := waitReasonSyncWaitGroupWait + if synctestDurable { + reason = waitReasonSynctestWaitGroupWait + } + semacquire1(addr, false, semaBlockProfile, 0, reason) } //go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease @@ -631,7 +635,7 @@ func notifyListNotifyAll(l *notifyList) { s.next = nil if s.g.bubble != nil && getg().bubble != s.g.bubble { println("semaphore wake of synctest goroutine", s.g.goid, "from outside bubble") - panic("semaphore wake of synctest goroutine from outside bubble") + fatal("semaphore wake of synctest goroutine from outside bubble") } readyWithTime(s, 4) s = next @@ -688,7 +692,7 @@ func notifyListNotifyOne(l *notifyList) { s.next = nil if s.g.bubble != nil && getg().bubble != s.g.bubble { println("semaphore wake of synctest goroutine", s.g.goid, "from outside bubble") - panic("semaphore wake of synctest goroutine from outside bubble") + fatal("semaphore wake of synctest goroutine from outside bubble") } readyWithTime(s, 4) return diff --git a/src/runtime/synctest.go b/src/runtime/synctest.go index ff1979a8d8..f676afa20d 100644 --- a/src/runtime/synctest.go +++ b/src/runtime/synctest.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/runtime/atomic" "internal/runtime/sys" "unsafe" ) @@ -13,12 +14,13 @@ import ( type synctestBubble struct { mu mutex timers timers - now int64 // current fake time - root *g // caller of synctest.Run - waiter *g // caller of synctest.Wait - main *g // goroutine started by synctest.Run - waiting bool // true if a goroutine is calling synctest.Wait - done bool // true if main has exited + id uint64 // unique id + now int64 // current fake time + root *g // caller of synctest.Run + waiter *g // caller of synctest.Wait + main *g // goroutine started by synctest.Run + waiting bool // true if a goroutine is calling synctest.Wait + done bool // true if main has exited // The bubble is active (not blocked) so long as running > 0 || active > 0. // @@ -163,6 +165,8 @@ func (bubble *synctestBubble) raceaddr() unsafe.Pointer { return unsafe.Pointer(bubble) } +var bubbleGen atomic.Uint64 // bubble ID counter + //go:linkname synctestRun internal/synctest.Run func synctestRun(f func()) { if debug.asynctimerchan.Load() != 0 { @@ -174,6 +178,7 @@ func synctestRun(f func()) { panic("synctest.Run called from within a synctest bubble") } bubble := &synctestBubble{ + id: bubbleGen.Add(1), total: 1, running: 1, root: gp, @@ -313,6 +318,11 @@ func synctestwait_c(gp *g, _ unsafe.Pointer) bool { return true } +//go:linkname synctest_isInBubble internal/synctest.IsInBubble +func synctest_isInBubble() bool { + return getg().bubble != nil +} + //go:linkname synctest_acquire internal/synctest.acquire func synctest_acquire() any { if bubble := getg().bubble; bubble != nil { @@ -339,3 +349,85 @@ func synctest_inBubble(bubble any, f func()) { }() f() } + +// specialBubble is a special used to associate objects with bubbles. +type specialBubble struct { + _ sys.NotInHeap + special special + bubbleid uint64 +} + +// getOrSetBubbleSpecial checks the special record for p's bubble membership. +// +// If add is true and p is not associated with any bubble, +// it adds a special record for p associating it with bubbleid. +// +// It returns ok==true if p is associated with bubbleid +// (including if a new association was added), +// and ok==false if not. +func getOrSetBubbleSpecial(p unsafe.Pointer, bubbleid uint64, add bool) (ok bool) { + span := spanOfHeap(uintptr(p)) + if span == nil { + throw("getOrSetBubbleSpecial on invalid pointer") + } + + // Ensure that the span is swept. + // Sweeping accesses the specials list w/o locks, so we have + // to synchronize with it. And it's just much safer. + mp := acquirem() + span.ensureSwept() + + offset := uintptr(p) - span.base() + + lock(&span.speciallock) + + // Find splice point, check for existing record. + iter, exists := span.specialFindSplicePoint(offset, _KindSpecialBubble) + if exists { + // p is already associated with a bubble. + // Return true iff it's the same bubble. + s := (*specialBubble)((unsafe.Pointer)(*iter)) + ok = s.bubbleid == bubbleid + } else if add { + // p is not associated with a bubble, + // and we've been asked to add an association. + s := (*specialBubble)(mheap_.specialBubbleAlloc.alloc()) + s.bubbleid = bubbleid + s.special.kind = _KindSpecialBubble + s.special.offset = offset + s.special.next = *iter + *iter = (*special)(unsafe.Pointer(s)) + spanHasSpecials(span) + ok = true + } else { + // p is not associated with a bubble. + ok = false + } + + unlock(&span.speciallock) + releasem(mp) + + return ok +} + +// synctest_associate associates p with the current bubble. +// It returns false if p is already associated with a different bubble. +// +//go:linkname synctest_associate internal/synctest.associate +func synctest_associate(p unsafe.Pointer) (ok bool) { + return getOrSetBubbleSpecial(p, getg().bubble.id, true) +} + +// synctest_disassociate disassociates p from its bubble. +// +//go:linkname synctest_disassociate internal/synctest.disassociate +func synctest_disassociate(p unsafe.Pointer) { + removespecial(p, _KindSpecialBubble) +} + +// synctest_isAssociated reports whether p is associated with the current bubble. +// +//go:linkname synctest_isAssociated internal/synctest.isAssociated +func synctest_isAssociated(p unsafe.Pointer) bool { + return getOrSetBubbleSpecial(p, getg().bubble.id, false) +} diff --git a/src/runtime/testdata/testprog/synctest.go b/src/runtime/testdata/testprog/synctest.go new file mode 100644 index 0000000000..dd3a6df8a0 --- /dev/null +++ b/src/runtime/testdata/testprog/synctest.go @@ -0,0 +1,58 @@ +// Copyright 2025 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 main + +import ( + "internal/synctest" + "sync" +) + +func init() { + register("SynctestCond/signal/no_bubble", func() { + synctestCond(func(cond *sync.Cond) { + cond.Signal() + }) + }) + register("SynctestCond/broadcast/no_bubble", func() { + synctestCond(func(cond *sync.Cond) { + cond.Broadcast() + }) + }) + register("SynctestCond/signal/other_bubble", func() { + synctestCond(func(cond *sync.Cond) { + synctest.Run(cond.Signal) + }) + }) + register("SynctestCond/broadcast/other_bubble", func() { + synctestCond(func(cond *sync.Cond) { + synctest.Run(cond.Broadcast) + }) + }) +} + +func synctestCond(f func(*sync.Cond)) { + var ( + mu sync.Mutex + cond = sync.NewCond(&mu) + readyc = make(chan struct{}) + wg sync.WaitGroup + ) + defer wg.Wait() + wg.Go(func() { + synctest.Run(func() { + go func() { + mu.Lock() + defer mu.Unlock() + cond.Wait() + }() + synctest.Wait() + <-readyc // #1: signal that cond.Wait is waiting + <-readyc // #2: wait to continue + cond.Signal() + }) + }) + readyc <- struct{}{} + f(cond) +} diff --git a/src/runtime/traceruntime.go b/src/runtime/traceruntime.go index 98ac1082a8..39adeb4c07 100644 --- a/src/runtime/traceruntime.go +++ b/src/runtime/traceruntime.go @@ -574,7 +574,9 @@ func (tl traceLocker) HeapAlloc(live uint64) { // HeapGoal reads the current heap goal and emits a HeapGoal event. func (tl traceLocker) HeapGoal() { heapGoal := gcController.heapGoal() - if heapGoal == ^uint64(0) { + // The heapGoal calculations will result in strange numbers if the GC if off. See go.dev/issue/63864. + // Check gcPercent before using the heapGoal in the trace. + if heapGoal == ^uint64(0) || gcController.gcPercent.Load() < 0 { // Heap-based triggering is disabled. heapGoal = 0 } diff --git a/src/runtime/vgetrandom_linux.go b/src/runtime/vgetrandom_linux.go index 8f39f6d3a6..225f7029be 100644 --- a/src/runtime/vgetrandom_linux.go +++ b/src/runtime/vgetrandom_linux.go @@ -40,7 +40,7 @@ func vgetrandomInit() { vgetrandomAlloc.mmapProt = int32(params.MmapProt) vgetrandomAlloc.mmapFlags = int32(params.MmapFlags) - lockInit(&vgetrandomAlloc.statesLock, lockRankLeafRank) + lockInit(&vgetrandomAlloc.statesLock, lockRankVgetrandom) } func vgetrandomGetState() uintptr { diff --git a/src/slices/iter.go b/src/slices/iter.go index cd8f308ca0..bbea6134d9 100644 --- a/src/slices/iter.go +++ b/src/slices/iter.go @@ -46,6 +46,7 @@ func Values[Slice ~[]E, E any](s Slice) iter.Seq[E] { // AppendSeq appends the values from seq to the slice and // returns the extended slice. +// If seq is empty, the result preserves the nilness of s. func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice { for v := range seq { s = append(s, v) @@ -54,12 +55,14 @@ func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice { } // Collect collects values from seq into a new slice and returns it. +// If seq is empty, the result is nil. func Collect[E any](seq iter.Seq[E]) []E { return AppendSeq([]E(nil), seq) } // Sorted collects values from seq into a new slice, sorts the slice, // and returns it. +// If seq is empty, the result is nil. func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E { s := Collect(seq) Sort(s) @@ -68,6 +71,7 @@ func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E { // SortedFunc collects values from seq into a new slice, sorts the slice // using the comparison function, and returns it. +// If seq is empty, the result is nil. func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { s := Collect(seq) SortFunc(s, cmp) @@ -78,6 +82,7 @@ func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { // It then sorts the slice while keeping the original order of equal elements, // using the comparison function to compare elements. // It returns the new slice. +// If seq is empty, the result is nil. func SortedStableFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { s := Collect(seq) SortStableFunc(s, cmp) diff --git a/src/slices/slices.go b/src/slices/slices.go index 32029cd8ed..30595793c9 100644 --- a/src/slices/slices.go +++ b/src/slices/slices.go @@ -131,6 +131,7 @@ func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool { // and, if i < len(s), r[i+len(v)] == value originally at r[i]. // Insert panics if i > len(s). // This function is O(len(s) + len(v)). +// If the result is empty, it has the same nilness as s. func Insert[S ~[]E, E any](s S, i int, v ...E) S { _ = s[i:] // bounds check @@ -217,6 +218,7 @@ func Insert[S ~[]E, E any](s S, i int, v ...E) S { // Delete is O(len(s)-i), so if many items must be deleted, it is better to // make a single call deleting them all together than to delete one at a time. // Delete zeroes the elements s[len(s)-(j-i):len(s)]. +// If the result is empty, it has the same nilness as s. func Delete[S ~[]E, E any](s S, i, j int) S { _ = s[i:j:len(s)] // bounds check @@ -233,6 +235,7 @@ func Delete[S ~[]E, E any](s S, i, j int) S { // DeleteFunc removes any elements from s for which del returns true, // returning the modified slice. // DeleteFunc zeroes the elements between the new length and the original length. +// If the result is empty, it has the same nilness as s. func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S { i := IndexFunc(s, del) if i == -1 { @@ -253,6 +256,7 @@ func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S { // modified slice. // Replace panics if j > len(s) or s[i:j] is not a valid slice of s. // When len(v) < (j-i), Replace zeroes the elements between the new length and the original length. +// If the result is empty, it has the same nilness as s. func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { _ = s[i:j] // bounds check @@ -345,6 +349,7 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { // Clone returns a copy of the slice. // The elements are copied using assignment, so this is a shallow clone. // The result may have additional unused capacity. +// The result preserves the nilness of s. func Clone[S ~[]E, E any](s S) S { // Preserve nilness in case it matters. if s == nil { @@ -360,6 +365,7 @@ func Clone[S ~[]E, E any](s S) S { // Compact modifies the contents of the slice s and returns the modified slice, // which may have a smaller length. // Compact zeroes the elements between the new length and the original length. +// The result preserves the nilness of s. func Compact[S ~[]E, E comparable](s S) S { if len(s) < 2 { return s @@ -384,6 +390,7 @@ func Compact[S ~[]E, E comparable](s S) S { // CompactFunc is like [Compact] but uses an equality function to compare elements. // For runs of elements that compare equal, CompactFunc keeps the first one. // CompactFunc zeroes the elements between the new length and the original length. +// The result preserves the nilness of s. func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { if len(s) < 2 { return s @@ -409,6 +416,7 @@ func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { // another n elements. After Grow(n), at least n elements can be appended // to the slice without another allocation. If n is negative or too large to // allocate the memory, Grow panics. +// The result preserves the nilness of s. func Grow[S ~[]E, E any](s S, n int) S { if n < 0 { panic("cannot be negative") @@ -421,6 +429,7 @@ func Grow[S ~[]E, E any](s S, n int) S { } // Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. +// The result preserves the nilness of s. func Clip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] } @@ -476,6 +485,7 @@ func Reverse[S ~[]E, E any](s S) { } // Concat returns a new slice concatenating the passed in slices. +// If the concatenation is empty, the result is nil. func Concat[S ~[]E, E any](slices ...S) S { size := 0 for _, s := range slices { diff --git a/src/slices/slices_test.go b/src/slices/slices_test.go index 4ced7c0759..edf7e7b610 100644 --- a/src/slices/slices_test.go +++ b/src/slices/slices_test.go @@ -1462,3 +1462,86 @@ func TestIssue68488(t *testing.T) { t.Error("clone keeps alive s due to array overlap") } } + +// This test asserts the behavior when the primary slice operand is nil. +// +// Some operations preserve the nilness of their operand while others +// do not, but in all cases the behavior is documented. +func TestNilness(t *testing.T) { + var ( + emptySlice = []int{} + nilSlice = []int(nil) + emptySeq = func(yield func(int) bool) {} + truth = func(int) bool { return true } + equal = func(x, y int) bool { panic("unreachable") } + ) + + wantNil := func(slice []int, cond string) { + if slice != nil { + t.Errorf("%s != nil", cond) + } + } + wantNonNil := func(slice []int, cond string) { + if slice == nil { + t.Errorf("%s == nil", cond) + } + } + + // The update functions + // Insert, AppendSeq, Delete, DeleteFunc, Clone, Compact, CompactFunc + // preserve nilness, like s[i:j]. + wantNil(AppendSeq(nilSlice, emptySeq), "AppendSeq(nil, empty)") + wantNonNil(AppendSeq(emptySlice, emptySeq), "AppendSeq(nil, empty)") + + wantNil(Insert(nilSlice, 0), "Insert(nil, 0)") + wantNonNil(Insert(emptySlice, 0), "Insert(empty, 0)") + + wantNil(Delete(nilSlice, 0, 0), "Delete(nil, 0, 0)") + wantNonNil(Delete(emptySlice, 0, 0), "Delete(empty, 0, 0)") + wantNonNil(Delete([]int{1}, 0, 1), "Delete([]int{1}, 0, 1)") + + wantNil(DeleteFunc(nilSlice, truth), "DeleteFunc(nil, f)") + wantNonNil(DeleteFunc(emptySlice, truth), "DeleteFunc(empty, f)") + wantNonNil(DeleteFunc([]int{1}, truth), "DeleteFunc([]int{1}, truth)") + + wantNil(Replace(nilSlice, 0, 0), "Replace(nil, 0, 0)") + wantNonNil(Replace(emptySlice, 0, 0), "Replace(empty, 0, 0)") + wantNonNil(Replace([]int{1}, 0, 1), "Replace([]int{1}, 0, 1)") + + wantNil(Clone(nilSlice), "Clone(nil)") + wantNonNil(Clone(emptySlice), "Clone(empty)") + + wantNil(Compact(nilSlice), "Compact(nil)") + wantNonNil(Compact(emptySlice), "Compact(empty)") + + wantNil(CompactFunc(nilSlice, equal), "CompactFunc(nil)") + wantNonNil(CompactFunc(emptySlice, equal), "CompactFunc(empty)") + + wantNil(Grow(nilSlice, 0), "Grow(nil, 0)") + wantNonNil(Grow(emptySlice, 0), "Grow(empty, 0)") + + wantNil(Clip(nilSlice), "Clip(nil)") + wantNonNil(Clip(emptySlice), "Clip(empty)") + wantNonNil(Clip([]int{1}[:0:0]), "Clip([]int{1}[:0:0])") + + // Concat returns nil iff the result is empty. + // This is an unfortunate irregularity. + wantNil(Concat(nilSlice, emptySlice, nilSlice, emptySlice), "Concat(nil, ...empty...)") + wantNil(Concat(emptySlice, emptySlice, nilSlice, emptySlice), "Concat(empty, ...empty...)") + wantNil(Concat[[]int](), "Concat()") + + // Repeat never returns nil. Another irregularity. + wantNonNil(Repeat(nilSlice, 0), "Repeat(nil, 0)") + wantNonNil(Repeat(emptySlice, 0), "Repeat(empty, 0)") + wantNonNil(Repeat(nilSlice, 2), "Repeat(nil, 2)") + wantNonNil(Repeat(emptySlice, 2), "Repeat(empty, 2)") + + // The collection functions + // Collect, Sorted, SortedFunc, SortedStableFunc + // return nil given an empty sequence. + wantNil(Collect(emptySeq), "Collect(empty)") + + wantNil(Sorted(emptySeq), "Sorted(empty)") + wantNil(SortedFunc(emptySeq, cmp.Compare), "SortedFunc(empty)") + wantNil(SortedStableFunc(emptySeq, cmp.Compare), "SortedStableFunc(empty)") +} diff --git a/src/sync/runtime.go b/src/sync/runtime.go index 99e5bccbee..ae3368e58d 100644 --- a/src/sync/runtime.go +++ b/src/sync/runtime.go @@ -14,7 +14,7 @@ import "unsafe" func runtime_Semacquire(s *uint32) // SemacquireWaitGroup is like Semacquire, but for WaitGroup.Wait. -func runtime_SemacquireWaitGroup(s *uint32) +func runtime_SemacquireWaitGroup(s *uint32, synctestDurable bool) // Semacquire(RW)Mutex(R) is like Semacquire, but for profiling contended // Mutexes and RWMutexes. diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go index c850f58ed1..efc63be099 100644 --- a/src/sync/waitgroup.go +++ b/src/sync/waitgroup.go @@ -6,6 +6,7 @@ package sync import ( "internal/race" + "internal/synctest" "sync/atomic" "unsafe" ) @@ -47,10 +48,17 @@ import ( type WaitGroup struct { noCopy noCopy - state atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count. + // Bits (high to low): + // bits[0:32] counter + // bits[32] flag: synctest bubble membership + // bits[33:64] wait count + state atomic.Uint64 sema uint32 } +// waitGroupBubbleFlag indicates that a WaitGroup is associated with a synctest bubble. +const waitGroupBubbleFlag = 0x8000_0000 + // Add adds delta, which may be negative, to the [WaitGroup] task counter. // If the counter becomes zero, all goroutines blocked on [WaitGroup.Wait] are released. // If the counter goes negative, Add panics. @@ -75,9 +83,27 @@ func (wg *WaitGroup) Add(delta int) { race.Disable() defer race.Enable() } + if synctest.IsInBubble() { + // If Add is called from within a bubble, then all Add calls must be made + // from the same bubble. + if !synctest.Associate(wg) { + // wg is already associated with a different bubble. + fatal("sync: WaitGroup.Add called from multiple synctest bubbles") + } else { + state := wg.state.Or(waitGroupBubbleFlag) + if state != 0 && state&waitGroupBubbleFlag == 0 { + // Add has been called from outside this bubble. + fatal("sync: WaitGroup.Add called from inside and outside synctest bubble") + } + } + } state := wg.state.Add(uint64(delta) << 32) + if state&waitGroupBubbleFlag != 0 && !synctest.IsInBubble() { + // Add has been called from within a synctest bubble (and we aren't in one). + fatal("sync: WaitGroup.Add called from inside and outside synctest bubble") + } v := int32(state >> 32) - w := uint32(state) + w := uint32(state & 0x7fffffff) if race.Enabled && delta > 0 && v == int32(delta) { // The first increment must be synchronized with Wait. // Need to model this as a read, because there can be @@ -90,6 +116,13 @@ func (wg *WaitGroup) Add(delta int) { if w != 0 && delta > 0 && v == int32(delta) { panic("sync: WaitGroup misuse: Add called concurrently with Wait") } + if v == 0 && state&waitGroupBubbleFlag != 0 { + // Disassociate the WaitGroup from its bubble. + synctest.Disassociate(wg) + if w == 0 { + wg.state.Store(0) + } + } if v > 0 || w == 0 { return } @@ -147,7 +180,21 @@ func (wg *WaitGroup) Wait() { // otherwise concurrent Waits will race with each other. race.Write(unsafe.Pointer(&wg.sema)) } - runtime_SemacquireWaitGroup(&wg.sema) + synctestDurable := false + if state&waitGroupBubbleFlag != 0 && synctest.IsInBubble() { + if race.Enabled { + race.Enable() + } + if synctest.IsAssociated(wg) { + // Add was called within the current bubble, + // so this Wait is durably blocking. + synctestDurable = true + } + if race.Enabled { + race.Disable() + } + } + runtime_SemacquireWaitGroup(&wg.sema, synctestDurable) if wg.state.Load() != 0 { panic("sync: WaitGroup is reused before previous Wait has returned") } diff --git a/src/testing/synctest/synctest.go b/src/testing/synctest/synctest.go index c7e93b2201..57a6fbfbd6 100644 --- a/src/testing/synctest/synctest.go +++ b/src/testing/synctest/synctest.go @@ -72,10 +72,17 @@ // - a blocking select statement where every case is a channel created // within the bubble // - [sync.Cond.Wait] -// - [sync.WaitGroup.Wait] +// - [sync.WaitGroup.Wait], when [sync.WaitGroup.Add] was called within the bubble // - [time.Sleep] // -// Locking a [sync.Mutex] or [sync.RWMutex] is not durably blocking. +// Operations not in the above list are not durably blocking. +// In particular, the following operations may block a goroutine, +// but are not durably blocking because the goroutine can be unblocked +// by an event occurring outside its bubble: +// +// - locking a [sync.Mutex] or [sync.RWMutex] +// - blocking on I/O, such as reading from a network socket +// - system calls // // # Isolation // @@ -83,6 +90,13 @@ // is associated with it. Operating on a bubbled channel, timer, or // ticker from outside the bubble panics. // +// A [sync.WaitGroup] becomes associated with a bubble on the first +// call to Add or Go. Once a WaitGroup is associated with a bubble, +// calling Add or Go from outside that bubble is a fatal error. +// +// [sync.Cond.Wait] is durably blocking. Waking a goroutine in a bubble +// blocked on Cond.Wait from outside the bubble is a fatal error. +// // Cleanup functions and finalizers registered with // [runtime.AddCleanup] and [runtime.SetFinalizer] // run outside of any bubble. @@ -259,13 +273,19 @@ import ( // associated with the bubble. // - T.Run, T.Parallel, and T.Deadline must not be called. func Test(t *testing.T, f func(*testing.T)) { + var ok bool synctest.Run(func() { - testingSynctestTest(t, f) + ok = testingSynctestTest(t, f) }) + if !ok { + // Fail the test outside the bubble, + // so test durations get set using real time. + t.FailNow() + } } //go:linkname testingSynctestTest testing/synctest.testingSynctestTest -func testingSynctestTest(t *testing.T, f func(*testing.T)) +func testingSynctestTest(t *testing.T, f func(*testing.T)) bool // Wait blocks until every goroutine within the current bubble, // other than the current goroutine, is durably blocked. diff --git a/src/testing/synctest/synctest_test.go b/src/testing/synctest/synctest_test.go index 4897df999e..822fd6fe1c 100644 --- a/src/testing/synctest/synctest_test.go +++ b/src/testing/synctest/synctest_test.go @@ -22,37 +22,56 @@ func TestSuccess(t *testing.T) { } func TestFatal(t *testing.T) { - runTest(t, func() { + runTest(t, nil, func() { synctest.Test(t, func(t *testing.T) { t.Fatal("fatal") }) - }, `^=== RUN TestFatal + }, `^--- FAIL: TestFatal.* synctest_test.go:.* fatal ---- FAIL: TestFatal.* FAIL $`) } func TestError(t *testing.T) { - runTest(t, func() { + runTest(t, nil, func() { synctest.Test(t, func(t *testing.T) { t.Error("error") }) - }, `^=== RUN TestError + }, `^--- FAIL: TestError.* synctest_test.go:.* error ---- FAIL: TestError.* +FAIL +$`) +} + +func TestVerboseError(t *testing.T) { + runTest(t, []string{"-test.v"}, func() { + synctest.Test(t, func(t *testing.T) { + t.Error("error") + }) + }, `^=== RUN TestVerboseError + synctest_test.go:.* error +--- FAIL: TestVerboseError.* FAIL $`) } func TestSkip(t *testing.T) { - runTest(t, func() { + runTest(t, nil, func() { synctest.Test(t, func(t *testing.T) { t.Skip("skip") }) - }, `^=== RUN TestSkip + }, `^PASS +$`) +} + +func TestVerboseSkip(t *testing.T) { + runTest(t, []string{"-test.v"}, func() { + synctest.Test(t, func(t *testing.T) { + t.Skip("skip") + }) + }, `^=== RUN TestVerboseSkip synctest_test.go:.* skip ---- PASS: TestSkip.* +--- PASS: TestVerboseSkip.* PASS $`) } @@ -131,7 +150,7 @@ func wantPanic(t *testing.T, want string) { } } -func runTest(t *testing.T, f func(), pattern string) { +func runTest(t *testing.T, args []string, f func(), pattern string) { if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { f() return @@ -139,7 +158,8 @@ func runTest(t *testing.T, f func(), pattern string) { t.Helper() re := regexp.MustCompile(pattern) testenv.MustHaveExec(t) - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.v", "-test.count=1") + cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+regexp.QuoteMeta(t.Name())+"$", "-test.count=1") + cmd.Args = append(cmd.Args, args...) cmd = testenv.CleanCmdEnv(cmd) cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") out, _ := cmd.CombinedOutput() diff --git a/src/testing/testing.go b/src/testing/testing.go index 85ac1aeb32..b5305f29cc 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1045,7 +1045,7 @@ func (c *common) destination() *common { c.mu.Lock() defer c.mu.Unlock() - if !c.done { + if !c.done && !c.isSynctest { return c } for parent := c.parent; parent != nil; parent = parent.parent { @@ -1851,7 +1851,8 @@ func tRunner(t *T, fn func(t *T)) { t.Logf("cleanup panicked with %v", r) } // Flush the output log up to the root before dying. - for root := &t.common; root.parent != nil; root = root.parent { + // Skip this if this *T is a synctest bubble, because we're not a subtest. + for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent { root.mu.Lock() root.duration += highPrecisionTimeSince(root.start) d := root.duration @@ -2013,7 +2014,7 @@ func (t *T) Run(name string, f func(t *T)) bool { // It is called by synctest.Test, from within an already-created bubble. // //go:linkname testingSynctestTest testing/synctest.testingSynctestTest -func testingSynctestTest(t *T, f func(*T)) { +func testingSynctestTest(t *T, f func(*T)) (ok bool) { if t.cleanupStarted.Load() { panic("testing: synctest.Run called during t.Cleanup") } @@ -2037,7 +2038,6 @@ func testingSynctestTest(t *T, f func(*T)) { }, tstate: t.tstate, } - t2.setOutputWriter() go tRunner(t2, f) if !<-t2.signal { @@ -2045,6 +2045,7 @@ func testingSynctestTest(t *T, f func(*T)) { // parent tests by one of the subtests. Continue aborting up the chain. runtime.Goexit() } + return !t2.failed } // Deadline reports the time at which the test binary will have diff --git a/test/fixedbugs/issue73748a.go b/test/fixedbugs/issue73748a.go new file mode 100644 index 0000000000..c8ac10c29c --- /dev/null +++ b/test/fixedbugs/issue73748a.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2025 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 main + +import ( + "context" + "io" + "runtime/trace" +) + +type T struct { + a [16]int +} + +//go:noinline +func f(x *T) { + *x = T{} +} + +func main() { + trace.Start(io.Discard) + defer func() { + recover() + trace.Log(context.Background(), "a", "b") + + }() + f(nil) +} diff --git a/test/fixedbugs/issue73748b.go b/test/fixedbugs/issue73748b.go new file mode 100644 index 0000000000..ff094a9764 --- /dev/null +++ b/test/fixedbugs/issue73748b.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2025 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 main + +import ( + "context" + "io" + "runtime/trace" +) + +type T struct { + a [16]int +} + +//go:noinline +func f(x, y *T) { + *x = *y +} + +func main() { + trace.Start(io.Discard) + defer func() { + recover() + trace.Log(context.Background(), "a", "b") + + }() + f(nil, nil) +}