goid: new package
Allows retrieving the goroutine ID for concurrency testing when the race detector is enabled. Updates #1472 PiperOrigin-RevId: 289155308
This commit is contained in:
parent
dacd349d6f
commit
6b83111499
|
@ -0,0 +1,26 @@
|
|||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "goid",
|
||||
srcs = [
|
||||
"goid.go",
|
||||
"goid_amd64.s",
|
||||
"goid_race.go",
|
||||
"goid_unsafe.go",
|
||||
],
|
||||
importpath = "gvisor.dev/gvisor/pkg/goid",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "goid_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"empty_test.go",
|
||||
"goid_test.go",
|
||||
],
|
||||
embed = [":goid"],
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !race
|
||||
|
||||
package goid
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestNothing exists to make the build system happy.
|
||||
func TestNothing(t *testing.T) {}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !race
|
||||
|
||||
// Package goid provides access to the ID of the current goroutine in
|
||||
// race/gotsan builds.
|
||||
package goid
|
||||
|
||||
// Get returns the ID of the current goroutine.
|
||||
func Get() int64 {
|
||||
panic("unimplemented for non-race builds")
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func getg() *g
|
||||
TEXT ·getg(SB),NOSPLIT,$0-8
|
||||
MOVQ (TLS), R14
|
||||
MOVQ R14, ret+0(FP)
|
||||
RET
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Only available in race/gotsan builds.
|
||||
// +build race
|
||||
|
||||
// Package goid provides access to the ID of the current goroutine in
|
||||
// race/gotsan builds.
|
||||
package goid
|
||||
|
||||
// Get returns the ID of the current goroutine.
|
||||
func Get() int64 {
|
||||
return goid()
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build race
|
||||
|
||||
package goid
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInitialGoID(t *testing.T) {
|
||||
const max = 10000
|
||||
if id := goid(); id < 0 || id > max {
|
||||
t.Errorf("got goid = %d, want 0 < goid <= %d", id, max)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGoIDSquence verifies that goid returns values which could plausibly be
|
||||
// goroutine IDs. If this test breaks or becomes flaky, the structs in
|
||||
// goid_unsafe.go may need to be updated.
|
||||
func TestGoIDSquence(t *testing.T) {
|
||||
// Goroutine IDs are cached by each P.
|
||||
runtime.GOMAXPROCS(1)
|
||||
|
||||
// Fill any holes in lower range.
|
||||
for i := 0; i < 50; i++ {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
wg.Done()
|
||||
|
||||
// Leak the goroutine to prevent the ID from being
|
||||
// reused.
|
||||
select {}
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
id := goid()
|
||||
for i := 0; i < 100; i++ {
|
||||
var (
|
||||
newID int64
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
newID = goid()
|
||||
wg.Done()
|
||||
|
||||
// Leak the goroutine to prevent the ID from being
|
||||
// reused.
|
||||
select {}
|
||||
}()
|
||||
wg.Wait()
|
||||
if max := id + 100; newID <= id || newID > max {
|
||||
t.Errorf("unexpected goroutine ID pattern, got goid = %d, want %d < goid <= %d (previous = %d)", newID, id, max, id)
|
||||
}
|
||||
id = newID
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package goid
|
||||
|
||||
// Structs from Go runtime. These may change in the future and require
|
||||
// updating. These structs are currently the same on both AMD64 and ARM64,
|
||||
// but may diverge in the future.
|
||||
|
||||
type stack struct {
|
||||
lo uintptr
|
||||
hi uintptr
|
||||
}
|
||||
|
||||
type gobuf struct {
|
||||
sp uintptr
|
||||
pc uintptr
|
||||
g uintptr
|
||||
ctxt uintptr
|
||||
ret uint64
|
||||
lr uintptr
|
||||
bp uintptr
|
||||
}
|
||||
|
||||
type g struct {
|
||||
stack stack
|
||||
stackguard0 uintptr
|
||||
stackguard1 uintptr
|
||||
|
||||
_panic uintptr
|
||||
_defer uintptr
|
||||
m uintptr
|
||||
sched gobuf
|
||||
syscallsp uintptr
|
||||
syscallpc uintptr
|
||||
stktopsp uintptr
|
||||
param uintptr
|
||||
atomicstatus uint32
|
||||
stackLock uint32
|
||||
goid int64
|
||||
|
||||
// More fields...
|
||||
//
|
||||
// We only use goid and the fields before it are only listed to
|
||||
// calculate the correct offset.
|
||||
}
|
||||
|
||||
func getg() *g
|
||||
|
||||
// goid returns the ID of the current goroutine.
|
||||
func goid() int64 {
|
||||
return getg().goid
|
||||
}
|
Loading…
Reference in New Issue