Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2014 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 "SkCachedData.h"
      9 #include "SkDiscardableMemoryPool.h"
     10 #include "SkMalloc.h"
     11 #include "SkRefCnt.h"
     12 #include "SkTypes.h"
     13 #include "Test.h"
     14 
     15 #include <cstring>
     16 
     17 class SkDiscardableMemory;
     18 
     19 enum LockedState {
     20     kUnlocked,
     21     kLocked,
     22 };
     23 
     24 enum CachedState {
     25     kNotInCache,
     26     kInCache,
     27 };
     28 
     29 static void check_data(skiatest::Reporter* reporter, SkCachedData* data,
     30                        int refcnt, CachedState cacheState, LockedState lockedState) {
     31     REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt);
     32     REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState));
     33     REPORTER_ASSERT(reporter, data->testing_only_isLocked() == (lockedState == kLocked));
     34 }
     35 
     36 static SkCachedData* make_data(size_t size, SkDiscardableMemoryPool* pool) {
     37     if (pool) {
     38         SkDiscardableMemory* dm = pool->create(size);
     39         // the pool "can" return null, but it shouldn't in these controlled conditions
     40         SkASSERT_RELEASE(dm);
     41         return new SkCachedData(size, dm);
     42     } else {
     43         return new SkCachedData(sk_malloc_throw(size), size);
     44     }
     45 }
     46 
     47 // returns with the data locked by client and cache
     48 static SkCachedData* test_locking(skiatest::Reporter* reporter,
     49                                   size_t size, SkDiscardableMemoryPool* pool) {
     50     SkCachedData* data = make_data(size, pool);
     51 
     52     memset(data->writable_data(), 0x80, size);  // just to use writable_data()
     53 
     54     check_data(reporter, data, 1, kNotInCache, kLocked);
     55 
     56     data->ref();
     57     check_data(reporter, data, 2, kNotInCache, kLocked);
     58     data->unref();
     59     check_data(reporter, data, 1, kNotInCache, kLocked);
     60 
     61     data->attachToCacheAndRef();
     62     check_data(reporter, data, 2, kInCache, kLocked);
     63 
     64     data->unref();
     65     check_data(reporter, data, 1, kInCache, kUnlocked);
     66 
     67     data->ref();
     68     check_data(reporter, data, 2, kInCache, kLocked);
     69 
     70     return data;
     71 }
     72 
     73 /*
     74  *  SkCachedData behaves differently (regarding its locked/unlocked state) depending on
     75  *  when it is in the cache or not. Being in the cache is signaled by calling attachToCacheAndRef()
     76  *  instead of ref(). (and balanced by detachFromCacheAndUnref).
     77  *
     78  *  Thus, among other things, we test the end-of-life behavior when the client is the last owner
     79  *  and when the cache is.
     80  */
     81 DEF_TEST(CachedData, reporter) {
     82     sk_sp<SkDiscardableMemoryPool> pool(SkDiscardableMemoryPool::Make(1000));
     83 
     84     for (int useDiscardable = 0; useDiscardable <= 1; ++useDiscardable) {
     85         const size_t size = 100;
     86 
     87         // test with client as last owner
     88         SkCachedData* data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
     89         check_data(reporter, data, 2, kInCache, kLocked);
     90         data->detachFromCacheAndUnref();
     91         check_data(reporter, data, 1, kNotInCache, kLocked);
     92         data->unref();
     93 
     94         // test with cache as last owner
     95         data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
     96         check_data(reporter, data, 2, kInCache, kLocked);
     97         data->unref();
     98         check_data(reporter, data, 1, kInCache, kUnlocked);
     99         data->detachFromCacheAndUnref();
    100     }
    101 }
    102