Commit ac802560 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent e39e6682
...@@ -68,7 +68,7 @@ type Ref struct { ...@@ -68,7 +68,7 @@ type Ref struct {
state weakRefState state weakRefState
} }
//trace:event traceRelease(w *Ref, released bool) //trace:event traceRelease(w *Ref)
// NewRef creates new weak reference pointing to obj. // NewRef creates new weak reference pointing to obj.
// //
...@@ -100,11 +100,10 @@ func NewRef(obj interface{}) *Ref { ...@@ -100,11 +100,10 @@ func NewRef(obj interface{}) *Ref {
if w.state == objGot { if w.state == objGot {
w.state = objLive w.state = objLive
runtime.SetFinalizer(obj, release) runtime.SetFinalizer(obj, release)
traceRelease(w, false)
} else { } else {
w.state = objReleased w.state = objReleased
traceRelease(w, true)
} }
traceRelease(w)
w.mu.Unlock() w.mu.Unlock()
} }
......
...@@ -56,20 +56,27 @@ func TestIface(t *testing.T) { ...@@ -56,20 +56,27 @@ func TestIface(t *testing.T) {
} }
func TestWeakRef(t *testing.T) { func TestWeakRef(t *testing.T) {
for i := 0; i < 100; i++ {
println(i)
testWeakRef(t)
}
}
func testWeakRef(t *testing.T) {
type T struct{ _ [8]int64 } // large enough not to go into tinyalloc type T struct{ _ [8]int64 } // large enough not to go into tinyalloc
p := new(T) p := new(T)
w := NewRef(p) w := NewRef(p)
pptr := uintptr(unsafe.Pointer(p)) pptr := uintptr(unsafe.Pointer(p))
wrelease := make(chan bool) // events from traceRelease(w) wrelease := make(chan weakRefState) // w.state from traceRelease(w) event
tpg := &tracing.ProbeGroup{} tpg := &tracing.ProbeGroup{}
tracing.Lock() tracing.Lock()
traceRelease_Attach(tpg, func(w_ *Ref, released bool) { traceRelease_Attach(tpg, func(w_ *Ref) {
if w_ != w { if w_ != w {
panic("release: w != w_") panic("release: w != w_")
} }
wrelease <- released wrelease <- w.state
}) })
traceGotPre_Attach(tpg, func(w *Ref) { traceGotPre_Attach(tpg, func(w *Ref) {
// nop for now // nop for now
...@@ -86,40 +93,47 @@ func TestWeakRef(t *testing.T) { ...@@ -86,40 +93,47 @@ func TestWeakRef(t *testing.T) {
} }
// perform GC + give finalizers a chance to run. // perform GC + give finalizers a chance to run.
GC := func(expectRelease bool) { GCnofin := func() {
t.Helper()
runtime.GC()
select {
case <-time.After(10 * time.Millisecond):
// ok
case <-wrelease:
t.Fatal("unexpected release event")
}
}
GCfin := func(stateOK weakRefState) {
t.Helper() t.Helper()
runtime.GC() runtime.GC()
// GC only queues finalizers, not runs them directly. Give it // GC only queues finalizers, not runs them directly. Give it
// some time so that finalizers could have been run. // some time so that finalizers could have been run.
if expectRelease { var state weakRefState
select { select {
case <-wrelease: case state = <-wrelease:
// ok // ok
case <-time.After(100 * time.Millisecond): case <-time.After(1 * time.Second):
t.Fatal("no release event") t.Fatal("no release event")
} }
} else {
select { if state != stateOK {
case <-time.After(10 * time.Millisecond): t.Fatalf("release: state != stateOK; state=%v stateOK=%v", state, stateOK)
// ok
case <-wrelease:
t.Fatal("unexpected release event")
}
} }
} }
assertEq(w.state, objLive) assertEq(w.state, objLive)
assertEq(w.Get(), p) assertEq(w.Get(), p)
assertEq(w.state, objGot) assertEq(w.state, objGot)
GC(false) GCnofin()
assertEq(w.state, objGot) // fin has not been run at all (p is live) assertEq(w.state, objGot) // fin has not been run at all (p is live)
assertEq(w.Get(), p) assertEq(w.Get(), p)
assertEq(w.state, objGot) assertEq(w.state, objGot)
p = nil p = nil
GC(true) GCfin(objLive) // fin ran and downgraded got -> live
assertEq(w.state, objLive) // fin ran and downgraded got -> live assertEq(w.state, objLive)
switch p_ := w.Get().(type) { switch p_ := w.Get().(type) {
default: default:
t.Fatalf("Get after objGot -> objLive: %#v", p_) t.Fatalf("Get after objGot -> objLive: %#v", p_)
...@@ -130,10 +144,8 @@ func TestWeakRef(t *testing.T) { ...@@ -130,10 +144,8 @@ func TestWeakRef(t *testing.T) {
} }
assertEq(w.state, objGot) assertEq(w.state, objGot)
GC(true) GCfin(objLive) // fin ran again and again downgraded got -> live
assertEq(w.state, objLive) // fin ran again and again downgraded got -> live
GC(true) GCfin(objReleased) // fin ran again and released the object
assertEq(w.state, objReleased) // fin ran again and released the object
assertEq(w.Get(), nil) assertEq(w.Get(), nil)
} }
...@@ -35,32 +35,32 @@ func traceGotPre_Attach(pg *tracing.ProbeGroup, probe func(w *Ref)) *tracing.Pro ...@@ -35,32 +35,32 @@ func traceGotPre_Attach(pg *tracing.ProbeGroup, probe func(w *Ref)) *tracing.Pro
return &p.Probe return &p.Probe
} }
// traceevent: traceRelease(w *Ref, released bool) // traceevent: traceRelease(w *Ref)
type _t_traceRelease struct { type _t_traceRelease struct {
tracing.Probe tracing.Probe
probefunc func(w *Ref, released bool) probefunc func(w *Ref)
} }
var _traceRelease *_t_traceRelease var _traceRelease *_t_traceRelease
func traceRelease(w *Ref, released bool) { func traceRelease(w *Ref) {
if _traceRelease != nil { if _traceRelease != nil {
_traceRelease_run(w, released) _traceRelease_run(w)
} }
} }
func _traceRelease_run(w *Ref, released bool) { func _traceRelease_run(w *Ref) {
for p := _traceRelease; p != nil; p = (*_t_traceRelease)(unsafe.Pointer(p.Next())) { for p := _traceRelease; p != nil; p = (*_t_traceRelease)(unsafe.Pointer(p.Next())) {
p.probefunc(w, released) p.probefunc(w)
} }
} }
func traceRelease_Attach(pg *tracing.ProbeGroup, probe func(w *Ref, released bool)) *tracing.Probe { func traceRelease_Attach(pg *tracing.ProbeGroup, probe func(w *Ref)) *tracing.Probe {
p := _t_traceRelease{probefunc: probe} p := _t_traceRelease{probefunc: probe}
tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_traceRelease)), &p.Probe) tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_traceRelease)), &p.Probe)
return &p.Probe return &p.Probe
} }
// trace export signature // trace export signature
func _trace_exporthash_c65df3d81975319429a288a09095370dace6a87b() {} func _trace_exporthash_55416cf1cbcad92c4b4497269fa14b46e82469bd() {}
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