1 /*
2 * Copyright 2020 Google LLC
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 "src/sksl/SkSLPool.h"
9
10 #include "include/private/SkSLDefines.h"
11
12 #define VLOG(...) // printf(__VA_ARGS__)
13
14 namespace SkSL {
15
16 #if SKSL_USE_THREAD_LOCAL
17
18 static thread_local MemoryPool* sMemPool = nullptr;
19
get_thread_local_memory_pool()20 static MemoryPool* get_thread_local_memory_pool() {
21 return sMemPool;
22 }
23
set_thread_local_memory_pool(MemoryPool * memPool)24 static void set_thread_local_memory_pool(MemoryPool* memPool) {
25 sMemPool = memPool;
26 }
27
28 #else
29
30 #include <pthread.h>
31
32 static pthread_key_t get_pthread_key() {
33 static pthread_key_t sKey = []{
34 pthread_key_t key;
35 int result = pthread_key_create(&key, /*destructor=*/nullptr);
36 if (result != 0) {
37 SK_ABORT("pthread_key_create failure: %d", result);
38 }
39 return key;
40 }();
41 return sKey;
42 }
43
44 static MemoryPool* get_thread_local_memory_pool() {
45 return static_cast<MemoryPool*>(pthread_getspecific(get_pthread_key()));
46 }
47
48 static void set_thread_local_memory_pool(MemoryPool* poolData) {
49 pthread_setspecific(get_pthread_key(), poolData);
50 }
51
52 #endif // SKSL_USE_THREAD_LOCAL
53
~Pool()54 Pool::~Pool() {
55 if (get_thread_local_memory_pool() == fMemPool.get()) {
56 SkDEBUGFAIL("SkSL pool is being destroyed while it is still attached to the thread");
57 set_thread_local_memory_pool(nullptr);
58 }
59
60 fMemPool->reportLeaks();
61 SkASSERT(fMemPool->isEmpty());
62
63 VLOG("DELETE Pool:0x%016llX\n", (uint64_t)fMemPool.get());
64 }
65
Create()66 std::unique_ptr<Pool> Pool::Create() {
67 auto pool = std::unique_ptr<Pool>(new Pool);
68 pool->fMemPool = MemoryPool::Make(/*preallocSize=*/65536, /*minAllocSize=*/32768);
69 VLOG("CREATE Pool:0x%016llX\n", (uint64_t)pool->fMemPool.get());
70 return pool;
71 }
72
IsAttached()73 bool Pool::IsAttached() {
74 return get_thread_local_memory_pool();
75 }
76
attachToThread()77 void Pool::attachToThread() {
78 VLOG("ATTACH Pool:0x%016llX\n", (uint64_t)fMemPool.get());
79 SkASSERT(get_thread_local_memory_pool() == nullptr);
80 set_thread_local_memory_pool(fMemPool.get());
81 }
82
detachFromThread()83 void Pool::detachFromThread() {
84 MemoryPool* memPool = get_thread_local_memory_pool();
85 VLOG("DETACH Pool:0x%016llX\n", (uint64_t)memPool);
86 SkASSERT(memPool == fMemPool.get());
87 memPool->resetScratchSpace();
88 set_thread_local_memory_pool(nullptr);
89 }
90
AllocMemory(size_t size)91 void* Pool::AllocMemory(size_t size) {
92 // Is a pool attached?
93 MemoryPool* memPool = get_thread_local_memory_pool();
94 if (memPool) {
95 void* ptr = memPool->allocate(size);
96 VLOG("ALLOC Pool:0x%016llX 0x%016llX\n", (uint64_t)memPool, (uint64_t)ptr);
97 return ptr;
98 }
99
100 // There's no pool attached. Allocate memory using the system allocator.
101 void* ptr = ::operator new(size);
102 VLOG("ALLOC Pool:__________________ 0x%016llX\n", (uint64_t)ptr);
103 return ptr;
104 }
105
FreeMemory(void * ptr)106 void Pool::FreeMemory(void* ptr) {
107 // Is a pool attached?
108 MemoryPool* memPool = get_thread_local_memory_pool();
109 if (memPool) {
110 VLOG("FREE Pool:0x%016llX 0x%016llX\n", (uint64_t)memPool, (uint64_t)ptr);
111 memPool->release(ptr);
112 return;
113 }
114
115 // There's no pool attached. Free it using the system allocator.
116 VLOG("FREE Pool:__________________ 0x%016llX\n", (uint64_t)ptr);
117 ::operator delete(ptr);
118 }
119
120 } // namespace SkSL
121