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