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