Home | History | Annotate | Download | only in tests
      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 
     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 
     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 
     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 
     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 
     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 
     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:
     99     Effect() : fRefCnt(1) {
    100         gNewCounter += 1;
    101     }
    102     virtual ~Effect() {}
    103 
    104     int fRefCnt;
    105 
    106     void ref() {
    107         gRefCounter += 1;
    108         fRefCnt += 1;
    109     }
    110     void unref() {
    111         gUnrefCounter += 1;
    112 
    113         SkASSERT(fRefCnt > 0);
    114         if (0 == --fRefCnt) {
    115             gDeleteCounter += 1;
    116             delete this;
    117         }
    118     }
    119 
    120     int* method() const { return new int; }
    121 };
    122 
    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 
    131     const sk_sp<Effect>& get() const { return fEffect; }
    132 
    133     void set(sk_sp<Effect> value) {
    134         fEffect = std::move(value);
    135     }
    136 };
    137 
    138 struct EffectImpl : public Effect {
    139     ~EffectImpl() override {}
    140 
    141     static sk_sp<EffectImpl> Create() {
    142         return sk_sp<EffectImpl>(new EffectImpl);
    143     }
    144     int fValue;
    145 };
    146 static sk_sp<Effect> make_effect() {
    147     auto foo = EffectImpl::Create();
    148     foo->fValue = 42;
    149     return std::move(foo);
    150 }
    151 
    152 static void reset_counters() {
    153     gRefCounter = 0;
    154     gUnrefCounter = 0;
    155     gNewCounter = 0;
    156     gDeleteCounter = 0;
    157 }
    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 {
    359     void f() override {}
    360 };
    361 }
    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 }
    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 //
    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 
    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