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 "include/core/SkRefCnt.h" 9#include "include/core/SkTypes.h" 10#include "include/private/SkWeakRefCnt.h" 11#include "tests/Test.h" 12 13#include <thread> 14 15static 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 23static 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 36static 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 45static 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 53static 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 71DEF_TEST(RefCnt, reporter) { 72 test_refCnt(reporter); 73 test_weakRefCnt(reporter); 74} 75 76/////////////////////////////////////////////////////////////////////////////////////////////////// 77 78static int gRefCounter; 79static int gUnrefCounter; 80static int gNewCounter; 81static 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 89class Effect { 90public: 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 115static sk_sp<Effect> Create() { 116 return sk_make_sp<Effect>(); 117} 118 119class Paint { 120public: 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 130struct 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}; 138static sk_sp<Effect> make_effect() { 139 auto foo = EffectImpl::Create(); 140 foo->fValue = 42; 141 return std::move(foo); 142} 143 144static void reset_counters() { 145 gRefCounter = 0; 146 gUnrefCounter = 0; 147 gNewCounter = 0; 148 gDeleteCounter = 0; 149} 150DEF_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 284 { 285 sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>(); 286 sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>(); 287 REPORTER_ASSERT(reporter, a != b); 288 REPORTER_ASSERT(reporter, a == a); 289 } 290 291 // http://wg21.cmeerw.net/lwg/issue998 292 { 293 class foo : public SkRefCnt { 294 public: 295 foo() : bar(this) {} 296 void reset() { bar.reset(); } 297 private: 298 sk_sp<foo> bar; 299 }; 300 // The following should properly delete the object and not cause undefined behavior. 301 // This is an ugly example, but the same issue can arise in more subtle ways. 302 (new foo)->reset(); 303 } 304 305 // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c 306 { 307 struct StructB; 308 struct StructA : public SkRefCnt { 309 sk_sp<StructB> b; 310 }; 311 312 struct StructB : public SkRefCnt { 313 sk_sp<StructA> a; 314 ~StructB() override {} // Some clang versions don't emit this implicitly. 315 }; 316 317 // Create a reference cycle. 318 StructA* a = new StructA; 319 a->b.reset(new StructB); 320 a->b->a.reset(a); 321 322 // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|) 323 // to be deleted before the call to reset() returns. This tests that the 324 // implementation of sk_sp::reset() doesn't access |this| after it 325 // deletes the underlying pointer. This behaviour is consistent with the 326 // definition of unique_ptr::reset in C++11. 327 a->b.reset(); 328 } 329} 330 331namespace { 332struct FooAbstract : public SkRefCnt { 333 virtual void f() = 0; 334}; 335struct FooConcrete : public FooAbstract { 336 void f() override {} 337}; 338} // namespace 339static sk_sp<FooAbstract> make_foo() { 340 // can not cast FooConcrete to FooAbstract. 341 // can cast FooConcrete* to FooAbstract*. 342 return sk_make_sp<FooConcrete>(); 343} 344DEF_TEST(sk_make_sp, r) { 345 auto x = make_foo(); 346} 347 348// Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice 349// 350DEF_TEST(sk_sp_reset, r) { 351 SkRefCnt* rc = new SkRefCnt; 352 REPORTER_ASSERT(r, rc->unique()); 353 354 sk_sp<SkRefCnt> sp; 355 sp.reset(rc); 356 // We have transfered our ownership over to sp 357 REPORTER_ASSERT(r, rc->unique()); 358 359 rc->ref(); // now "rc" is also an owner 360 REPORTER_ASSERT(r, !rc->unique()); 361 362 sp.reset(rc); // this should transfer our ownership over to sp 363 REPORTER_ASSERT(r, rc->unique()); 364} 365 366DEF_TEST(sk_sp_ref, r) { 367 SkRefCnt* rc = new SkRefCnt; 368 REPORTER_ASSERT(r, rc->unique()); 369 370 { 371 sk_sp<SkRefCnt> sp = sk_ref_sp(rc); 372 REPORTER_ASSERT(r, !rc->unique()); 373 } 374 375 REPORTER_ASSERT(r, rc->unique()); 376 rc->unref(); 377} 378