Commit 5074da5b authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 245d1005
...@@ -63,6 +63,8 @@ type WeakRef struct { ...@@ -63,6 +63,8 @@ type WeakRef struct {
} }
// NewWeakRef creates new weak reference pointing to obj. // NewWeakRef creates new weak reference pointing to obj.
//
// XXX + onrelease callback?
func NewWeakRef(obj interface{}) *WeakRef { func NewWeakRef(obj interface{}) *WeakRef {
// since starting from ~ Go1.4 the GC is precise, we can save interface // since starting from ~ Go1.4 the GC is precise, we can save interface
// pointers to uintptr and that won't prevent GC from garbage // pointers to uintptr and that won't prevent GC from garbage
...@@ -73,7 +75,7 @@ func NewWeakRef(obj interface{}) *WeakRef { ...@@ -73,7 +75,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
} }
var release func(interface{}) var release func(interface{})
release = func(_ interface{}) { release = func(obj interface{}) {
// GC decided that the object is no longer reachable and // GC decided that the object is no longer reachable and
// scheduled us to run as finalizer. During the time till we // scheduled us to run as finalizer. During the time till we
// actually run, WeakRef.Get might have been come to run and // actually run, WeakRef.Get might have been come to run and
......
...@@ -20,13 +20,12 @@ ...@@ -20,13 +20,12 @@
package main package main
import ( import (
"runtime"
"testing" "testing"
"time"
"unsafe" "unsafe"
) )
// v -> weakref -> get -> == v
// GC -> get -> alive -> GC get alive -> GC get alive -> GC GC get ø
// verify that interface <-> iface works ok. // verify that interface <-> iface works ok.
func TestIface(t *testing.T) { func TestIface(t *testing.T) {
var i interface{} var i interface{}
...@@ -54,5 +53,56 @@ func TestIface(t *testing.T) { ...@@ -54,5 +53,56 @@ func TestIface(t *testing.T) {
} }
} }
func TestWeakRef(t *testing.T) { func TestWeakRef(t *testing.T) {
type T struct { _ [8]int64 } // large enough not to go into tinyalloc
p := new(T)
w := NewWeakRef(p)
pptr := uintptr(unsafe.Pointer(p))
assertEq := func(a, b interface{}) {
t.Helper()
if a != b {
t.Fatalf("not equal: %#v != %#v", a, b)
}
}
// perform GC + give finalizers a chancet to run.
GC := func() {
runtime.GC()
// GC only queues finalizers, not runs them directly. Give it
// some time so that finalizers could have been run.
time.Sleep(10*time.Millisecond) // XXX hack
}
assertEq(w.state, objLive)
assertEq(w.Get(), p)
assertEq(w.state, objGot)
GC()
assertEq(w.state, objGot) // fin has not been run at all (p is live)
assertEq(w.Get(), p)
assertEq(w.state, objGot)
p = nil
GC()
assertEq(w.state, objLive) // fin ran and downgraded got -> live
switch p_ := w.Get().(type) {
default:
t.Fatalf("Get after objGot -> objLive: %#v", p_)
case *T:
if uintptr(unsafe.Pointer(p_)) != pptr {
t.Fatal("Get after objGot -> objLive: T, but ptr is not the same")
}
}
assertEq(w.state, objGot)
GC()
assertEq(w.state, objLive) // fin ran again and again downgraded got -> live
GC()
assertEq(w.state, objReleased) // fin ran again and released the object
assertEq(w.Get(), nil)
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment