blob: d5be62170b2a60cb4f8bd454a38f86c3297a8b32 [file] [log] [blame]
bungeman@google.com55487522012-05-14 14:09:24 +00001/*
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
bungeman@google.com55487522012-05-14 14:09:24 +00008#include "SkRefCnt.h"
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00009#include "SkThreadUtils.h"
10#include "SkTypes.h"
11#include "SkWeakRefCnt.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000012#include "Test.h"
bungeman@google.com55487522012-05-14 14:09:24 +000013
14static 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
22static 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
bungeman@google.com55487522012-05-14 14:09:24 +000028 SkASSERT(thing1.start());
29 SkASSERT(thing2.start());
30
31 thing1.join();
32 thing2.join();
33
mtkleinbbb61d72014-11-24 13:09:39 -080034 REPORTER_ASSERT(reporter, ref->unique());
bungeman@google.com55487522012-05-14 14:09:24 +000035 ref->unref();
36}
37
bungeman@google.coma02bc152012-05-16 18:21:56 +000038static 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
47static 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
55static 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
bungeman@google.coma02bc152012-05-16 18:21:56 +000063 SkASSERT(thing1.start());
64 SkASSERT(thing2.start());
65 SkASSERT(thing3.start());
66 SkASSERT(thing4.start());
67
68 thing1.join();
69 thing2.join();
70 thing3.join();
71 thing4.join();
72
mtkleinbbb61d72014-11-24 13:09:39 -080073 REPORTER_ASSERT(reporter, ref->unique());
bungeman2c4bd072016-04-08 06:58:51 -070074 SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
bungeman@google.coma02bc152012-05-16 18:21:56 +000075 ref->unref();
76}
77
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +000078DEF_TEST(RefCnt, reporter) {
bungeman@google.coma02bc152012-05-16 18:21:56 +000079 test_refCnt(reporter);
80 test_weakRefCnt(reporter);
81}
reedbb7b0432016-03-01 07:28:51 -080082
83///////////////////////////////////////////////////////////////////////////////////////////////////
84
85static int gRefCounter;
86static int gUnrefCounter;
87static int gNewCounter;
88static 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
97class Effect {
98public:
99 Effect() : fRefCnt(1) {
100 gNewCounter += 1;
101 }
mtklein71aca542016-03-07 12:28:17 -0800102 virtual ~Effect() {}
reedbb7b0432016-03-01 07:28:51 -0800103
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
123static sk_sp<Effect> Create() {
halcanary217c0b32016-03-02 08:06:20 -0800124 return sk_make_sp<Effect>();
reedbb7b0432016-03-01 07:28:51 -0800125}
126
127class Paint {
128public:
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
halcanarycb6cb382016-03-02 08:11:26 -0800138struct EffectImpl : public Effect {
mtklein71aca542016-03-07 12:28:17 -0800139 ~EffectImpl() override {}
140
halcanarycb6cb382016-03-02 08:11:26 -0800141 static sk_sp<EffectImpl> Create() {
142 return sk_sp<EffectImpl>(new EffectImpl);
143 }
144 int fValue;
145};
146static sk_sp<Effect> make_effect() {
147 auto foo = EffectImpl::Create();
148 foo->fValue = 42;
149 return std::move(foo);
150}
151
152static void reset_counters() {
reedbb7b0432016-03-01 07:28:51 -0800153 gRefCounter = 0;
154 gUnrefCounter = 0;
155 gNewCounter = 0;
156 gDeleteCounter = 0;
halcanarycb6cb382016-03-02 08:11:26 -0800157}
158DEF_TEST(sk_sp, reporter) {
159 reset_counters();
reedbb7b0432016-03-01 07:28:51 -0800160
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
bungemanbeab9e72016-03-03 07:50:49 -0800170 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
reedbb7b0432016-03-01 07:28:51 -0800181 paint.set(nullptr);
182 check(reporter, 0, 1, 1, 1);
183
bungemanbeab9e72016-03-03 07:50:49 -0800184 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
reedbb7b0432016-03-01 07:28:51 -0800195 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
bungemanbeab9e72016-03-03 07:50:49 -0800208 // Test sk_sp::operator->
reedbb7b0432016-03-01 07:28:51 -0800209 delete paint.get()->method();
210 check(reporter, 2, 1, 2, 1);
halcanarycb6cb382016-03-02 08:11:26 -0800211
bungemanbeab9e72016-03-03 07:50:49 -0800212 // Test sk_sp::operator*
213 delete (*paint.get()).method();
214 check(reporter, 2, 1, 2, 1);
215
halcanarycb6cb382016-03-02 08:11:26 -0800216 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);
bungemanc901c112016-03-08 08:35:23 -0800278
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;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400337 ~StructB() override {} // Some clang versions don't emit this implicitly.
bungemanc901c112016-03-08 08:35:23 -0800338 };
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 }
reedbb7b0432016-03-01 07:28:51 -0800352}
353
halcanaryffa39e02016-03-05 08:30:28 -0800354namespace {
355struct FooAbstract : public SkRefCnt {
356 virtual void f() = 0;
357};
358struct FooConcrete : public FooAbstract {
359 void f() override {}
360};
361}
362static 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}
367DEF_TEST(sk_make_sp, r) {
368 auto x = make_foo();
369}
reed941da9d2016-03-06 13:54:00 -0800370
371// Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
372//
373DEF_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}
reed647cc842016-03-08 12:54:48 -0800388
389DEF_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}