• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkRefCnt.h"
9 #include "SkThreadUtils.h"
10 #include "SkTypes.h"
11 #include "SkWeakRefCnt.h"
12 #include "Test.h"
13 
bounce_ref(void * data)14 static void bounce_ref(void* data) {
15     SkRefCnt* ref = static_cast<SkRefCnt*>(data);
16     for (int i = 0; i < 100000; ++i) {
17         ref->ref();
18         ref->unref();
19     }
20 }
21 
test_refCnt(skiatest::Reporter * reporter)22 static void test_refCnt(skiatest::Reporter* reporter) {
23     SkRefCnt* ref = new SkRefCnt();
24 
25     SkThread thing1(bounce_ref, ref);
26     SkThread thing2(bounce_ref, ref);
27 
28     SkAssertResult(thing1.start());
29     SkAssertResult(thing2.start());
30 
31     thing1.join();
32     thing2.join();
33 
34     REPORTER_ASSERT(reporter, ref->unique());
35     ref->unref();
36 }
37 
bounce_weak_ref(void * data)38 static void bounce_weak_ref(void* data) {
39     SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
40     for (int i = 0; i < 100000; ++i) {
41         if (ref->try_ref()) {
42             ref->unref();
43         }
44     }
45 }
46 
bounce_weak_weak_ref(void * data)47 static void bounce_weak_weak_ref(void* data) {
48     SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
49     for (int i = 0; i < 100000; ++i) {
50         ref->weak_ref();
51         ref->weak_unref();
52     }
53 }
54 
test_weakRefCnt(skiatest::Reporter * reporter)55 static void test_weakRefCnt(skiatest::Reporter* reporter) {
56     SkWeakRefCnt* ref = new SkWeakRefCnt();
57 
58     SkThread thing1(bounce_ref, ref);
59     SkThread thing2(bounce_ref, ref);
60     SkThread thing3(bounce_weak_ref, ref);
61     SkThread thing4(bounce_weak_weak_ref, ref);
62 
63     SkAssertResult(thing1.start());
64     SkAssertResult(thing2.start());
65     SkAssertResult(thing3.start());
66     SkAssertResult(thing4.start());
67 
68     thing1.join();
69     thing2.join();
70     thing3.join();
71     thing4.join();
72 
73     REPORTER_ASSERT(reporter, ref->unique());
74     SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
75     ref->unref();
76 }
77 
DEF_TEST(RefCnt,reporter)78 DEF_TEST(RefCnt, reporter) {
79     test_refCnt(reporter);
80     test_weakRefCnt(reporter);
81 }
82 
83 ///////////////////////////////////////////////////////////////////////////////////////////////////
84 
85 static int gRefCounter;
86 static int gUnrefCounter;
87 static int gNewCounter;
88 static int gDeleteCounter;
89 
90 #define check(reporter, ref, unref, make, kill)             \
91     REPORTER_ASSERT(reporter, gRefCounter == ref);          \
92     REPORTER_ASSERT(reporter, gUnrefCounter == unref);      \
93     REPORTER_ASSERT(reporter, gNewCounter == make);         \
94     REPORTER_ASSERT(reporter, gDeleteCounter == kill);
95 
96 
97 class Effect {
98 public:
Effect()99     Effect() : fRefCnt(1) {
100         gNewCounter += 1;
101     }
~Effect()102     virtual ~Effect() {}
103 
104     int fRefCnt;
105 
ref()106     void ref() {
107         gRefCounter += 1;
108         fRefCnt += 1;
109     }
unref()110     void unref() {
111         gUnrefCounter += 1;
112 
113         SkASSERT(fRefCnt > 0);
114         if (0 == --fRefCnt) {
115             gDeleteCounter += 1;
116             delete this;
117         }
118     }
119 
method() const120     int* method() const { return new int; }
121 };
122 
Create()123 static sk_sp<Effect> Create() {
124     return sk_make_sp<Effect>();
125 }
126 
127 class Paint {
128 public:
129     sk_sp<Effect> fEffect;
130 
get() const131     const sk_sp<Effect>& get() const { return fEffect; }
132 
set(sk_sp<Effect> value)133     void set(sk_sp<Effect> value) {
134         fEffect = std::move(value);
135     }
136 };
137 
138 struct EffectImpl : public Effect {
~EffectImplEffectImpl139     ~EffectImpl() override {}
140 
CreateEffectImpl141     static sk_sp<EffectImpl> Create() {
142         return sk_sp<EffectImpl>(new EffectImpl);
143     }
144     int fValue;
145 };
make_effect()146 static sk_sp<Effect> make_effect() {
147     auto foo = EffectImpl::Create();
148     foo->fValue = 42;
149     return std::move(foo);
150 }
151 
reset_counters()152 static void reset_counters() {
153     gRefCounter = 0;
154     gUnrefCounter = 0;
155     gNewCounter = 0;
156     gDeleteCounter = 0;
157 }
DEF_TEST(sk_sp,reporter)158 DEF_TEST(sk_sp, reporter) {
159     reset_counters();
160 
161     Paint paint;
162     REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
163     REPORTER_ASSERT(reporter, !paint.get());
164     check(reporter, 0, 0, 0, 0);
165 
166     paint.set(Create());
167     check(reporter, 0, 0, 1, 0);
168     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 1);
169 
170     if (paint.get()) {
171         REPORTER_ASSERT(reporter, true);
172     } else {
173         REPORTER_ASSERT(reporter, false);
174     }
175     if (!paint.get()) {
176         REPORTER_ASSERT(reporter, false);
177     } else {
178         REPORTER_ASSERT(reporter, true);
179     }
180 
181     paint.set(nullptr);
182     check(reporter, 0, 1, 1, 1);
183 
184     if (paint.get()) {
185         REPORTER_ASSERT(reporter, false);
186     } else {
187         REPORTER_ASSERT(reporter, true);
188     }
189     if (!paint.get()) {
190         REPORTER_ASSERT(reporter, true);
191     } else {
192         REPORTER_ASSERT(reporter, false);
193     }
194 
195     auto e = Create();
196     REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
197 
198     check(reporter, 0, 1, 2, 1);
199     paint.set(e);
200     check(reporter, 1, 1, 2, 1);
201     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 2);
202 
203     Paint paint2;
204     paint2.set(paint.get());
205     check(reporter, 2, 1, 2, 1);
206     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 3);
207 
208     // Test sk_sp::operator->
209     delete paint.get()->method();
210     check(reporter, 2, 1, 2, 1);
211 
212     // Test sk_sp::operator*
213     delete (*paint.get()).method();
214     check(reporter, 2, 1, 2, 1);
215 
216     paint.set(nullptr);
217     e = nullptr;
218     paint2.set(nullptr);
219     check(reporter, 2, 4, 2, 2);
220 
221     reset_counters();
222     {
223         // Test convertible sk_sp assignment.
224         check(reporter, 0, 0, 0, 0);
225         sk_sp<Effect> foo(nullptr);
226         REPORTER_ASSERT(reporter, !foo);
227         foo = make_effect();
228         REPORTER_ASSERT(reporter, foo);
229         check(reporter, 0, 0, 1, 0);
230     }
231     check(reporter, 0, 1, 1, 1);
232 
233     // Test passing convertible rvalue into funtion.
234     reset_counters();
235     paint.set(EffectImpl::Create());
236     check(reporter, 0, 0, 1, 0);
237     paint.set(nullptr);
238     check(reporter, 0, 1, 1, 1);
239 
240     reset_counters();
241     auto baz = EffectImpl::Create();
242     check(reporter, 0, 0, 1, 0);
243     paint.set(std::move(baz));
244     check(reporter, 0, 0, 1, 0);
245     REPORTER_ASSERT(reporter, !baz);
246     paint.set(nullptr);
247     check(reporter, 0, 1, 1, 1);
248 
249     reset_counters();
250     {
251         // test comparison operator with convertible type.
252         sk_sp<EffectImpl> bar1 = EffectImpl::Create();
253         sk_sp<Effect> bar2(bar1);  // convertible copy constructor
254         check(reporter, 1, 0, 1, 0);
255         REPORTER_ASSERT(reporter, bar1);
256         REPORTER_ASSERT(reporter, bar2);
257         REPORTER_ASSERT(reporter, bar1 == bar2);
258         REPORTER_ASSERT(reporter, bar2 == bar1);
259         REPORTER_ASSERT(reporter, !(bar1 != bar2));
260         REPORTER_ASSERT(reporter, !(bar2 != bar1));
261         sk_sp<Effect> bar3(nullptr);
262         bar3 = bar1;  // convertible copy assignment
263         check(reporter, 2, 0, 1, 0);
264 
265     }
266     check(reporter, 2, 3, 1, 1);
267 
268     // test passing convertible copy into funtion.
269     reset_counters();
270     baz = EffectImpl::Create();
271     check(reporter, 0, 0, 1, 0);
272     paint.set(baz);
273     check(reporter, 1, 0, 1, 0);
274     baz = nullptr;
275     check(reporter, 1, 1, 1, 0);
276     paint.set(nullptr);
277     check(reporter, 1, 2, 1, 1);
278 
279     {
280         sk_sp<SkRefCnt> empty;
281         sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>();
282         REPORTER_ASSERT(reporter, empty == sk_sp<SkRefCnt>());
283 
284         REPORTER_ASSERT(reporter, notEmpty != empty);
285         REPORTER_ASSERT(reporter, empty != notEmpty);
286 
287         REPORTER_ASSERT(reporter, nullptr == empty);
288         REPORTER_ASSERT(reporter, empty == nullptr);
289         REPORTER_ASSERT(reporter, empty == empty);
290 
291         REPORTER_ASSERT(reporter, nullptr <= empty);
292         REPORTER_ASSERT(reporter, empty <= nullptr);
293         REPORTER_ASSERT(reporter, empty <= empty);
294 
295         REPORTER_ASSERT(reporter, nullptr >= empty);
296         REPORTER_ASSERT(reporter, empty >= nullptr);
297         REPORTER_ASSERT(reporter, empty >= empty);
298     }
299 
300     {
301         sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
302         sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
303         REPORTER_ASSERT(reporter, a != b);
304         REPORTER_ASSERT(reporter, (a < b) != (b < a));
305         REPORTER_ASSERT(reporter, (b > a) != (a > b));
306         REPORTER_ASSERT(reporter, (a <= b) != (b <= a));
307         REPORTER_ASSERT(reporter, (b >= a) != (a >= b));
308 
309         REPORTER_ASSERT(reporter, a == a);
310         REPORTER_ASSERT(reporter, a <= a);
311         REPORTER_ASSERT(reporter, a >= a);
312     }
313 
314     // http://wg21.cmeerw.net/lwg/issue998
315     {
316         class foo : public SkRefCnt {
317         public:
318             foo() : bar(this) {}
319             void reset() { bar.reset(); }
320         private:
321             sk_sp<foo> bar;
322         };
323         // The following should properly delete the object and not cause undefined behavior.
324         // This is an ugly example, but the same issue can arise in more subtle ways.
325         (new foo)->reset();
326     }
327 
328     // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
329     {
330         struct StructB;
331         struct StructA : public SkRefCnt {
332             sk_sp<StructB> b;
333         };
334 
335         struct StructB : public SkRefCnt {
336             sk_sp<StructA> a;
337             ~StructB() override {} // Some clang versions don't emit this implicitly.
338         };
339 
340         // Create a reference cycle.
341         StructA* a = new StructA;
342         a->b.reset(new StructB);
343         a->b->a.reset(a);
344 
345         // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
346         // to be deleted before the call to reset() returns. This tests that the
347         // implementation of sk_sp::reset() doesn't access |this| after it
348         // deletes the underlying pointer. This behaviour is consistent with the
349         // definition of unique_ptr::reset in C++11.
350         a->b.reset();
351     }
352 }
353 
354 namespace {
355 struct FooAbstract : public SkRefCnt {
356     virtual void f() = 0;
357 };
358 struct FooConcrete : public FooAbstract {
f__anon0e21115c0111::FooConcrete359     void f() override {}
360 };
361 }
make_foo()362 static sk_sp<FooAbstract> make_foo() {
363     // can not cast FooConcrete to FooAbstract.
364     // can cast FooConcrete* to FooAbstract*.
365     return sk_make_sp<FooConcrete>();
366 }
DEF_TEST(sk_make_sp,r)367 DEF_TEST(sk_make_sp, r) {
368     auto x = make_foo();
369 }
370 
371 // Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
372 //
DEF_TEST(sk_sp_reset,r)373 DEF_TEST(sk_sp_reset, r) {
374     SkRefCnt* rc = new SkRefCnt;
375     REPORTER_ASSERT(r, rc->unique());
376 
377     sk_sp<SkRefCnt> sp;
378     sp.reset(rc);
379     // We have transfered our ownership over to sp
380     REPORTER_ASSERT(r, rc->unique());
381 
382     rc->ref();  // now "rc" is also an owner
383     REPORTER_ASSERT(r, !rc->unique());
384 
385     sp.reset(rc);   // this should transfer our ownership over to sp
386     REPORTER_ASSERT(r, rc->unique());
387 }
388 
DEF_TEST(sk_sp_ref,r)389 DEF_TEST(sk_sp_ref, r) {
390     SkRefCnt* rc = new SkRefCnt;
391     REPORTER_ASSERT(r, rc->unique());
392 
393     {
394         sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
395         REPORTER_ASSERT(r, !rc->unique());
396     }
397 
398     REPORTER_ASSERT(r, rc->unique());
399     rc->unref();
400 }
401