1/*
2 * Copyright (C) 2014-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef PerThread_h
27#define PerThread_h
28
29#include "BInline.h"
30#include "BPlatform.h"
31#include "PerHeapKind.h"
32#include "VMAllocate.h"
33#include <mutex>
34#include <pthread.h>
35
36#if defined(__has_include)
37#if __has_include(<System/pthread_machdep.h>)
38#include <System/pthread_machdep.h>
39#define HAVE_PTHREAD_MACHDEP_H 1
40#else
41#define HAVE_PTHREAD_MACHDEP_H 0
42#endif
43#else
44#define HAVE_PTHREAD_MACHDEP_H 0
45#endif
46
47namespace bmalloc {
48
49// Usage:
50// Object* object = PerThread<Object>::get();
51
52template<typename T>
53class PerThread {
54public:
55 static T* get();
56 static T* getFastCase();
57 static T* getSlowCase();
58
59private:
60 static void destructor(void*);
61};
62
63#if HAVE_PTHREAD_MACHDEP_H
64
65class Cache;
66template<typename T> struct PerThreadStorage;
67
68// For now, we only support PerThread<PerHeapKind<Cache>>. We can expand to other types by
69// using more keys.
70template<> struct PerThreadStorage<PerHeapKind<Cache>> {
71 static const pthread_key_t key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
72
73 static void* get()
74 {
75 return _pthread_getspecific_direct(key);
76 }
77
78 static void init(void* object, void (*destructor)(void*))
79 {
80 _pthread_setspecific_direct(key, object);
81 pthread_key_init_np(key, destructor);
82 }
83};
84
85#else
86
87template<typename T> struct PerThreadStorage {
88 static bool s_didInitialize;
89 static pthread_key_t s_key;
90 static std::once_flag s_onceFlag;
91
92 static void* get()
93 {
94 if (!s_didInitialize)
95 return nullptr;
96 return pthread_getspecific(s_key);
97 }
98
99 static void init(void* object, void (*destructor)(void*))
100 {
101 std::call_once(s_onceFlag, [destructor]() {
102 int error = pthread_key_create(&s_key, destructor);
103 if (error)
104 BCRASH();
105 s_didInitialize = true;
106 });
107 pthread_setspecific(s_key, object);
108 }
109};
110
111class Cache;
112class Heap;
113
114template<> bool PerThreadStorage<PerHeapKind<Cache>>::s_didInitialize;
115template<> pthread_key_t PerThreadStorage<PerHeapKind<Cache>>::s_key;
116template<> std::once_flag PerThreadStorage<PerHeapKind<Cache>>::s_onceFlag;
117
118template<> bool PerThreadStorage<PerHeapKind<Heap>>::s_didInitialize;
119template<> pthread_key_t PerThreadStorage<PerHeapKind<Heap>>::s_key;
120template<> std::once_flag PerThreadStorage<PerHeapKind<Heap>>::s_onceFlag;
121
122#endif
123
124template<typename T>
125BINLINE T* PerThread<T>::getFastCase()
126{
127 return static_cast<T*>(PerThreadStorage<T>::get());
128}
129
130template<typename T>
131inline T* PerThread<T>::get()
132{
133 T* t = getFastCase();
134 if (!t)
135 return getSlowCase();
136 return t;
137}
138
139template<typename T>
140void PerThread<T>::destructor(void* p)
141{
142 T* t = static_cast<T*>(p);
143 t->~T();
144 vmDeallocate(t, vmSize(sizeof(T)));
145}
146
147template<typename T>
148T* PerThread<T>::getSlowCase()
149{
150 BASSERT(!getFastCase());
151 T* t = static_cast<T*>(vmAllocate(vmSize(sizeof(T))));
152 new (t) T();
153 PerThreadStorage<T>::init(t, destructor);
154 return t;
155}
156
157} // namespace bmalloc
158
159#endif // PerThread_h
160