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