diff options
Diffstat (limited to 'pkg/refsvfs2')
-rw-r--r-- | pkg/refsvfs2/BUILD | 37 | ||||
-rw-r--r-- | pkg/refsvfs2/refs_template.go | 152 | ||||
-rw-r--r-- | pkg/refsvfs2/refsvfs2_state_autogen.go | 3 |
3 files changed, 3 insertions, 189 deletions
diff --git a/pkg/refsvfs2/BUILD b/pkg/refsvfs2/BUILD deleted file mode 100644 index bfa1daa10..000000000 --- a/pkg/refsvfs2/BUILD +++ /dev/null @@ -1,37 +0,0 @@ -load("//tools:defs.bzl", "go_library") -load("//tools/go_generics:defs.bzl", "go_template") - -package(licenses = ["notice"]) - -go_template( - name = "refs_template", - srcs = [ - "refs_template.go", - ], - opt_consts = [ - "logTrace", - ], - types = [ - "T", - ], - visibility = ["//:sandbox"], - deps = [ - "//pkg/log", - "//pkg/refs", - ], -) - -go_library( - name = "refsvfs2", - srcs = [ - "refs.go", - "refs_map.go", - ], - visibility = ["//:sandbox"], - deps = [ - "//pkg/context", - "//pkg/log", - "//pkg/refs", - "//pkg/sync", - ], -) diff --git a/pkg/refsvfs2/refs_template.go b/pkg/refsvfs2/refs_template.go deleted file mode 100644 index 8f50b4ee6..000000000 --- a/pkg/refsvfs2/refs_template.go +++ /dev/null @@ -1,152 +0,0 @@ -// 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 refs_template defines a template that can be used by reference -// counted objects. The "owner" template parameter is used in log messages to -// indicate the type of reference-counted object that exhibited a reference -// leak. As a result, structs that are embedded in other structs should not use -// this template, since it will make tracking down leaks more difficult. -package refs_template - -import ( - "fmt" - "sync/atomic" - - "gvisor.dev/gvisor/pkg/refsvfs2" -) - -// enableLogging indicates whether reference-related events should be logged (with -// stack traces). This is false by default and should only be set to true for -// debugging purposes, as it can generate an extremely large amount of output -// and drastically degrade performance. -const enableLogging = false - -// T is the type of the reference counted object. It is only used to customize -// debug output when leak checking. -type T interface{} - -// obj is used to customize logging. Note that we use a pointer to T so that -// we do not copy the entire object when passed as a format parameter. -var obj *T - -// Refs implements refs.RefCounter. It keeps a reference count using atomic -// operations and calls the destructor when the count reaches zero. -// -// Note that the number of references is actually refCount + 1 so that a default -// zero-value Refs object contains one reference. -// -// +stateify savable -type Refs struct { - // refCount is composed of two fields: - // - // [32-bit speculative references]:[32-bit real references] - // - // Speculative references are used for TryIncRef, to avoid a CompareAndSwap - // loop. See IncRef, DecRef and TryIncRef for details of how these fields are - // used. - refCount int64 -} - -// RefType implements refsvfs2.CheckedObject.RefType. -func (r *Refs) RefType() string { - return fmt.Sprintf("%T", obj)[1:] -} - -// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. -func (r *Refs) LeakMessage() string { - return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) -} - -// LogRefs implements refsvfs2.CheckedObject.LogRefs. -func (r *Refs) LogRefs() bool { - return enableLogging -} - -// EnableLeakCheck enables reference leak checking on r. -func (r *Refs) EnableLeakCheck() { - refsvfs2.Register(r) -} - -// ReadRefs returns the current number of references. The returned count is -// inherently racy and is unsafe to use without external synchronization. -func (r *Refs) ReadRefs() int64 { - // Account for the internal -1 offset on refcounts. - return atomic.LoadInt64(&r.refCount) + 1 -} - -// IncRef implements refs.RefCounter.IncRef. -// -//go:nosplit -func (r *Refs) IncRef() { - v := atomic.AddInt64(&r.refCount, 1) - refsvfs2.LogIncRef(r, v+1) - if v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) - } -} - -// TryIncRef implements refs.RefCounter.TryIncRef. -// -// To do this safely without a loop, a speculative reference is first acquired -// on the object. This allows multiple concurrent TryIncRef calls to distinguish -// other TryIncRef calls from genuine references held. -// -//go:nosplit -func (r *Refs) TryIncRef() bool { - const speculativeRef = 1 << 32 - if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { - // This object has already been freed. - atomic.AddInt64(&r.refCount, -speculativeRef) - return false - } - - // Turn into a real reference. - v := atomic.AddInt64(&r.refCount, -speculativeRef+1) - refsvfs2.LogTryIncRef(r, v+1) - return true -} - -// DecRef implements refs.RefCounter.DecRef. -// -// Note that speculative references are counted here. Since they were added -// prior to real references reaching zero, they will successfully convert to -// real references. In other words, we see speculative references only in the -// following case: -// -// A: TryIncRef [speculative increase => sees non-negative references] -// B: DecRef [real decrease] -// A: TryIncRef [transform speculative to real] -// -//go:nosplit -func (r *Refs) DecRef(destroy func()) { - v := atomic.AddInt64(&r.refCount, -1) - refsvfs2.LogDecRef(r, v+1) - switch { - case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) - - case v == -1: - refsvfs2.Unregister(r) - // Call the destructor. - if destroy != nil { - destroy() - } - } -} - -func (r *Refs) afterLoad() { - if r.ReadRefs() > 0 { - r.EnableLeakCheck() - } -} diff --git a/pkg/refsvfs2/refsvfs2_state_autogen.go b/pkg/refsvfs2/refsvfs2_state_autogen.go new file mode 100644 index 000000000..ca5fbb104 --- /dev/null +++ b/pkg/refsvfs2/refsvfs2_state_autogen.go @@ -0,0 +1,3 @@ +// automatically generated by stateify. + +package refsvfs2 |