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 "src/core/SkTLS.h"
9 
10 struct SkTLSRec {
11     SkTLSRec*           fNext;
12     void*               fData;
13     SkTLS::CreateProc   fCreateProc;
14     SkTLS::DeleteProc   fDeleteProc;
15 
~SkTLSRecSkTLSRec16     ~SkTLSRec() {
17         if (fDeleteProc) {
18             fDeleteProc(fData);
19         }
20         // else we leak fData, or it will be managed by the caller
21     }
22 };
23 
Destructor(void * ptr)24 void SkTLS::Destructor(void* ptr) {
25     SkTLSRec* rec = (SkTLSRec*)ptr;
26     do {
27         SkTLSRec* next = rec->fNext;
28         delete rec;
29         rec = next;
30     } while (rec);
31 }
32 
Get(CreateProc createProc,DeleteProc deleteProc)33 void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
34     if (nullptr == createProc) {
35         return nullptr;
36     }
37 
38     void* ptr = SkTLS::PlatformGetSpecific(true);
39 
40     if (ptr) {
41         const SkTLSRec* rec = (const SkTLSRec*)ptr;
42         do {
43             if (rec->fCreateProc == createProc) {
44                 SkASSERT(rec->fDeleteProc == deleteProc);
45                 return rec->fData;
46             }
47         } while ((rec = rec->fNext) != nullptr);
48         // not found, so create a new one
49     }
50 
51     // add a new head of our change
52     SkTLSRec* rec = new SkTLSRec;
53     rec->fNext = (SkTLSRec*)ptr;
54 
55     SkTLS::PlatformSetSpecific(rec);
56 
57     rec->fData = createProc();
58     rec->fCreateProc = createProc;
59     rec->fDeleteProc = deleteProc;
60     return rec->fData;
61 }
62 
Find(CreateProc createProc)63 void* SkTLS::Find(CreateProc createProc) {
64     if (nullptr == createProc) {
65         return nullptr;
66     }
67 
68     void* ptr = SkTLS::PlatformGetSpecific(false);
69 
70     if (ptr) {
71         const SkTLSRec* rec = (const SkTLSRec*)ptr;
72         do {
73             if (rec->fCreateProc == createProc) {
74                 return rec->fData;
75             }
76         } while ((rec = rec->fNext) != nullptr);
77     }
78     return nullptr;
79 }
80 
Delete(CreateProc createProc)81 void SkTLS::Delete(CreateProc createProc) {
82     if (nullptr == createProc) {
83         return;
84     }
85 
86     void* ptr = SkTLS::PlatformGetSpecific(false);
87 
88     SkTLSRec* curr = (SkTLSRec*)ptr;
89     SkTLSRec* prev = nullptr;
90     while (curr) {
91         SkTLSRec* next = curr->fNext;
92         if (curr->fCreateProc == createProc) {
93             if (prev) {
94                 prev->fNext = next;
95             } else {
96                 // we have a new head of our chain
97                 SkTLS::PlatformSetSpecific(next);
98             }
99             delete curr;
100             break;
101         }
102         prev = curr;
103         curr = next;
104     }
105 }
106