headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / runtime_loader / elf_tls.cpp
blobf534cecc00b64c393707d5978dacad8ec595cdae
1 /*
2 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "elf_tls.h"
8 #include <stdlib.h>
9 #include <string.h>
11 #include <support/TLS.h>
13 #include <tls.h>
15 #include <util/kernel_cpp.h>
18 class TLSBlock {
19 public:
20 inline TLSBlock();
21 inline TLSBlock(void* pointer);
23 inline status_t Initialize(unsigned dso);
25 void Destroy();
27 bool IsInvalid() const { return fPointer == NULL; }
29 void* operator+(addr_t offset) const
30 { return (void*)((addr_t)fPointer + offset); }
32 private:
33 void* fPointer;
36 class Generation {
37 public:
38 inline Generation();
40 unsigned Counter() const { return fCounter; }
41 unsigned Size() const { return fSize; }
43 void SetCounter(unsigned counter) { fCounter = counter; }
44 void SetSize(unsigned size) { fSize = size; }
46 private:
47 unsigned fCounter;
48 unsigned fSize;
51 class DynamicThreadVector {
52 public:
53 inline DynamicThreadVector();
55 void DestroyAll();
57 inline TLSBlock& operator[](unsigned dso);
59 private:
60 bool _DoesExist() const { return *fVector != NULL; }
61 unsigned _Size() const
62 { return _DoesExist()
63 ? fGeneration->Size() : 0; }
65 unsigned _Generation() const;
67 status_t _ResizeVector(unsigned minimumSize);
69 TLSBlock** fVector;
70 Generation* fGeneration;
71 TLSBlock fNullBlock;
75 TLSBlockTemplates* TLSBlockTemplates::fInstance;
78 void
79 TLSBlockTemplate::SetBaseAddress(addr_t baseAddress)
81 fAddress = (void*)((addr_t)fAddress + baseAddress);
85 TLSBlock
86 TLSBlockTemplate::CreateBlock()
88 void* pointer = malloc(fMemorySize);
89 if (pointer == NULL)
90 return TLSBlock();
91 memcpy(pointer, fAddress, fFileSize);
92 if (fMemorySize > fFileSize)
93 memset((char*)pointer + fFileSize, 0, fMemorySize - fFileSize);
94 return TLSBlock(pointer);
98 TLSBlockTemplates&
99 TLSBlockTemplates::Get()
101 if (fInstance == NULL)
102 fInstance = new TLSBlockTemplates;
103 return *fInstance;
107 unsigned
108 TLSBlockTemplates::Register(const TLSBlockTemplate& block)
110 unsigned dso;
112 if (!fFreeDSOs.empty()) {
113 dso = fFreeDSOs.back();
114 fFreeDSOs.pop_back();
115 fTemplates[dso] = block;
116 } else {
117 dso = fTemplates.size();
118 fTemplates.push_back(block);
121 fTemplates[dso].SetGeneration(fGeneration);
122 return dso;
126 void
127 TLSBlockTemplates::Unregister(unsigned dso)
129 if (dso == unsigned(-1))
130 return;
132 fGeneration++;
133 fFreeDSOs.push_back(dso);
137 void
138 TLSBlockTemplates::SetBaseAddress(unsigned dso, addr_t baseAddress)
140 if (dso != unsigned(-1))
141 fTemplates[dso].SetBaseAddress(baseAddress);
145 unsigned
146 TLSBlockTemplates::GetGeneration(unsigned dso) const
148 if (dso == unsigned(-1))
149 return fGeneration;
150 return fTemplates[dso].Generation();
154 TLSBlock
155 TLSBlockTemplates::CreateBlock(unsigned dso)
157 return fTemplates[dso].CreateBlock();
161 TLSBlockTemplates::TLSBlockTemplates()
163 fGeneration(0)
168 TLSBlock::TLSBlock()
170 fPointer(NULL)
175 TLSBlock::TLSBlock(void* pointer)
177 fPointer(pointer)
182 status_t
183 TLSBlock::Initialize(unsigned dso)
185 fPointer = TLSBlockTemplates::Get().CreateBlock(dso).fPointer;
186 return fPointer != NULL ? B_OK : B_NO_MEMORY;
190 void
191 TLSBlock::Destroy()
193 free(fPointer);
194 fPointer = NULL;
198 Generation::Generation()
200 fCounter(0),
201 fSize(0)
206 DynamicThreadVector::DynamicThreadVector()
208 fVector((TLSBlock**)tls_address(TLS_DYNAMIC_THREAD_VECTOR)),
209 fGeneration(NULL)
211 if (*fVector != NULL)
212 fGeneration = (Generation*)*(void**)*fVector;
216 void
217 DynamicThreadVector::DestroyAll()
219 for (unsigned i = 0; i < _Size(); i++) {
220 TLSBlock& block = (*fVector)[i + 1];
221 if (!block.IsInvalid())
222 block.Destroy();
225 free(*fVector);
226 *fVector = NULL;
228 delete fGeneration;
232 TLSBlock&
233 DynamicThreadVector::operator[](unsigned dso)
235 unsigned generation = TLSBlockTemplates::Get().GetGeneration(-1);
236 if (_Generation() < generation) {
237 for (unsigned i = 0; i < _Size(); i++) {
238 TLSBlock& block = (*fVector)[i + 1];
239 unsigned dsoGeneration
240 = TLSBlockTemplates::Get().GetGeneration(dso);
241 if (_Generation() < dsoGeneration && dsoGeneration <= generation)
242 block.Destroy();
245 fGeneration->SetCounter(generation);
248 if (_Size() <= dso) {
249 status_t result = _ResizeVector(dso + 1);
250 if (result != B_OK)
251 return fNullBlock;
254 TLSBlock& block = (*fVector)[dso + 1];
255 if (block.IsInvalid()) {
256 status_t result = block.Initialize(dso);
257 if (result != B_OK)
258 return fNullBlock;
261 return block;
265 unsigned
266 DynamicThreadVector::_Generation() const
268 if (fGeneration != NULL)
269 return fGeneration->Counter();
270 return unsigned(-1);
274 status_t
275 DynamicThreadVector::_ResizeVector(unsigned minimumSize)
277 static const unsigned kInitialSize = 4;
278 unsigned size = std::max(minimumSize, kInitialSize);
279 unsigned oldSize = _Size();
280 if (size <= oldSize)
281 return B_OK;
283 void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock));
284 if (newVector == NULL)
285 return B_NO_MEMORY;
287 *fVector = (TLSBlock*)newVector;
288 memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock));
289 if (fGeneration == NULL) {
290 fGeneration = new Generation;
291 if (fGeneration == NULL)
292 return B_NO_MEMORY;
295 *(Generation**)*fVector = fGeneration;
296 fGeneration->SetSize(size);
298 return B_OK;
302 void*
303 get_tls_address(unsigned dso, addr_t offset)
305 DynamicThreadVector dynamicThreadVector;
306 TLSBlock& block = dynamicThreadVector[dso];
307 if (block.IsInvalid())
308 return NULL;
309 return block + offset;
313 void
314 destroy_thread_tls()
316 DynamicThreadVector().DestroyAll();