Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5ef5a686c | ||
|
|
f3a584b498 | ||
|
|
57388d3e2f | ||
|
|
0d3d2f971b | ||
|
|
98c5110178 | ||
|
|
59840a035a | ||
|
|
ada6955fd4 | ||
|
|
a02b4e43d6 | ||
|
|
c0f79a96a0 | ||
|
|
5ec2836d14 | ||
|
|
530b016cd0 | ||
|
|
e2770a2ccc |
1
.github/workflows/go-build.yml
vendored
1
.github/workflows/go-build.yml
vendored
@@ -73,6 +73,7 @@ jobs:
|
|||||||
rm -rf src/*.rc
|
rm -rf src/*.rc
|
||||||
rm -rf src/make.*
|
rm -rf src/make.*
|
||||||
rm -rf src/run.*
|
rm -rf src/run.*
|
||||||
|
rm -rf *.md
|
||||||
|
|
||||||
# Process binaries
|
# Process binaries
|
||||||
cd bin
|
cd bin
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -10,6 +10,8 @@ _Gopher image by [Renee French][rf], licensed under [Creative Commons 4.0 Attrib
|
|||||||
1. **Windows 7 and Windows Server 2008 R2 Support**
|
1. **Windows 7 and Windows Server 2008 R2 Support**
|
||||||
While the official Go project has dropped support for Windows 7 and Windows Server 2008 R2, this fork maintains compatibility with these legacy Windows systems.
|
While the official Go project has dropped support for Windows 7 and Windows Server 2008 R2, this fork maintains compatibility with these legacy Windows systems.
|
||||||
|
|
||||||
|
Tested on Windows 7 RTM (build 7600) — no updates required — through Windows 11 24H2
|
||||||
|
|
||||||
2. **Classic `go get` Behaviour**
|
2. **Classic `go get` Behaviour**
|
||||||
This fork allows for the deprecated `go get` behaviour when `GO111MODULE` is set to "off" or "auto". This means:
|
This fork allows for the deprecated `go get` behaviour when `GO111MODULE` is set to "off" or "auto". This means:
|
||||||
|
|
||||||
@@ -29,6 +31,7 @@ Every release includes the following modifications:
|
|||||||
- Added back Windows 7 console handle workaround (reverted [48042aa](https://github.com/golang/go/commit/48042aa09c2f878c4faa576948b07fe625c4707a))
|
- Added back Windows 7 console handle workaround (reverted [48042aa](https://github.com/golang/go/commit/48042aa09c2f878c4faa576948b07fe625c4707a))
|
||||||
- Added back 5ms sleep on Windows 7/8 in (\*Process).Wait (reverted [f0894a0](https://github.com/golang/go/commit/f0894a00f4b756d4b9b4078af2e686b359493583))
|
- Added back 5ms sleep on Windows 7/8 in (\*Process).Wait (reverted [f0894a0](https://github.com/golang/go/commit/f0894a00f4b756d4b9b4078af2e686b359493583))
|
||||||
- Restored deprecated `go get` behavior for use outside modules (reverted [de4d503](https://github.com/golang/go/commit/de4d50316fb5c6d1529aa5377dc93b26021ee843))
|
- Restored deprecated `go get` behavior for use outside modules (reverted [de4d503](https://github.com/golang/go/commit/de4d50316fb5c6d1529aa5377dc93b26021ee843))
|
||||||
|
- Reverted to the previous `removeall_noat` variant for Windows (fixed [issue #2](https://github.com/thongtech/go-legacy-win7/issues/2))
|
||||||
- Includes all improvements and bug fixes from the corresponding upstream Go release
|
- Includes all improvements and bug fixes from the corresponding upstream Go release
|
||||||
|
|
||||||
The Windows binary provided here also supports Windows 7 and Windows Server 2008 R2
|
The Windows binary provided here also supports Windows 7 and Windows Server 2008 R2
|
||||||
@@ -37,7 +40,20 @@ The Windows binary provided here also supports Windows 7 and Windows Server 2008
|
|||||||
|
|
||||||
### Binary Distributions
|
### Binary Distributions
|
||||||
|
|
||||||
Binary distributions are **available at the [release page](https://github.com/thongtech/go-legacy-win7/releases)**.
|
| OS | Architecture | Filename | SHA‑256 Hash |
|
||||||
|
|----|--------------|----------|--------------|
|
||||||
|
| **macOS** | Intel (amd64) | [go-legacy-win7-1.25.1-1.darwin_amd64.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.darwin_amd64.tar.gz) | `4bd9d9a3079c1b4d81b22d999697903fa9ac95eb18dee9376a88e6fa82474943` |
|
||||||
|
| macOS | Apple (ARM64) | [go-legacy-win7-1.25.1-1.darwin_arm64.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.darwin_arm64.tar.gz) | `d269eb12273f6a94df965a4bcd46b67aafe45467701b6e1ddf0df31d687b55bb` |
|
||||||
|
| **Linux** | x86 (386) | [go-legacy-win7-1.25.1-1.linux_386.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.linux_386.tar.gz) | `de0d649fff56dd0fcdd335c5a126ad5847cf0a227724cff44f86cb78d14ddc43` |
|
||||||
|
| Linux | x64 (amd64) | [go-legacy-win7-1.25.1-1.linux_amd64.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.linux_amd64.tar.gz) | `452aafba7800600da66dfeb36d3cf291f9c01381fdc6e24441aba7697c49d33a` |
|
||||||
|
| Linux | ARM (32‑bit) | [go-legacy-win7-1.25.1-1.linux_arm.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.linux_arm.tar.gz) | `eb80a1f41bd3e21c0f857500b2d30afcd17311f902ea3c04c13e345664a54ff6` |
|
||||||
|
| Linux | ARM64 | [go-legacy-win7-1.25.1-1.linux_arm64.tar.gz](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.linux_arm64.tar.gz) | `a05468e7b90fbeee70610dc4c1a439d7929a0ec06765d5cb0454cd900e4f90cb` |
|
||||||
|
| **Windows** | x86 (386) | [go-legacy-win7-1.25.1-1.windows_386.zip](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.windows_386.zip) | `c7c90918f8506e2fd28270a38a03e5200635e2183e4365090e7b00aca5a320be` |
|
||||||
|
| Windows | x64 (amd64) | [go-legacy-win7-1.25.1-1.windows_amd64.zip](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.windows_amd64.zip) | `aa6c2a22bb7c8e4ac632e3656ce6eb3461de7ea0645064496f161bc4edc47555` |
|
||||||
|
| Windows | ARM64 | [go-legacy-win7-1.25.1-1.windows_arm64.zip](https://github.com/thongtech/go-legacy-win7/releases/download/v1.25.1-1/go-legacy-win7-1.25.1-1.windows_arm64.zip) | `fe498473f8f6cc7ad7f5d41a46acebc8f6ac1be7edaeb75f356eb604061b4276` |
|
||||||
|
|
||||||
|
### Before you begin
|
||||||
|
To avoid PATH/GOROOT conflicts and mixed toolchains, uninstall any existing Go installation first.
|
||||||
|
|
||||||
#### Windows Installation
|
#### Windows Installation
|
||||||
|
|
||||||
|
|||||||
4
VERSION
4
VERSION
@@ -1,2 +1,2 @@
|
|||||||
go1.25.0
|
go1.25.1
|
||||||
time 2025-08-08T19:33:32Z
|
time 2025-08-27T15:49:40Z
|
||||||
|
|||||||
130
patches/0006-Use-removeall_noat-variant-on-Windows.patch
Normal file
130
patches/0006-Use-removeall_noat-variant-on-Windows.patch
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
From c0f79a96a0262b2dd69d1a85e20b481d03cba8f2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
|
||||||
|
Date: Tue, 26 Aug 2025 15:07:25 +0700
|
||||||
|
Subject: [PATCH] Use removeall_noat variant on Windows
|
||||||
|
|
||||||
|
---
|
||||||
|
src/os/removeall_at.go | 2 +-
|
||||||
|
src/os/removeall_noat.go | 2 +-
|
||||||
|
src/os/root.go | 6 ------
|
||||||
|
src/os/root_noopenat.go | 20 --------------------
|
||||||
|
src/os/root_openat.go | 22 ----------------------
|
||||||
|
5 files changed, 2 insertions(+), 50 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
|
||||||
|
index 5ddc1ade..61298a46 100644
|
||||||
|
--- a/src/os/removeall_at.go
|
||||||
|
+++ b/src/os/removeall_at.go
|
||||||
|
@@ -2,7 +2,7 @@
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
-//go:build unix || wasip1 || windows
|
||||||
|
+//go:build unix || wasip1
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go
|
||||||
|
index 395a1503..02f6fca7 100644
|
||||||
|
--- a/src/os/removeall_noat.go
|
||||||
|
+++ b/src/os/removeall_noat.go
|
||||||
|
@@ -2,7 +2,7 @@
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
-//go:build (js && wasm) || plan9
|
||||||
|
+//go:build (js && wasm) || plan9 || windows
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
diff --git a/src/os/root.go b/src/os/root.go
|
||||||
|
index d759727c..1ecbcc09 100644
|
||||||
|
--- a/src/os/root.go
|
||||||
|
+++ b/src/os/root.go
|
||||||
|
@@ -189,12 +189,6 @@ func (r *Root) Remove(name string) error {
|
||||||
|
return rootRemove(r, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
-// RemoveAll removes the named file or directory and any children that it contains.
|
||||||
|
-// See [RemoveAll] for more details.
|
||||||
|
-func (r *Root) RemoveAll(name string) error {
|
||||||
|
- return rootRemoveAll(r, name)
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
// Stat returns a [FileInfo] describing the named file in the root.
|
||||||
|
// See [Stat] for more details.
|
||||||
|
func (r *Root) Stat(name string) (FileInfo, error) {
|
||||||
|
diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go
|
||||||
|
index 59f1abe9..ecdf264f 100644
|
||||||
|
--- a/src/os/root_noopenat.go
|
||||||
|
+++ b/src/os/root_noopenat.go
|
||||||
|
@@ -11,7 +11,6 @@ import (
|
||||||
|
"internal/filepathlite"
|
||||||
|
"internal/stringslite"
|
||||||
|
"sync/atomic"
|
||||||
|
- "syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
@@ -186,25 +185,6 @@ func rootRemove(r *Root, name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
-func rootRemoveAll(r *Root, name string) error {
|
||||||
|
- if endsWithDot(name) {
|
||||||
|
- // Consistency with os.RemoveAll: Return EINVAL when trying to remove .
|
||||||
|
- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
|
||||||
|
- }
|
||||||
|
- if err := checkPathEscapesLstat(r, name); err != nil {
|
||||||
|
- if err == syscall.ENOTDIR {
|
||||||
|
- // Some intermediate path component is not a directory.
|
||||||
|
- // RemoveAll treats this as success (since the target doesn't exist).
|
||||||
|
- return nil
|
||||||
|
- }
|
||||||
|
- return &PathError{Op: "RemoveAll", Path: name, Err: err}
|
||||||
|
- }
|
||||||
|
- if err := RemoveAll(joinPath(r.root.name, name)); err != nil {
|
||||||
|
- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
|
||||||
|
- }
|
||||||
|
- return nil
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
func rootReadlink(r *Root, name string) (string, error) {
|
||||||
|
if err := checkPathEscapesLstat(r, name); err != nil {
|
||||||
|
return "", &PathError{Op: "readlinkat", Path: name, Err: err}
|
||||||
|
diff --git a/src/os/root_openat.go b/src/os/root_openat.go
|
||||||
|
index e433bd50..cfc6d906 100644
|
||||||
|
--- a/src/os/root_openat.go
|
||||||
|
+++ b/src/os/root_openat.go
|
||||||
|
@@ -194,28 +194,6 @@ func rootRemove(r *Root, name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
-func rootRemoveAll(r *Root, name string) error {
|
||||||
|
- // Consistency with os.RemoveAll: Strip trailing /s from the name,
|
||||||
|
- // so RemoveAll("not_a_directory/") succeeds.
|
||||||
|
- for len(name) > 0 && IsPathSeparator(name[len(name)-1]) {
|
||||||
|
- name = name[:len(name)-1]
|
||||||
|
- }
|
||||||
|
- if endsWithDot(name) {
|
||||||
|
- // Consistency with os.RemoveAll: Return EINVAL when trying to remove .
|
||||||
|
- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
|
||||||
|
- }
|
||||||
|
- _, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) {
|
||||||
|
- return struct{}{}, removeAllFrom(parent, name)
|
||||||
|
- })
|
||||||
|
- if IsNotExist(err) {
|
||||||
|
- return nil
|
||||||
|
- }
|
||||||
|
- if err != nil {
|
||||||
|
- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
|
||||||
|
- }
|
||||||
|
- return err
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
func rootRename(r *Root, oldname, newname string) error {
|
||||||
|
_, err := doInRoot(r, oldname, nil, func(oldparent sysfdType, oldname string) (struct{}, error) {
|
||||||
|
_, err := doInRoot(r, newname, nil, func(newparent sysfdType, newname string) (struct{}, error) {
|
||||||
|
--
|
||||||
|
2.50.1.windows.1
|
||||||
|
|
||||||
8368
patches/0007-Drop-public-And-Or-ops-and-race-instrumentation.patch
Normal file
8368
patches/0007-Drop-public-And-Or-ops-and-race-instrumentation.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
From c63f37858041ffd2bcf751f57632c90d630eddc2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
|
||||||
|
Date: Thu, 18 Sep 2025 12:01:09 +0800
|
||||||
|
Subject: [PATCH] Replace atomic Or with compare-and-swap loop
|
||||||
|
|
||||||
|
---
|
||||||
|
src/sync/waitgroup.go | 17 +++++++++++++----
|
||||||
|
1 file changed, 13 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go
|
||||||
|
index 5b035aa3..8aeae7bf 100644
|
||||||
|
--- a/src/sync/waitgroup.go
|
||||||
|
+++ b/src/sync/waitgroup.go
|
||||||
|
@@ -94,10 +94,19 @@ func (wg *WaitGroup) Add(delta int) {
|
||||||
|
fatal("sync: WaitGroup.Add called from multiple synctest bubbles")
|
||||||
|
case synctest.CurrentBubble:
|
||||||
|
bubbled = true
|
||||||
|
- 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")
|
||||||
|
+ // Use compare-and-swap loop to implement atomic Or operation
|
||||||
|
+ // since race detector doesn't have __tsan_go_atomic64_fetch_or
|
||||||
|
+ for {
|
||||||
|
+ old := wg.state.Load()
|
||||||
|
+ new := old | waitGroupBubbleFlag
|
||||||
|
+ if wg.state.CompareAndSwap(old, new) {
|
||||||
|
+ state := old
|
||||||
|
+ 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")
|
||||||
|
+ }
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.47.2
|
||||||
|
|
||||||
@@ -109,6 +109,9 @@ func ModIsPrefix(path, vers string) bool {
|
|||||||
// The caller is assumed to have checked that ModIsValid(path, vers) is true.
|
// The caller is assumed to have checked that ModIsValid(path, vers) is true.
|
||||||
func ModIsPrerelease(path, vers string) bool {
|
func ModIsPrerelease(path, vers string) bool {
|
||||||
if IsToolchain(path) {
|
if IsToolchain(path) {
|
||||||
|
if path == "toolchain" {
|
||||||
|
return IsPrerelease(FromToolchain(vers))
|
||||||
|
}
|
||||||
return IsPrerelease(vers)
|
return IsPrerelease(vers)
|
||||||
}
|
}
|
||||||
return semver.Prerelease(vers) != ""
|
return semver.Prerelease(vers) != ""
|
||||||
|
|||||||
10
src/cmd/go/testdata/script/mod_get_toolchain.txt
vendored
10
src/cmd/go/testdata/script/mod_get_toolchain.txt
vendored
@@ -94,12 +94,14 @@ stderr '^go: added toolchain go1.24rc1$'
|
|||||||
grep 'go 1.22.9' go.mod # no longer implied
|
grep 'go 1.22.9' go.mod # no longer implied
|
||||||
grep 'toolchain go1.24rc1' go.mod
|
grep 'toolchain go1.24rc1' go.mod
|
||||||
|
|
||||||
# go get toolchain@latest finds go1.999testmod.
|
# go get toolchain@latest finds go1.23.9.
|
||||||
cp go.mod.orig go.mod
|
cp go.mod.orig go.mod
|
||||||
go get toolchain@latest
|
go get toolchain@latest
|
||||||
stderr '^go: added toolchain go1.999testmod$'
|
stderr '^go: added toolchain go1.23.9$'
|
||||||
grep 'go 1.21' go.mod
|
grep 'go 1.21' go.mod
|
||||||
grep 'toolchain go1.999testmod' go.mod
|
grep 'toolchain go1.23.9' go.mod
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Bug fixes.
|
# Bug fixes.
|
||||||
|
|
||||||
@@ -115,7 +117,7 @@ stderr '^go: upgraded go 1.19 => 1.21.0'
|
|||||||
|
|
||||||
# go get toolchain@1.24rc1 is OK too.
|
# go get toolchain@1.24rc1 is OK too.
|
||||||
go get toolchain@1.24rc1
|
go get toolchain@1.24rc1
|
||||||
stderr '^go: downgraded toolchain go1.999testmod => go1.24rc1$'
|
stderr '^go: upgraded toolchain go1.23.9 => go1.24rc1$'
|
||||||
|
|
||||||
# go get go@1.21 should work if we are the Go 1.21 language version,
|
# go get go@1.21 should work if we are the Go 1.21 language version,
|
||||||
# even though there's no toolchain for it.
|
# even though there's no toolchain for it.
|
||||||
|
|||||||
@@ -1106,6 +1106,12 @@ func (fd *FD) Seek(offset int64, whence int) (int64, error) {
|
|||||||
fd.l.Lock()
|
fd.l.Lock()
|
||||||
defer fd.l.Unlock()
|
defer fd.l.Unlock()
|
||||||
|
|
||||||
|
if !fd.isBlocking && whence == io.SeekCurrent {
|
||||||
|
// Windows doesn't keep the file pointer for overlapped file handles.
|
||||||
|
// We do it ourselves in case to account for any read or write
|
||||||
|
// operations that may have occurred.
|
||||||
|
offset += fd.offset
|
||||||
|
}
|
||||||
n, err := syscall.Seek(fd.Sysfd, offset, whence)
|
n, err := syscall.Seek(fd.Sysfd, offset, whence)
|
||||||
fd.setOffset(n)
|
fd.setOffset(n)
|
||||||
return n, err
|
return n, err
|
||||||
|
|||||||
@@ -383,57 +383,59 @@ func TestChannelMovedOutOfBubble(t *testing.T) {
|
|||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
desc string
|
desc string
|
||||||
f func(chan struct{})
|
f func(chan struct{})
|
||||||
wantPanic string
|
wantFatal string
|
||||||
}{{
|
}{{
|
||||||
desc: "receive",
|
desc: "receive",
|
||||||
f: func(ch chan struct{}) {
|
f: func(ch chan struct{}) {
|
||||||
<-ch
|
<-ch
|
||||||
},
|
},
|
||||||
wantPanic: "receive on synctest channel from outside bubble",
|
wantFatal: "receive on synctest channel from outside bubble",
|
||||||
}, {
|
}, {
|
||||||
desc: "send",
|
desc: "send",
|
||||||
f: func(ch chan struct{}) {
|
f: func(ch chan struct{}) {
|
||||||
ch <- struct{}{}
|
ch <- struct{}{}
|
||||||
},
|
},
|
||||||
wantPanic: "send on synctest channel from outside bubble",
|
wantFatal: "send on synctest channel from outside bubble",
|
||||||
}, {
|
}, {
|
||||||
desc: "close",
|
desc: "close",
|
||||||
f: func(ch chan struct{}) {
|
f: func(ch chan struct{}) {
|
||||||
close(ch)
|
close(ch)
|
||||||
},
|
},
|
||||||
wantPanic: "close of synctest channel from outside bubble",
|
wantFatal: "close of synctest channel from outside bubble",
|
||||||
}} {
|
}} {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
// Bubbled channel accessed from outside any bubble.
|
// Bubbled channel accessed from outside any bubble.
|
||||||
t.Run("outside_bubble", func(t *testing.T) {
|
t.Run("outside_bubble", func(t *testing.T) {
|
||||||
donec := make(chan struct{})
|
wantFatal(t, test.wantFatal, func() {
|
||||||
ch := make(chan chan struct{})
|
donec := make(chan struct{})
|
||||||
go func() {
|
ch := make(chan chan struct{})
|
||||||
defer close(donec)
|
go func() {
|
||||||
defer wantPanic(t, test.wantPanic)
|
defer close(donec)
|
||||||
test.f(<-ch)
|
test.f(<-ch)
|
||||||
}()
|
}()
|
||||||
synctest.Run(func() {
|
synctest.Run(func() {
|
||||||
ch <- make(chan struct{})
|
ch <- make(chan struct{})
|
||||||
|
})
|
||||||
|
<-donec
|
||||||
})
|
})
|
||||||
<-donec
|
|
||||||
})
|
})
|
||||||
// Bubbled channel accessed from a different bubble.
|
// Bubbled channel accessed from a different bubble.
|
||||||
t.Run("different_bubble", func(t *testing.T) {
|
t.Run("different_bubble", func(t *testing.T) {
|
||||||
donec := make(chan struct{})
|
wantFatal(t, test.wantFatal, func() {
|
||||||
ch := make(chan chan struct{})
|
donec := make(chan struct{})
|
||||||
go func() {
|
ch := make(chan chan struct{})
|
||||||
defer close(donec)
|
go func() {
|
||||||
c := <-ch
|
defer close(donec)
|
||||||
|
c := <-ch
|
||||||
|
synctest.Run(func() {
|
||||||
|
test.f(c)
|
||||||
|
})
|
||||||
|
}()
|
||||||
synctest.Run(func() {
|
synctest.Run(func() {
|
||||||
defer wantPanic(t, test.wantPanic)
|
ch <- make(chan struct{})
|
||||||
test.f(c)
|
|
||||||
})
|
})
|
||||||
}()
|
<-donec
|
||||||
synctest.Run(func() {
|
|
||||||
ch <- make(chan struct{})
|
|
||||||
})
|
})
|
||||||
<-donec
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -443,39 +445,40 @@ func TestTimerFromInsideBubble(t *testing.T) {
|
|||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
desc string
|
desc string
|
||||||
f func(tm *time.Timer)
|
f func(tm *time.Timer)
|
||||||
wantPanic string
|
wantFatal string
|
||||||
}{{
|
}{{
|
||||||
desc: "read channel",
|
desc: "read channel",
|
||||||
f: func(tm *time.Timer) {
|
f: func(tm *time.Timer) {
|
||||||
<-tm.C
|
<-tm.C
|
||||||
},
|
},
|
||||||
wantPanic: "receive on synctest channel from outside bubble",
|
wantFatal: "receive on synctest channel from outside bubble",
|
||||||
}, {
|
}, {
|
||||||
desc: "Reset",
|
desc: "Reset",
|
||||||
f: func(tm *time.Timer) {
|
f: func(tm *time.Timer) {
|
||||||
tm.Reset(1 * time.Second)
|
tm.Reset(1 * time.Second)
|
||||||
},
|
},
|
||||||
wantPanic: "reset of synctest timer from outside bubble",
|
wantFatal: "reset of synctest timer from outside bubble",
|
||||||
}, {
|
}, {
|
||||||
desc: "Stop",
|
desc: "Stop",
|
||||||
f: func(tm *time.Timer) {
|
f: func(tm *time.Timer) {
|
||||||
tm.Stop()
|
tm.Stop()
|
||||||
},
|
},
|
||||||
wantPanic: "stop of synctest timer from outside bubble",
|
wantFatal: "stop of synctest timer from outside bubble",
|
||||||
}} {
|
}} {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
donec := make(chan struct{})
|
wantFatal(t, test.wantFatal, func() {
|
||||||
ch := make(chan *time.Timer)
|
donec := make(chan struct{})
|
||||||
go func() {
|
ch := make(chan *time.Timer)
|
||||||
defer close(donec)
|
go func() {
|
||||||
defer wantPanic(t, test.wantPanic)
|
defer close(donec)
|
||||||
test.f(<-ch)
|
test.f(<-ch)
|
||||||
}()
|
}()
|
||||||
synctest.Run(func() {
|
synctest.Run(func() {
|
||||||
tm := time.NewTimer(1 * time.Second)
|
tm := time.NewTimer(1 * time.Second)
|
||||||
ch <- tm
|
ch <- tm
|
||||||
|
})
|
||||||
|
<-donec
|
||||||
})
|
})
|
||||||
<-donec
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,13 +77,21 @@ func (c *CrossOriginProtection) AddTrustedOrigin(origin string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var noopHandler = HandlerFunc(func(w ResponseWriter, r *Request) {})
|
type noopHandler struct{}
|
||||||
|
|
||||||
|
func (noopHandler) ServeHTTP(ResponseWriter, *Request) {}
|
||||||
|
|
||||||
|
var sentinelHandler Handler = &noopHandler{}
|
||||||
|
|
||||||
// AddInsecureBypassPattern permits all requests that match the given pattern.
|
// AddInsecureBypassPattern permits all requests that match the given pattern.
|
||||||
// The pattern syntax and precedence rules are the same as [ServeMux].
|
|
||||||
//
|
//
|
||||||
// AddInsecureBypassPattern can be called concurrently with other methods
|
// The pattern syntax and precedence rules are the same as [ServeMux]. Only
|
||||||
// or request handling, and applies to future requests.
|
// requests that match the pattern directly are permitted. Those that ServeMux
|
||||||
|
// would redirect to a pattern (e.g. after cleaning the path or adding a
|
||||||
|
// trailing slash) are not.
|
||||||
|
//
|
||||||
|
// AddInsecureBypassPattern can be called concurrently with other methods or
|
||||||
|
// request handling, and applies to future requests.
|
||||||
func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) {
|
func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) {
|
||||||
var bypass *ServeMux
|
var bypass *ServeMux
|
||||||
|
|
||||||
@@ -99,7 +107,7 @@ func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bypass.Handle(pattern, noopHandler)
|
bypass.Handle(pattern, sentinelHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDenyHandler sets a handler to invoke when a request is rejected.
|
// SetDenyHandler sets a handler to invoke when a request is rejected.
|
||||||
@@ -172,7 +180,7 @@ var (
|
|||||||
// be deferred until the last moment.
|
// be deferred until the last moment.
|
||||||
func (c *CrossOriginProtection) isRequestExempt(req *Request) bool {
|
func (c *CrossOriginProtection) isRequestExempt(req *Request) bool {
|
||||||
if bypass := c.bypass.Load(); bypass != nil {
|
if bypass := c.bypass.Load(); bypass != nil {
|
||||||
if _, pattern := bypass.Handler(req); pattern != "" {
|
if h, _ := bypass.Handler(req); h == sentinelHandler {
|
||||||
// The request matches a bypass pattern.
|
// The request matches a bypass pattern.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,11 @@ func TestCrossOriginProtectionPatternBypass(t *testing.T) {
|
|||||||
protection := http.NewCrossOriginProtection()
|
protection := http.NewCrossOriginProtection()
|
||||||
protection.AddInsecureBypassPattern("/bypass/")
|
protection.AddInsecureBypassPattern("/bypass/")
|
||||||
protection.AddInsecureBypassPattern("/only/{foo}")
|
protection.AddInsecureBypassPattern("/only/{foo}")
|
||||||
|
protection.AddInsecureBypassPattern("/no-trailing")
|
||||||
|
protection.AddInsecureBypassPattern("/yes-trailing/")
|
||||||
|
protection.AddInsecureBypassPattern("PUT /put-only/")
|
||||||
|
protection.AddInsecureBypassPattern("GET /get-only/")
|
||||||
|
protection.AddInsecureBypassPattern("POST /post-only/")
|
||||||
handler := protection.Handler(okHandler)
|
handler := protection.Handler(okHandler)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -126,13 +131,23 @@ func TestCrossOriginProtectionPatternBypass(t *testing.T) {
|
|||||||
{"non-bypass path without sec-fetch-site", "/api/", "", http.StatusForbidden},
|
{"non-bypass path without sec-fetch-site", "/api/", "", http.StatusForbidden},
|
||||||
{"non-bypass path with cross-site", "/api/", "cross-site", http.StatusForbidden},
|
{"non-bypass path with cross-site", "/api/", "cross-site", http.StatusForbidden},
|
||||||
|
|
||||||
{"redirect to bypass path without ..", "/foo/../bypass/bar", "", http.StatusOK},
|
{"redirect to bypass path without ..", "/foo/../bypass/bar", "", http.StatusForbidden},
|
||||||
{"redirect to bypass path with trailing slash", "/bypass", "", http.StatusOK},
|
{"redirect to bypass path with trailing slash", "/bypass", "", http.StatusForbidden},
|
||||||
{"redirect to non-bypass path with ..", "/foo/../api/bar", "", http.StatusForbidden},
|
{"redirect to non-bypass path with ..", "/foo/../api/bar", "", http.StatusForbidden},
|
||||||
{"redirect to non-bypass path with trailing slash", "/api", "", http.StatusForbidden},
|
{"redirect to non-bypass path with trailing slash", "/api", "", http.StatusForbidden},
|
||||||
|
|
||||||
{"wildcard bypass", "/only/123", "", http.StatusOK},
|
{"wildcard bypass", "/only/123", "", http.StatusOK},
|
||||||
{"non-wildcard", "/only/123/foo", "", http.StatusForbidden},
|
{"non-wildcard", "/only/123/foo", "", http.StatusForbidden},
|
||||||
|
|
||||||
|
// https://go.dev/issue/75054
|
||||||
|
{"no trailing slash exact match", "/no-trailing", "", http.StatusOK},
|
||||||
|
{"no trailing slash with slash", "/no-trailing/", "", http.StatusForbidden},
|
||||||
|
{"yes trailing slash exact match", "/yes-trailing/", "", http.StatusOK},
|
||||||
|
{"yes trailing slash without slash", "/yes-trailing", "", http.StatusForbidden},
|
||||||
|
|
||||||
|
{"method-specific hit", "/post-only/", "", http.StatusOK},
|
||||||
|
{"method-specific miss (PUT)", "/put-only/", "", http.StatusForbidden},
|
||||||
|
{"method-specific miss (GET)", "/get-only/", "", http.StatusForbidden},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
|
|||||||
@@ -237,8 +237,12 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
|
|||||||
func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
|
func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
|
||||||
// ipToSockaddrInet4 has special handling here for zero length slices.
|
// ipToSockaddrInet4 has special handling here for zero length slices.
|
||||||
// We do not, because netip has no concept of a generic zero IP address.
|
// We do not, because netip has no concept of a generic zero IP address.
|
||||||
|
//
|
||||||
|
// addr is allowed to be an IPv4-mapped IPv6 address.
|
||||||
|
// As4 will unmap it to an IPv4 address.
|
||||||
|
// The error message is kept consistent with ipToSockaddrInet4.
|
||||||
addr := ap.Addr()
|
addr := ap.Addr()
|
||||||
if !addr.Is4() {
|
if !addr.Is4() && !addr.Is4In6() {
|
||||||
return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()}
|
return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()}
|
||||||
}
|
}
|
||||||
sa := syscall.SockaddrInet4{
|
sa := syscall.SockaddrInet4{
|
||||||
|
|||||||
@@ -705,3 +705,35 @@ func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
|
||||||
|
// WriteMsgUDPAddrPort accepts IPv4 and IPv4-mapped IPv6 destination addresses,
|
||||||
|
// and rejects IPv6 destination addresses on a "udp4" connection.
|
||||||
|
func TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
|
||||||
|
if !testableNetwork("udp4") {
|
||||||
|
t.Skipf("skipping: udp4 not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
|
||||||
|
daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
|
||||||
|
daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
|
||||||
|
if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4); err != nil {
|
||||||
|
t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4) failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6); err != nil {
|
||||||
|
t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6) failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6); err == nil {
|
||||||
|
t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr6) should have failed, but got no error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func findExecutable(file string) error {
|
|||||||
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
|
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
|
||||||
// [errors.Is](err, [ErrDot]). See the package documentation for more details.
|
// [errors.Is](err, [ErrDot]). See the package documentation for more details.
|
||||||
func LookPath(file string) (string, error) {
|
func LookPath(file string) (string, error) {
|
||||||
if err := validateLookPath(file); err != nil {
|
if err := validateLookPath(filepath.Clean(file)); err != nil {
|
||||||
return "", &Error{file, err}
|
return "", &Error{file, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1845,6 +1845,44 @@ func TestFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileOverlappedSeek(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
name := filepath.Join(t.TempDir(), "foo")
|
||||||
|
f := newFileOverlapped(t, name, true)
|
||||||
|
content := []byte("foo")
|
||||||
|
if _, err := f.Write(content); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Check that the file pointer is at the expected offset.
|
||||||
|
n, err := f.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if n != int64(len(content)) {
|
||||||
|
t.Errorf("expected file pointer to be at offset %d, got %d", len(content), n)
|
||||||
|
}
|
||||||
|
// Set the file pointer to the start of the file.
|
||||||
|
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Read the first byte.
|
||||||
|
var buf [1]byte
|
||||||
|
if _, err := f.Read(buf[:]); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(buf[:], content[:len(buf)]) {
|
||||||
|
t.Errorf("expected %q, got %q", content[:len(buf)], buf[:])
|
||||||
|
}
|
||||||
|
// Check that the file pointer is at the expected offset.
|
||||||
|
n, err = f.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if n != int64(len(buf)) {
|
||||||
|
t.Errorf("expected file pointer to be at offset %d, got %d", len(buf), n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPipe(t *testing.T) {
|
func TestPipe(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
r, w, err := os.Pipe()
|
r, w, err := os.Pipe()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build unix || wasip1 || windows
|
//go:build unix || wasip1
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build (js && wasm) || plan9
|
//go:build (js && wasm) || plan9 || windows
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
@@ -189,12 +189,6 @@ func (r *Root) Remove(name string) error {
|
|||||||
return rootRemove(r, name)
|
return rootRemove(r, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAll removes the named file or directory and any children that it contains.
|
|
||||||
// See [RemoveAll] for more details.
|
|
||||||
func (r *Root) RemoveAll(name string) error {
|
|
||||||
return rootRemoveAll(r, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat returns a [FileInfo] describing the named file in the root.
|
// Stat returns a [FileInfo] describing the named file in the root.
|
||||||
// See [Stat] for more details.
|
// See [Stat] for more details.
|
||||||
func (r *Root) Stat(name string) (FileInfo, error) {
|
func (r *Root) Stat(name string) (FileInfo, error) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"internal/filepathlite"
|
"internal/filepathlite"
|
||||||
"internal/stringslite"
|
"internal/stringslite"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -186,25 +185,6 @@ func rootRemove(r *Root, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rootRemoveAll(r *Root, name string) error {
|
|
||||||
if endsWithDot(name) {
|
|
||||||
// Consistency with os.RemoveAll: Return EINVAL when trying to remove .
|
|
||||||
return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
|
|
||||||
}
|
|
||||||
if err := checkPathEscapesLstat(r, name); err != nil {
|
|
||||||
if err == syscall.ENOTDIR {
|
|
||||||
// Some intermediate path component is not a directory.
|
|
||||||
// RemoveAll treats this as success (since the target doesn't exist).
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &PathError{Op: "RemoveAll", Path: name, Err: err}
|
|
||||||
}
|
|
||||||
if err := RemoveAll(joinPath(r.root.name, name)); err != nil {
|
|
||||||
return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rootReadlink(r *Root, name string) (string, error) {
|
func rootReadlink(r *Root, name string) (string, error) {
|
||||||
if err := checkPathEscapesLstat(r, name); err != nil {
|
if err := checkPathEscapesLstat(r, name); err != nil {
|
||||||
return "", &PathError{Op: "readlinkat", Path: name, Err: err}
|
return "", &PathError{Op: "readlinkat", Path: name, Err: err}
|
||||||
|
|||||||
@@ -194,28 +194,6 @@ func rootRemove(r *Root, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rootRemoveAll(r *Root, name string) error {
|
|
||||||
// Consistency with os.RemoveAll: Strip trailing /s from the name,
|
|
||||||
// so RemoveAll("not_a_directory/") succeeds.
|
|
||||||
for len(name) > 0 && IsPathSeparator(name[len(name)-1]) {
|
|
||||||
name = name[:len(name)-1]
|
|
||||||
}
|
|
||||||
if endsWithDot(name) {
|
|
||||||
// Consistency with os.RemoveAll: Return EINVAL when trying to remove .
|
|
||||||
return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
|
|
||||||
}
|
|
||||||
_, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) {
|
|
||||||
return struct{}{}, removeAllFrom(parent, name)
|
|
||||||
})
|
|
||||||
if IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func rootRename(r *Root, oldname, newname string) error {
|
func rootRename(r *Root, oldname, newname string) error {
|
||||||
_, err := doInRoot(r, oldname, nil, func(oldparent sysfdType, oldname string) (struct{}, error) {
|
_, err := doInRoot(r, oldname, nil, func(oldparent sysfdType, oldname string) (struct{}, error) {
|
||||||
_, err := doInRoot(r, newname, nil, func(newparent sysfdType, newname string) (struct{}, error) {
|
_, err := doInRoot(r, newname, nil, func(newparent sysfdType, newname string) (struct{}, error) {
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.bubble != nil && getg().bubble != c.bubble {
|
if c.bubble != nil && getg().bubble != c.bubble {
|
||||||
panic(plainError("send on synctest channel from outside bubble"))
|
fatal("send on synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path: check for failed non-blocking operation without acquiring the lock.
|
// Fast path: check for failed non-blocking operation without acquiring the lock.
|
||||||
@@ -318,7 +318,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
|
|||||||
func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
|
func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
|
||||||
if c.bubble != nil && getg().bubble != c.bubble {
|
if c.bubble != nil && getg().bubble != c.bubble {
|
||||||
unlockf()
|
unlockf()
|
||||||
panic(plainError("send on synctest channel from outside bubble"))
|
fatal("send on synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
if c.dataqsiz == 0 {
|
if c.dataqsiz == 0 {
|
||||||
@@ -416,7 +416,7 @@ func closechan(c *hchan) {
|
|||||||
panic(plainError("close of nil channel"))
|
panic(plainError("close of nil channel"))
|
||||||
}
|
}
|
||||||
if c.bubble != nil && getg().bubble != c.bubble {
|
if c.bubble != nil && getg().bubble != c.bubble {
|
||||||
panic(plainError("close of synctest channel from outside bubble"))
|
fatal("close of synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
|
|
||||||
lock(&c.lock)
|
lock(&c.lock)
|
||||||
@@ -538,7 +538,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.bubble != nil && getg().bubble != c.bubble {
|
if c.bubble != nil && getg().bubble != c.bubble {
|
||||||
panic(plainError("receive on synctest channel from outside bubble"))
|
fatal("receive on synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.timer != nil {
|
if c.timer != nil {
|
||||||
@@ -702,7 +702,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
|
|||||||
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
|
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
|
||||||
if c.bubble != nil && getg().bubble != c.bubble {
|
if c.bubble != nil && getg().bubble != c.bubble {
|
||||||
unlockf()
|
unlockf()
|
||||||
panic(plainError("receive on synctest channel from outside bubble"))
|
fatal("receive on synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
if c.dataqsiz == 0 {
|
if c.dataqsiz == 0 {
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
|
|||||||
@@ -406,10 +406,6 @@ var __tsan_report_count byte
|
|||||||
//go:cgo_import_static __tsan_go_atomic64_exchange
|
//go:cgo_import_static __tsan_go_atomic64_exchange
|
||||||
//go:cgo_import_static __tsan_go_atomic32_fetch_add
|
//go:cgo_import_static __tsan_go_atomic32_fetch_add
|
||||||
//go:cgo_import_static __tsan_go_atomic64_fetch_add
|
//go:cgo_import_static __tsan_go_atomic64_fetch_add
|
||||||
//go:cgo_import_static __tsan_go_atomic32_fetch_and
|
|
||||||
//go:cgo_import_static __tsan_go_atomic64_fetch_and
|
|
||||||
//go:cgo_import_static __tsan_go_atomic32_fetch_or
|
|
||||||
//go:cgo_import_static __tsan_go_atomic64_fetch_or
|
|
||||||
//go:cgo_import_static __tsan_go_atomic32_compare_exchange
|
//go:cgo_import_static __tsan_go_atomic32_compare_exchange
|
||||||
//go:cgo_import_static __tsan_go_atomic64_compare_exchange
|
//go:cgo_import_static __tsan_go_atomic64_compare_exchange
|
||||||
|
|
||||||
@@ -738,36 +734,6 @@ func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64)
|
|||||||
//go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr
|
//go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr
|
||||||
func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
|
func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_AndInt32 sync/atomic.AndInt32
|
|
||||||
func abigen_sync_atomic_AndInt32(addr *int32, mask int32) (old int32)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_AndUint32 sync/atomic.AndUint32
|
|
||||||
func abigen_sync_atomic_AndUint32(addr *uint32, mask uint32) (old uint32)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_AndInt64 sync/atomic.AndInt64
|
|
||||||
func abigen_sync_atomic_AndInt64(addr *int64, mask int64) (old int64)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_AndUint64 sync/atomic.AndUint64
|
|
||||||
func abigen_sync_atomic_AndUint64(addr *uint64, mask uint64) (old uint64)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_AndUintptr sync/atomic.AndUintptr
|
|
||||||
func abigen_sync_atomic_AndUintptr(addr *uintptr, mask uintptr) (old uintptr)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_OrInt32 sync/atomic.OrInt32
|
|
||||||
func abigen_sync_atomic_OrInt32(addr *int32, mask int32) (old int32)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_OrUint32 sync/atomic.OrUint32
|
|
||||||
func abigen_sync_atomic_OrUint32(addr *uint32, mask uint32) (old uint32)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_OrInt64 sync/atomic.OrInt64
|
|
||||||
func abigen_sync_atomic_OrInt64(addr *int64, mask int64) (old int64)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_OrUint64 sync/atomic.OrUint64
|
|
||||||
func abigen_sync_atomic_OrUint64(addr *uint64, mask uint64) (old uint64)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_OrUintptr sync/atomic.OrUintptr
|
|
||||||
func abigen_sync_atomic_OrUintptr(addr *uintptr, mask uintptr) (old uintptr)
|
|
||||||
|
|
||||||
//go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32
|
//go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32
|
||||||
func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
|
func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -303,57 +303,6 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
|
|||||||
GO_ARGS
|
GO_ARGS
|
||||||
JMP sync∕atomic·AddInt64(SB)
|
JMP sync∕atomic·AddInt64(SB)
|
||||||
|
|
||||||
// And
|
|
||||||
TEXT sync∕atomic·AndInt32(SB), NOSPLIT|NOFRAME, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVQ $__tsan_go_atomic32_fetch_and(SB), AX
|
|
||||||
CALL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndInt64(SB), NOSPLIT|NOFRAME, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVQ $__tsan_go_atomic64_fetch_and(SB), AX
|
|
||||||
CALL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
// Or
|
|
||||||
TEXT sync∕atomic·OrInt32(SB), NOSPLIT|NOFRAME, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVQ $__tsan_go_atomic32_fetch_or(SB), AX
|
|
||||||
CALL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrInt64(SB), NOSPLIT|NOFRAME, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVQ $__tsan_go_atomic64_fetch_or(SB), AX
|
|
||||||
CALL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
|
|
||||||
// CompareAndSwap
|
// CompareAndSwap
|
||||||
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT|NOFRAME, $0-17
|
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT|NOFRAME, $0-17
|
||||||
GO_ARGS
|
GO_ARGS
|
||||||
|
|||||||
@@ -312,56 +312,6 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
|
|||||||
GO_ARGS
|
GO_ARGS
|
||||||
JMP sync∕atomic·AddInt64(SB)
|
JMP sync∕atomic·AddInt64(SB)
|
||||||
|
|
||||||
// And
|
|
||||||
TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_and(SB), R9
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_and(SB), R9
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
// Or
|
|
||||||
TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_or(SB), R9
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_or(SB), R9
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
// CompareAndSwap
|
// CompareAndSwap
|
||||||
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
||||||
GO_ARGS
|
GO_ARGS
|
||||||
|
|||||||
@@ -325,52 +325,6 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
|
|||||||
GO_ARGS
|
GO_ARGS
|
||||||
BR sync∕atomic·AddInt64(SB)
|
BR sync∕atomic·AddInt64(SB)
|
||||||
|
|
||||||
// And
|
|
||||||
TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_and(SB), R8
|
|
||||||
BR racecallatomic<>(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_and(SB), R8
|
|
||||||
BR racecallatomic<>(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·AndInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
// Or
|
|
||||||
TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_or(SB), R8
|
|
||||||
BR racecallatomic<>(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_or(SB), R8
|
|
||||||
BR racecallatomic<>(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·OrInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
BR sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
// CompareAndSwap in tsan
|
// CompareAndSwap in tsan
|
||||||
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
||||||
GO_ARGS
|
GO_ARGS
|
||||||
|
|||||||
@@ -274,56 +274,6 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
|
|||||||
GO_ARGS
|
GO_ARGS
|
||||||
JMP sync∕atomic·AddInt64(SB)
|
JMP sync∕atomic·AddInt64(SB)
|
||||||
|
|
||||||
// And
|
|
||||||
TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_and(SB), R1
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_and(SB), R1
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·AndInt64(SB)
|
|
||||||
|
|
||||||
// Or
|
|
||||||
TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic32_fetch_or(SB), R1
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
MOVD $__tsan_go_atomic64_fetch_or(SB), R1
|
|
||||||
BL racecallatomic<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt32(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
|
|
||||||
GO_ARGS
|
|
||||||
JMP sync∕atomic·OrInt64(SB)
|
|
||||||
|
|
||||||
// CompareAndSwap
|
// CompareAndSwap
|
||||||
|
|
||||||
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
|
|||||||
|
|
||||||
if cas.c.bubble != nil {
|
if cas.c.bubble != nil {
|
||||||
if getg().bubble != cas.c.bubble {
|
if getg().bubble != cas.c.bubble {
|
||||||
panic(plainError("select on synctest channel from outside bubble"))
|
fatal("select on synctest channel from outside bubble")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
allSynctest = false
|
allSynctest = false
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ func newTimer(when, period int64, f func(arg any, seq uintptr, delay int64), arg
|
|||||||
//go:linkname stopTimer time.stopTimer
|
//go:linkname stopTimer time.stopTimer
|
||||||
func stopTimer(t *timeTimer) bool {
|
func stopTimer(t *timeTimer) bool {
|
||||||
if t.isFake && getg().bubble == nil {
|
if t.isFake && getg().bubble == nil {
|
||||||
panic("stop of synctest timer from outside bubble")
|
fatal("stop of synctest timer from outside bubble")
|
||||||
}
|
}
|
||||||
return t.stop()
|
return t.stop()
|
||||||
}
|
}
|
||||||
@@ -430,7 +430,7 @@ func resetTimer(t *timeTimer, when, period int64) bool {
|
|||||||
racerelease(unsafe.Pointer(&t.timer))
|
racerelease(unsafe.Pointer(&t.timer))
|
||||||
}
|
}
|
||||||
if t.isFake && getg().bubble == nil {
|
if t.isFake && getg().bubble == nil {
|
||||||
panic("reset of synctest timer from outside bubble")
|
fatal("reset of synctest timer from outside bubble")
|
||||||
}
|
}
|
||||||
return t.reset(when, period)
|
return t.reset(when, period)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,33 +83,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
|
|||||||
|
|
||||||
TEXT ·StoreUintptr(SB),NOSPLIT,$0
|
TEXT ·StoreUintptr(SB),NOSPLIT,$0
|
||||||
JMP internal∕runtime∕atomic·Storeuintptr(SB)
|
JMP internal∕runtime∕atomic·Storeuintptr(SB)
|
||||||
|
|
||||||
TEXT ·AndInt32(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·And32(SB)
|
|
||||||
|
|
||||||
TEXT ·AndUint32(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·And32(SB)
|
|
||||||
|
|
||||||
TEXT ·AndUintptr(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Anduintptr(SB)
|
|
||||||
|
|
||||||
TEXT ·AndInt64(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·And64(SB)
|
|
||||||
|
|
||||||
TEXT ·AndUint64(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·And64(SB)
|
|
||||||
|
|
||||||
TEXT ·OrInt32(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Or32(SB)
|
|
||||||
|
|
||||||
TEXT ·OrUint32(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Or32(SB)
|
|
||||||
|
|
||||||
TEXT ·OrUintptr(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Oruintptr(SB)
|
|
||||||
|
|
||||||
TEXT ·OrInt64(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Or64(SB)
|
|
||||||
|
|
||||||
TEXT ·OrUint64(SB),NOSPLIT,$0
|
|
||||||
JMP internal∕runtime∕atomic·Or64(SB)
|
|
||||||
|
|||||||
@@ -531,472 +531,6 @@ func TestAddUintptrMethod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAndInt32(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int32
|
|
||||||
i int32
|
|
||||||
after int32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
x.i = -1
|
|
||||||
j := x.i
|
|
||||||
for mask := int32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := AndInt32(&x.i, ^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndInt32Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int32
|
|
||||||
i Int32
|
|
||||||
after int32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
x.i.Store(-1)
|
|
||||||
j := x.i.Load()
|
|
||||||
for mask := int32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.And(^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUint32(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint32
|
|
||||||
i uint32
|
|
||||||
after uint32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
x.i = 0xffffffff
|
|
||||||
j := x.i
|
|
||||||
for mask := uint32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := AndUint32(&x.i, ^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUint32Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint32
|
|
||||||
i Uint32
|
|
||||||
after uint32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
x.i.Store(0xffffffff)
|
|
||||||
j := x.i.Load()
|
|
||||||
for mask := uint32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.And(^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndInt64(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int64
|
|
||||||
i int64
|
|
||||||
after int64
|
|
||||||
}
|
|
||||||
magic64 := int64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
x.i = -1
|
|
||||||
j := x.i
|
|
||||||
for mask := int64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := AndInt64(&x.i, ^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndInt64Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int64
|
|
||||||
i Int64
|
|
||||||
after int64
|
|
||||||
}
|
|
||||||
magic64 := int64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
x.i.Store(-1)
|
|
||||||
j := x.i.Load()
|
|
||||||
for mask := int64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.And(^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUint64(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint64
|
|
||||||
i uint64
|
|
||||||
after uint64
|
|
||||||
}
|
|
||||||
magic64 := uint64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
x.i = 0xfffffffffffffff
|
|
||||||
j := x.i
|
|
||||||
for mask := uint64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := AndUint64(&x.i, ^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUint64Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint64
|
|
||||||
i Uint64
|
|
||||||
after uint64
|
|
||||||
}
|
|
||||||
magic64 := uint64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
x.i.Store(0xfffffffffffffff)
|
|
||||||
j := x.i.Load()
|
|
||||||
for mask := uint64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.And(^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUintptr(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uintptr
|
|
||||||
i uintptr
|
|
||||||
after uintptr
|
|
||||||
}
|
|
||||||
var m uint64 = magic64
|
|
||||||
magicptr := uintptr(m)
|
|
||||||
x.before = magicptr
|
|
||||||
x.after = magicptr
|
|
||||||
x.i = ^uintptr(0)
|
|
||||||
j := x.i
|
|
||||||
for mask := uintptr(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := AndUintptr(&x.i, ^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magicptr || x.after != magicptr {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndUintptrMethod(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uintptr
|
|
||||||
i Uintptr
|
|
||||||
after uintptr
|
|
||||||
}
|
|
||||||
var m uint64 = magic64
|
|
||||||
magicptr := uintptr(m)
|
|
||||||
x.before = magicptr
|
|
||||||
x.after = magicptr
|
|
||||||
x.i.Store(^uintptr(0))
|
|
||||||
j := x.i.Load()
|
|
||||||
for mask := uintptr(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.And(^mask)
|
|
||||||
j &= ^mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magicptr || x.after != magicptr {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrInt32(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int32
|
|
||||||
i int32
|
|
||||||
after int32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
var j int32
|
|
||||||
for mask := int32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := OrInt32(&x.i, mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrInt32Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int32
|
|
||||||
i Int32
|
|
||||||
after int32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
var j int32
|
|
||||||
for mask := int32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.Or(mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUint32(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint32
|
|
||||||
i uint32
|
|
||||||
after uint32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
var j uint32
|
|
||||||
for mask := uint32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := OrUint32(&x.i, mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUint32Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint32
|
|
||||||
i Uint32
|
|
||||||
after uint32
|
|
||||||
}
|
|
||||||
x.before = magic32
|
|
||||||
x.after = magic32
|
|
||||||
var j uint32
|
|
||||||
for mask := uint32(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.Or(mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic32 || x.after != magic32 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrInt64(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int64
|
|
||||||
i int64
|
|
||||||
after int64
|
|
||||||
}
|
|
||||||
magic64 := int64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
var j int64
|
|
||||||
for mask := int64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := OrInt64(&x.i, mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrInt64Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before int64
|
|
||||||
i Int64
|
|
||||||
after int64
|
|
||||||
}
|
|
||||||
magic64 := int64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
var j int64
|
|
||||||
for mask := int64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.Or(mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUint64(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint64
|
|
||||||
i uint64
|
|
||||||
after uint64
|
|
||||||
}
|
|
||||||
magic64 := uint64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
var j uint64
|
|
||||||
for mask := uint64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := OrUint64(&x.i, mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUint64Method(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uint64
|
|
||||||
i Uint64
|
|
||||||
after uint64
|
|
||||||
}
|
|
||||||
magic64 := uint64(magic64)
|
|
||||||
x.before = magic64
|
|
||||||
x.after = magic64
|
|
||||||
var j uint64
|
|
||||||
for mask := uint64(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.Or(mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magic64 || x.after != magic64 {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUintptr(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uintptr
|
|
||||||
i uintptr
|
|
||||||
after uintptr
|
|
||||||
}
|
|
||||||
var m uint64 = magic64
|
|
||||||
magicptr := uintptr(m)
|
|
||||||
x.before = magicptr
|
|
||||||
x.after = magicptr
|
|
||||||
var j uintptr
|
|
||||||
for mask := uintptr(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i
|
|
||||||
k := OrUintptr(&x.i, mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magicptr || x.after != magicptr {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOrUintptrMethod(t *testing.T) {
|
|
||||||
var x struct {
|
|
||||||
before uintptr
|
|
||||||
i Uintptr
|
|
||||||
after uintptr
|
|
||||||
}
|
|
||||||
var m uint64 = magic64
|
|
||||||
magicptr := uintptr(m)
|
|
||||||
x.before = magicptr
|
|
||||||
x.after = magicptr
|
|
||||||
var j uintptr
|
|
||||||
for mask := uintptr(1); mask != 0; mask <<= 1 {
|
|
||||||
old := x.i.Load()
|
|
||||||
k := x.i.Or(mask)
|
|
||||||
j |= mask
|
|
||||||
if x.i.Load() != j || k != old {
|
|
||||||
t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x.before != magicptr || x.after != magicptr {
|
|
||||||
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompareAndSwapInt32(t *testing.T) {
|
func TestCompareAndSwapInt32(t *testing.T) {
|
||||||
var x struct {
|
var x struct {
|
||||||
before int32
|
before int32
|
||||||
|
|||||||
@@ -128,48 +128,6 @@ func AddUint32(addr *uint32, delta uint32) (new uint32)
|
|||||||
//go:noescape
|
//go:noescape
|
||||||
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
|
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
|
||||||
|
|
||||||
// AndInt32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Int32.And] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func AndInt32(addr *int32, mask int32) (old int32)
|
|
||||||
|
|
||||||
// AndUint32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Uint32.And] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func AndUint32(addr *uint32, mask uint32) (old uint32)
|
|
||||||
|
|
||||||
// AndUintptr atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Uintptr.And] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func AndUintptr(addr *uintptr, mask uintptr) (old uintptr)
|
|
||||||
|
|
||||||
// OrInt32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Int32.Or] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func OrInt32(addr *int32, mask int32) (old int32)
|
|
||||||
|
|
||||||
// OrUint32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Uint32.Or] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func OrUint32(addr *uint32, mask uint32) (old uint32)
|
|
||||||
|
|
||||||
// OrUintptr atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
|
|
||||||
// and returns the old value.
|
|
||||||
// Consider using the more ergonomic and less error-prone [Uintptr.Or] instead.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func OrUintptr(addr *uintptr, mask uintptr) (old uintptr)
|
|
||||||
|
|
||||||
// LoadInt32 atomically loads *addr.
|
// LoadInt32 atomically loads *addr.
|
||||||
// Consider using the more ergonomic and less error-prone [Int32.Load] instead.
|
// Consider using the more ergonomic and less error-prone [Int32.Load] instead.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -93,14 +93,6 @@ func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) {
|
|||||||
// Add atomically adds delta to x and returns the new value.
|
// Add atomically adds delta to x and returns the new value.
|
||||||
func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
|
func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
|
||||||
|
|
||||||
// And atomically performs a bitwise AND operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Int32) And(mask int32) (old int32) { return AndInt32(&x.v, mask) }
|
|
||||||
|
|
||||||
// Or atomically performs a bitwise OR operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Int32) Or(mask int32) (old int32) { return OrInt32(&x.v, mask) }
|
|
||||||
|
|
||||||
// An Int64 is an atomic int64. The zero value is zero.
|
// An Int64 is an atomic int64. The zero value is zero.
|
||||||
//
|
//
|
||||||
// Int64 must not be copied after first use.
|
// Int64 must not be copied after first use.
|
||||||
@@ -127,14 +119,6 @@ func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) {
|
|||||||
// Add atomically adds delta to x and returns the new value.
|
// Add atomically adds delta to x and returns the new value.
|
||||||
func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
|
func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
|
||||||
|
|
||||||
// And atomically performs a bitwise AND operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Int64) And(mask int64) (old int64) { return AndInt64(&x.v, mask) }
|
|
||||||
|
|
||||||
// Or atomically performs a bitwise OR operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Int64) Or(mask int64) (old int64) { return OrInt64(&x.v, mask) }
|
|
||||||
|
|
||||||
// A Uint32 is an atomic uint32. The zero value is zero.
|
// A Uint32 is an atomic uint32. The zero value is zero.
|
||||||
//
|
//
|
||||||
// Uint32 must not be copied after first use.
|
// Uint32 must not be copied after first use.
|
||||||
@@ -160,14 +144,6 @@ func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) {
|
|||||||
// Add atomically adds delta to x and returns the new value.
|
// Add atomically adds delta to x and returns the new value.
|
||||||
func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
|
func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
|
||||||
|
|
||||||
// And atomically performs a bitwise AND operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Uint32) And(mask uint32) (old uint32) { return AndUint32(&x.v, mask) }
|
|
||||||
|
|
||||||
// Or atomically performs a bitwise OR operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Uint32) Or(mask uint32) (old uint32) { return OrUint32(&x.v, mask) }
|
|
||||||
|
|
||||||
// A Uint64 is an atomic uint64. The zero value is zero.
|
// A Uint64 is an atomic uint64. The zero value is zero.
|
||||||
//
|
//
|
||||||
// Uint64 must not be copied after first use.
|
// Uint64 must not be copied after first use.
|
||||||
@@ -194,14 +170,6 @@ func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) {
|
|||||||
// Add atomically adds delta to x and returns the new value.
|
// Add atomically adds delta to x and returns the new value.
|
||||||
func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
|
func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
|
||||||
|
|
||||||
// And atomically performs a bitwise AND operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Uint64) And(mask uint64) (old uint64) { return AndUint64(&x.v, mask) }
|
|
||||||
|
|
||||||
// Or atomically performs a bitwise OR operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Uint64) Or(mask uint64) (old uint64) { return OrUint64(&x.v, mask) }
|
|
||||||
|
|
||||||
// A Uintptr is an atomic uintptr. The zero value is zero.
|
// A Uintptr is an atomic uintptr. The zero value is zero.
|
||||||
//
|
//
|
||||||
// Uintptr must not be copied after first use.
|
// Uintptr must not be copied after first use.
|
||||||
@@ -227,14 +195,6 @@ func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) {
|
|||||||
// Add atomically adds delta to x and returns the new value.
|
// Add atomically adds delta to x and returns the new value.
|
||||||
func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
|
func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
|
||||||
|
|
||||||
// And atomically performs a bitwise AND operation on x using the bitmask
|
|
||||||
// provided as mask and returns the old value.
|
|
||||||
func (x *Uintptr) And(mask uintptr) (old uintptr) { return AndUintptr(&x.v, mask) }
|
|
||||||
|
|
||||||
// Or atomically performs a bitwise OR operation on x using the bitmask
|
|
||||||
// provided as mask and returns the updated value after the OR operation.
|
|
||||||
func (x *Uintptr) Or(mask uintptr) (old uintptr) { return OrUintptr(&x.v, mask) }
|
|
||||||
|
|
||||||
// noCopy may be added to structs which must not be copied
|
// noCopy may be added to structs which must not be copied
|
||||||
// after the first use.
|
// after the first use.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -94,10 +94,19 @@ func (wg *WaitGroup) Add(delta int) {
|
|||||||
fatal("sync: WaitGroup.Add called from multiple synctest bubbles")
|
fatal("sync: WaitGroup.Add called from multiple synctest bubbles")
|
||||||
case synctest.CurrentBubble:
|
case synctest.CurrentBubble:
|
||||||
bubbled = true
|
bubbled = true
|
||||||
state := wg.state.Or(waitGroupBubbleFlag)
|
// Use compare-and-swap loop to implement atomic Or operation
|
||||||
if state != 0 && state&waitGroupBubbleFlag == 0 {
|
// since race detector doesn't have __tsan_go_atomic64_fetch_or
|
||||||
// Add has been called from outside this bubble.
|
for {
|
||||||
fatal("sync: WaitGroup.Add called from inside and outside synctest bubble")
|
old := wg.state.Load()
|
||||||
|
new := old | waitGroupBubbleFlag
|
||||||
|
if wg.state.CompareAndSwap(old, new) {
|
||||||
|
state := old
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user