• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)45 void 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)58 void* 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)88 void* 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)106 void 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