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 "SkTLS.h" 9 10 // enable to help debug TLS storage 11 //#define SK_TRACE_TLS_LIFETIME 12 13 14 #ifdef SK_TRACE_TLS_LIFETIME 15 #include "SkAtomics.h" 16 static int32_t gTLSRecCount; 17 #endif 18 19 struct SkTLSRec { 20 SkTLSRec* fNext; 21 void* fData; 22 SkTLS::CreateProc fCreateProc; 23 SkTLS::DeleteProc fDeleteProc; 24 25 #ifdef SK_TRACE_TLS_LIFETIME SkTLSRecSkTLSRec26 SkTLSRec() { 27 int n = sk_atomic_inc(&gTLSRecCount); 28 SkDebugf(" SkTLSRec[%d]\n", n); 29 } 30 #endif 31 ~SkTLSRecSkTLSRec32 ~SkTLSRec() { 33 if (fDeleteProc) { 34 fDeleteProc(fData); 35 } 36 // else we leak fData, or it will be managed by the caller 37 38 #ifdef SK_TRACE_TLS_LIFETIME 39 int n = sk_atomic_dec(&gTLSRecCount); 40 SkDebugf("~SkTLSRec[%d]\n", n - 1); 41 #endif 42 } 43 }; 44 Destructor(void * ptr)45void SkTLS::Destructor(void* ptr) { 46 #ifdef SK_TRACE_TLS_LIFETIME 47 SkDebugf("SkTLS::Destructor(%p)\n", ptr); 48 #endif 49 50 SkTLSRec* rec = (SkTLSRec*)ptr; 51 do { 52 SkTLSRec* next = rec->fNext; 53 delete rec; 54 rec = next; 55 } while (rec); 56 } 57 Get(CreateProc createProc,DeleteProc deleteProc)58void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) { 59 if (nullptr == createProc) { 60 return nullptr; 61 } 62 63 void* ptr = SkTLS::PlatformGetSpecific(true); 64 65 if (ptr) { 66 const SkTLSRec* rec = (const SkTLSRec*)ptr; 67 do { 68 if (rec->fCreateProc == createProc) { 69 SkASSERT(rec->fDeleteProc == deleteProc); 70 return rec->fData; 71 } 72 } while ((rec = rec->fNext) != nullptr); 73 // not found, so create a new one 74 } 75 76 // add a new head of our change 77 SkTLSRec* rec = new SkTLSRec; 78 rec->fNext = (SkTLSRec*)ptr; 79 80 SkTLS::PlatformSetSpecific(rec); 81 82 rec->fData = createProc(); 83 rec->fCreateProc = createProc; 84 rec->fDeleteProc = deleteProc; 85 return rec->fData; 86 } 87 Find(CreateProc createProc)88void* SkTLS::Find(CreateProc createProc) { 89 if (nullptr == createProc) { 90 return nullptr; 91 } 92 93 void* ptr = SkTLS::PlatformGetSpecific(false); 94 95 if (ptr) { 96 const SkTLSRec* rec = (const SkTLSRec*)ptr; 97 do { 98 if (rec->fCreateProc == createProc) { 99 return rec->fData; 100 } 101 } while ((rec = rec->fNext) != nullptr); 102 } 103 return nullptr; 104 } 105 Delete(CreateProc createProc)106void SkTLS::Delete(CreateProc createProc) { 107 if (nullptr == createProc) { 108 return; 109 } 110 111 void* ptr = SkTLS::PlatformGetSpecific(false); 112 113 SkTLSRec* curr = (SkTLSRec*)ptr; 114 SkTLSRec* prev = nullptr; 115 while (curr) { 116 SkTLSRec* next = curr->fNext; 117 if (curr->fCreateProc == createProc) { 118 if (prev) { 119 prev->fNext = next; 120 } else { 121 // we have a new head of our chain 122 SkTLS::PlatformSetSpecific(next); 123 } 124 delete curr; 125 break; 126 } 127 prev = curr; 128 curr = next; 129 } 130 } 131