Line data Source code
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
26 : SkTLSRec() {
27 : int n = sk_atomic_inc(&gTLSRecCount);
28 : SkDebugf(" SkTLSRec[%d]\n", n);
29 : }
30 : #endif
31 :
32 0 : ~SkTLSRec() {
33 0 : if (fDeleteProc) {
34 0 : 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 0 : }
43 : };
44 :
45 0 : void SkTLS::Destructor(void* ptr) {
46 : #ifdef SK_TRACE_TLS_LIFETIME
47 : SkDebugf("SkTLS::Destructor(%p)\n", ptr);
48 : #endif
49 :
50 0 : SkTLSRec* rec = (SkTLSRec*)ptr;
51 0 : do {
52 0 : SkTLSRec* next = rec->fNext;
53 0 : delete rec;
54 0 : rec = next;
55 0 : } while (rec);
56 0 : }
57 :
58 0 : void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
59 0 : if (nullptr == createProc) {
60 0 : return nullptr;
61 : }
62 :
63 0 : void* ptr = SkTLS::PlatformGetSpecific(true);
64 :
65 0 : if (ptr) {
66 0 : const SkTLSRec* rec = (const SkTLSRec*)ptr;
67 0 : do {
68 0 : if (rec->fCreateProc == createProc) {
69 0 : SkASSERT(rec->fDeleteProc == deleteProc);
70 0 : return rec->fData;
71 : }
72 0 : } while ((rec = rec->fNext) != nullptr);
73 : // not found, so create a new one
74 : }
75 :
76 : // add a new head of our change
77 0 : SkTLSRec* rec = new SkTLSRec;
78 0 : rec->fNext = (SkTLSRec*)ptr;
79 :
80 0 : SkTLS::PlatformSetSpecific(rec);
81 :
82 0 : rec->fData = createProc();
83 0 : rec->fCreateProc = createProc;
84 0 : rec->fDeleteProc = deleteProc;
85 0 : return rec->fData;
86 : }
87 :
88 0 : void* SkTLS::Find(CreateProc createProc) {
89 0 : if (nullptr == createProc) {
90 0 : return nullptr;
91 : }
92 :
93 0 : void* ptr = SkTLS::PlatformGetSpecific(false);
94 :
95 0 : if (ptr) {
96 0 : const SkTLSRec* rec = (const SkTLSRec*)ptr;
97 0 : do {
98 0 : if (rec->fCreateProc == createProc) {
99 0 : return rec->fData;
100 : }
101 0 : } while ((rec = rec->fNext) != nullptr);
102 : }
103 0 : return nullptr;
104 : }
105 :
106 0 : void SkTLS::Delete(CreateProc createProc) {
107 0 : if (nullptr == createProc) {
108 0 : return;
109 : }
110 :
111 0 : void* ptr = SkTLS::PlatformGetSpecific(false);
112 :
113 0 : SkTLSRec* curr = (SkTLSRec*)ptr;
114 0 : SkTLSRec* prev = nullptr;
115 0 : while (curr) {
116 0 : SkTLSRec* next = curr->fNext;
117 0 : if (curr->fCreateProc == createProc) {
118 0 : if (prev) {
119 0 : prev->fNext = next;
120 : } else {
121 : // we have a new head of our chain
122 0 : SkTLS::PlatformSetSpecific(next);
123 : }
124 0 : delete curr;
125 0 : break;
126 : }
127 0 : prev = curr;
128 0 : curr = next;
129 : }
130 : }
|