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

.

parent 245d1005
......@@ -63,6 +63,8 @@ type WeakRef struct {
}
// NewWeakRef creates new weak reference pointing to obj.
//
// XXX + onrelease callback?
func NewWeakRef(obj interface{}) *WeakRef {
// since starting from ~ Go1.4 the GC is precise, we can save interface
// pointers to uintptr and that won't prevent GC from garbage
......@@ -73,7 +75,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
}
var release func(interface{})
release = func(_ interface{}) {
release = func(obj interface{}) {
// GC decided that the object is no longer reachable and
// scheduled us to run as finalizer. During the time till we
// actually run, WeakRef.Get might have been come to run and
......
......@@ -20,13 +20,12 @@
package main
import (
"runtime"
"testing"
"time"
"unsafe"
)
// v -> weakref -> get -> == v
// GC -> get -> alive -> GC get alive -> GC get alive -> GC GC get ø
// verify that interface <-> iface works ok.
func TestIface(t *testing.T) {
var i interface{}
......@@ -54,5 +53,56 @@ func TestIface(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