summaryrefslogtreecommitdiffhomepage
path: root/pkg/refs
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/refs')
-rw-r--r--pkg/refs/BUILD38
-rw-r--r--pkg/refs/refcounter_test.go173
-rwxr-xr-xpkg/refs/refs_state_autogen.go81
-rwxr-xr-xpkg/refs/weak_ref_list.go173
4 files changed, 254 insertions, 211 deletions
diff --git a/pkg/refs/BUILD b/pkg/refs/BUILD
deleted file mode 100644
index 74affc887..000000000
--- a/pkg/refs/BUILD
+++ /dev/null
@@ -1,38 +0,0 @@
-load("//tools:defs.bzl", "go_library", "go_test")
-load("//tools/go_generics:defs.bzl", "go_template_instance")
-
-package(licenses = ["notice"])
-
-go_template_instance(
- name = "weak_ref_list",
- out = "weak_ref_list.go",
- package = "refs",
- prefix = "weakRef",
- template = "//pkg/ilist:generic_list",
- types = {
- "Element": "*WeakRef",
- "Linker": "*WeakRef",
- },
-)
-
-go_library(
- name = "refs",
- srcs = [
- "refcounter.go",
- "refcounter_state.go",
- "weak_ref_list.go",
- ],
- visibility = ["//:sandbox"],
- deps = [
- "//pkg/log",
- "//pkg/sync",
- ],
-)
-
-go_test(
- name = "refs_test",
- size = "small",
- srcs = ["refcounter_test.go"],
- library = ":refs",
- deps = ["//pkg/sync"],
-)
diff --git a/pkg/refs/refcounter_test.go b/pkg/refs/refcounter_test.go
deleted file mode 100644
index 1ab4a4440..000000000
--- a/pkg/refs/refcounter_test.go
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2018 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
-
-import (
- "reflect"
- "testing"
-
- "gvisor.dev/gvisor/pkg/sync"
-)
-
-type testCounter struct {
- AtomicRefCount
-
- // mu protects the boolean below.
- mu sync.Mutex
-
- // destroyed indicates whether this was destroyed.
- destroyed bool
-}
-
-func (t *testCounter) DecRef() {
- t.AtomicRefCount.DecRefWithDestructor(t.destroy)
-}
-
-func (t *testCounter) destroy() {
- t.mu.Lock()
- defer t.mu.Unlock()
- t.destroyed = true
-}
-
-func (t *testCounter) IsDestroyed() bool {
- t.mu.Lock()
- defer t.mu.Unlock()
- return t.destroyed
-}
-
-func newTestCounter() *testCounter {
- return &testCounter{destroyed: false}
-}
-
-func TestOneRef(t *testing.T) {
- tc := newTestCounter()
- tc.DecRef()
-
- if !tc.IsDestroyed() {
- t.Errorf("object should have been destroyed")
- }
-}
-
-func TestTwoRefs(t *testing.T) {
- tc := newTestCounter()
- tc.IncRef()
- tc.DecRef()
- tc.DecRef()
-
- if !tc.IsDestroyed() {
- t.Errorf("object should have been destroyed")
- }
-}
-
-func TestMultiRefs(t *testing.T) {
- tc := newTestCounter()
- tc.IncRef()
- tc.DecRef()
-
- tc.IncRef()
- tc.DecRef()
-
- tc.DecRef()
-
- if !tc.IsDestroyed() {
- t.Errorf("object should have been destroyed")
- }
-}
-
-func TestWeakRef(t *testing.T) {
- tc := newTestCounter()
- w := NewWeakRef(tc, nil)
-
- // Try resolving.
- if x := w.Get(); x == nil {
- t.Errorf("weak reference didn't resolve: expected %v, got nil", tc)
- } else {
- x.DecRef()
- }
-
- // Try resolving again.
- if x := w.Get(); x == nil {
- t.Errorf("weak reference didn't resolve: expected %v, got nil", tc)
- } else {
- x.DecRef()
- }
-
- // Shouldn't be destroyed yet. (Can't continue if this fails.)
- if tc.IsDestroyed() {
- t.Fatalf("original object destroyed earlier than expected")
- }
-
- // Drop the original reference.
- tc.DecRef()
-
- // Assert destroyed.
- if !tc.IsDestroyed() {
- t.Errorf("original object not destroyed as expected")
- }
-
- // Shouldn't be anything.
- if x := w.Get(); x != nil {
- t.Errorf("weak reference resolved: expected nil, got %v", x)
- }
-}
-
-func TestWeakRefDrop(t *testing.T) {
- tc := newTestCounter()
- w := NewWeakRef(tc, nil)
- w.Drop()
-
- // Just assert the list is empty.
- if !tc.weakRefs.Empty() {
- t.Errorf("weak reference not dropped")
- }
-
- // Drop the original reference.
- tc.DecRef()
-}
-
-type testWeakRefUser struct {
- weakRefGone func()
-}
-
-func (u *testWeakRefUser) WeakRefGone() {
- u.weakRefGone()
-}
-
-func TestCallback(t *testing.T) {
- called := false
- tc := newTestCounter()
- var w *WeakRef
- w = NewWeakRef(tc, &testWeakRefUser{func() {
- called = true
-
- // Check that the weak ref has been zapped.
- rc := w.obj.Load().(RefCounter)
- if v := reflect.ValueOf(rc); v != reflect.Zero(v.Type()) {
- t.Fatalf("Callback called with non-nil ptr")
- }
-
- // Check that we're not holding the mutex by acquiring and
- // releasing it.
- tc.mu.Lock()
- tc.mu.Unlock()
- }})
-
- // Drop the original reference, this must trigger the callback.
- tc.DecRef()
-
- if !called {
- t.Fatalf("Callback not called")
- }
-}
diff --git a/pkg/refs/refs_state_autogen.go b/pkg/refs/refs_state_autogen.go
new file mode 100755
index 000000000..4c5591d30
--- /dev/null
+++ b/pkg/refs/refs_state_autogen.go
@@ -0,0 +1,81 @@
+// automatically generated by stateify.
+
+package refs
+
+import (
+ "gvisor.dev/gvisor/pkg/state"
+)
+
+func (x *WeakRef) beforeSave() {}
+func (x *WeakRef) save(m state.Map) {
+ x.beforeSave()
+ var obj savedReference = x.saveObj()
+ m.SaveValue("obj", obj)
+ m.Save("user", &x.user)
+}
+
+func (x *WeakRef) afterLoad() {}
+func (x *WeakRef) load(m state.Map) {
+ m.Load("user", &x.user)
+ m.LoadValue("obj", new(savedReference), func(y interface{}) { x.loadObj(y.(savedReference)) })
+}
+
+func (x *AtomicRefCount) beforeSave() {}
+func (x *AtomicRefCount) save(m state.Map) {
+ x.beforeSave()
+ m.Save("refCount", &x.refCount)
+ m.Save("name", &x.name)
+ m.Save("stack", &x.stack)
+}
+
+func (x *AtomicRefCount) afterLoad() {}
+func (x *AtomicRefCount) load(m state.Map) {
+ m.Load("refCount", &x.refCount)
+ m.Load("name", &x.name)
+ m.Load("stack", &x.stack)
+}
+
+func (x *savedReference) beforeSave() {}
+func (x *savedReference) save(m state.Map) {
+ x.beforeSave()
+ m.Save("obj", &x.obj)
+}
+
+func (x *savedReference) afterLoad() {}
+func (x *savedReference) load(m state.Map) {
+ m.Load("obj", &x.obj)
+}
+
+func (x *weakRefList) beforeSave() {}
+func (x *weakRefList) save(m state.Map) {
+ x.beforeSave()
+ m.Save("head", &x.head)
+ m.Save("tail", &x.tail)
+}
+
+func (x *weakRefList) afterLoad() {}
+func (x *weakRefList) load(m state.Map) {
+ m.Load("head", &x.head)
+ m.Load("tail", &x.tail)
+}
+
+func (x *weakRefEntry) beforeSave() {}
+func (x *weakRefEntry) save(m state.Map) {
+ x.beforeSave()
+ m.Save("next", &x.next)
+ m.Save("prev", &x.prev)
+}
+
+func (x *weakRefEntry) afterLoad() {}
+func (x *weakRefEntry) load(m state.Map) {
+ m.Load("next", &x.next)
+ m.Load("prev", &x.prev)
+}
+
+func init() {
+ state.Register("pkg/refs.WeakRef", (*WeakRef)(nil), state.Fns{Save: (*WeakRef).save, Load: (*WeakRef).load})
+ state.Register("pkg/refs.AtomicRefCount", (*AtomicRefCount)(nil), state.Fns{Save: (*AtomicRefCount).save, Load: (*AtomicRefCount).load})
+ state.Register("pkg/refs.savedReference", (*savedReference)(nil), state.Fns{Save: (*savedReference).save, Load: (*savedReference).load})
+ state.Register("pkg/refs.weakRefList", (*weakRefList)(nil), state.Fns{Save: (*weakRefList).save, Load: (*weakRefList).load})
+ state.Register("pkg/refs.weakRefEntry", (*weakRefEntry)(nil), state.Fns{Save: (*weakRefEntry).save, Load: (*weakRefEntry).load})
+}
diff --git a/pkg/refs/weak_ref_list.go b/pkg/refs/weak_ref_list.go
new file mode 100755
index 000000000..df8e98bf5
--- /dev/null
+++ b/pkg/refs/weak_ref_list.go
@@ -0,0 +1,173 @@
+package refs
+
+// ElementMapper provides an identity mapping by default.
+//
+// This can be replaced to provide a struct that maps elements to linker
+// objects, if they are not the same. An ElementMapper is not typically
+// required if: Linker is left as is, Element is left as is, or Linker and
+// Element are the same type.
+type weakRefElementMapper struct{}
+
+// linkerFor maps an Element to a Linker.
+//
+// This default implementation should be inlined.
+//
+//go:nosplit
+func (weakRefElementMapper) linkerFor(elem *WeakRef) *WeakRef { return elem }
+
+// List is an intrusive list. Entries can be added to or removed from the list
+// in O(1) time and with no additional memory allocations.
+//
+// The zero value for List is an empty list ready to use.
+//
+// To iterate over a list (where l is a List):
+// for e := l.Front(); e != nil; e = e.Next() {
+// // do something with e.
+// }
+//
+// +stateify savable
+type weakRefList struct {
+ head *WeakRef
+ tail *WeakRef
+}
+
+// Reset resets list l to the empty state.
+func (l *weakRefList) Reset() {
+ l.head = nil
+ l.tail = nil
+}
+
+// Empty returns true iff the list is empty.
+func (l *weakRefList) Empty() bool {
+ return l.head == nil
+}
+
+// Front returns the first element of list l or nil.
+func (l *weakRefList) Front() *WeakRef {
+ return l.head
+}
+
+// Back returns the last element of list l or nil.
+func (l *weakRefList) Back() *WeakRef {
+ return l.tail
+}
+
+// PushFront inserts the element e at the front of list l.
+func (l *weakRefList) PushFront(e *WeakRef) {
+ weakRefElementMapper{}.linkerFor(e).SetNext(l.head)
+ weakRefElementMapper{}.linkerFor(e).SetPrev(nil)
+
+ if l.head != nil {
+ weakRefElementMapper{}.linkerFor(l.head).SetPrev(e)
+ } else {
+ l.tail = e
+ }
+
+ l.head = e
+}
+
+// PushBack inserts the element e at the back of list l.
+func (l *weakRefList) PushBack(e *WeakRef) {
+ weakRefElementMapper{}.linkerFor(e).SetNext(nil)
+ weakRefElementMapper{}.linkerFor(e).SetPrev(l.tail)
+
+ if l.tail != nil {
+ weakRefElementMapper{}.linkerFor(l.tail).SetNext(e)
+ } else {
+ l.head = e
+ }
+
+ l.tail = e
+}
+
+// PushBackList inserts list m at the end of list l, emptying m.
+func (l *weakRefList) PushBackList(m *weakRefList) {
+ if l.head == nil {
+ l.head = m.head
+ l.tail = m.tail
+ } else if m.head != nil {
+ weakRefElementMapper{}.linkerFor(l.tail).SetNext(m.head)
+ weakRefElementMapper{}.linkerFor(m.head).SetPrev(l.tail)
+
+ l.tail = m.tail
+ }
+
+ m.head = nil
+ m.tail = nil
+}
+
+// InsertAfter inserts e after b.
+func (l *weakRefList) InsertAfter(b, e *WeakRef) {
+ a := weakRefElementMapper{}.linkerFor(b).Next()
+ weakRefElementMapper{}.linkerFor(e).SetNext(a)
+ weakRefElementMapper{}.linkerFor(e).SetPrev(b)
+ weakRefElementMapper{}.linkerFor(b).SetNext(e)
+
+ if a != nil {
+ weakRefElementMapper{}.linkerFor(a).SetPrev(e)
+ } else {
+ l.tail = e
+ }
+}
+
+// InsertBefore inserts e before a.
+func (l *weakRefList) InsertBefore(a, e *WeakRef) {
+ b := weakRefElementMapper{}.linkerFor(a).Prev()
+ weakRefElementMapper{}.linkerFor(e).SetNext(a)
+ weakRefElementMapper{}.linkerFor(e).SetPrev(b)
+ weakRefElementMapper{}.linkerFor(a).SetPrev(e)
+
+ if b != nil {
+ weakRefElementMapper{}.linkerFor(b).SetNext(e)
+ } else {
+ l.head = e
+ }
+}
+
+// Remove removes e from l.
+func (l *weakRefList) Remove(e *WeakRef) {
+ prev := weakRefElementMapper{}.linkerFor(e).Prev()
+ next := weakRefElementMapper{}.linkerFor(e).Next()
+
+ if prev != nil {
+ weakRefElementMapper{}.linkerFor(prev).SetNext(next)
+ } else {
+ l.head = next
+ }
+
+ if next != nil {
+ weakRefElementMapper{}.linkerFor(next).SetPrev(prev)
+ } else {
+ l.tail = prev
+ }
+}
+
+// Entry is a default implementation of Linker. Users can add anonymous fields
+// of this type to their structs to make them automatically implement the
+// methods needed by List.
+//
+// +stateify savable
+type weakRefEntry struct {
+ next *WeakRef
+ prev *WeakRef
+}
+
+// Next returns the entry that follows e in the list.
+func (e *weakRefEntry) Next() *WeakRef {
+ return e.next
+}
+
+// Prev returns the entry that precedes e in the list.
+func (e *weakRefEntry) Prev() *WeakRef {
+ return e.prev
+}
+
+// SetNext assigns 'entry' as the entry that follows e in the list.
+func (e *weakRefEntry) SetNext(elem *WeakRef) {
+ e.next = elem
+}
+
+// SetPrev assigns 'entry' as the entry that precedes e in the list.
+func (e *weakRefEntry) SetPrev(elem *WeakRef) {
+ e.prev = elem
+}