1
2
3
4
5 package weak_test
6
7 import (
8 "context"
9 "internal/weak"
10 "runtime"
11 "sync"
12 "testing"
13 "time"
14 )
15
16 type T struct {
17
18
19 t *T
20 a int
21 }
22
23 func TestPointer(t *testing.T) {
24 bt := new(T)
25 wt := weak.Make(bt)
26 if st := wt.Strong(); st != bt {
27 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt)
28 }
29
30 runtime.GC()
31
32 if st := wt.Strong(); st != bt {
33 t.Fatalf("weak pointer is not the same as strong pointer after GC: %p vs. %p", st, bt)
34 }
35
36 runtime.GC()
37
38 if st := wt.Strong(); st != nil {
39 t.Fatalf("expected weak pointer to be nil, got %p", st)
40 }
41 }
42
43 func TestPointerEquality(t *testing.T) {
44 bt := make([]*T, 10)
45 wt := make([]weak.Pointer[T], 10)
46 for i := range bt {
47 bt[i] = new(T)
48 wt[i] = weak.Make(bt[i])
49 }
50 for i := range bt {
51 st := wt[i].Strong()
52 if st != bt[i] {
53 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
54 }
55 if wp := weak.Make(st); wp != wt[i] {
56 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
57 }
58 if i == 0 {
59 continue
60 }
61 if wt[i] == wt[i-1] {
62 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
63 }
64 }
65
66 runtime.GC()
67 for i := range bt {
68 st := wt[i].Strong()
69 if st != bt[i] {
70 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
71 }
72 if wp := weak.Make(st); wp != wt[i] {
73 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
74 }
75 if i == 0 {
76 continue
77 }
78 if wt[i] == wt[i-1] {
79 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
80 }
81 }
82 bt = nil
83
84 runtime.GC()
85 for i := range bt {
86 st := wt[i].Strong()
87 if st != nil {
88 t.Fatalf("expected weak pointer to be nil, got %p", st)
89 }
90 if i == 0 {
91 continue
92 }
93 if wt[i] == wt[i-1] {
94 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
95 }
96 }
97 }
98
99 func TestPointerFinalizer(t *testing.T) {
100 bt := new(T)
101 wt := weak.Make(bt)
102 done := make(chan struct{}, 1)
103 runtime.SetFinalizer(bt, func(bt *T) {
104 if wt.Strong() != nil {
105 t.Errorf("weak pointer did not go nil before finalizer ran")
106 }
107 done <- struct{}{}
108 })
109
110
111 runtime.GC()
112 if wt.Strong() == nil {
113 t.Errorf("weak pointer went nil too soon")
114 }
115 runtime.KeepAlive(bt)
116
117
118
119
120 runtime.GC()
121 if wt.Strong() != nil {
122 t.Errorf("weak pointer did not go nil when finalizer was enqueued")
123 }
124
125
126 <-done
127
128
129 runtime.GC()
130 if wt.Strong() != nil {
131 t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
132 }
133 }
134
135
136
137
138
139
140
141
142 func TestIssue69210(t *testing.T) {
143 if testing.Short() {
144 t.Skip("this is a stress test that takes seconds to run on its own")
145 }
146 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
147 defer cancel()
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 var wg sync.WaitGroup
172 wg.Add(1)
173 go func() {
174 defer wg.Done()
175 for {
176 runtime.GC()
177
178 select {
179 case <-ctx.Done():
180 return
181 default:
182 }
183 }
184 }()
185 for range max(runtime.GOMAXPROCS(-1)-1, 1) {
186 wg.Add(1)
187 go func() {
188 defer wg.Done()
189 for {
190 for range 5 {
191 bt := new(T)
192 wt := weak.Make(bt)
193 bt = nil
194 time.Sleep(1 * time.Millisecond)
195 bt = wt.Strong()
196 if bt != nil {
197 time.Sleep(4 * time.Millisecond)
198 bt.t = bt
199 bt.a = 12
200 }
201 runtime.KeepAlive(bt)
202 }
203 select {
204 case <-ctx.Done():
205 return
206 default:
207 }
208 }
209 }()
210 }
211 wg.Wait()
212 }
213
View as plain text