bmalloc: Refactored SegregatedFreeList and BoundaryTag::init
[WebKit-https.git] / Source / bmalloc / bmalloc / PerThread.h
1 /*
2  * Copyright (C) 2014 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 "BPlatform.h"
30 #include "Inline.h"
31 #include <mutex>
32 #include <pthread.h>
33
34 #if defined(__has_include)
35 #if __has_include(<System/pthread_machdep.h>)
36 #include <System/pthread_machdep.h>
37 #define HAVE_PTHREAD_MACHDEP_H 1
38 #else
39 #define HAVE_PTHREAD_MACHDEP_H 0
40 #endif
41 #else
42 #define HAVE_PTHREAD_MACHDEP_H 0
43 #endif
44
45 namespace bmalloc {
46
47 // Usage:
48 //     Object* object = PerThread<Object>::get();
49
50 template<typename T>
51 class PerThread {
52 public:
53     static T* get();
54     static T* getFastCase();
55     static T* getSlowCase();
56
57 private:
58     static void destructor(void*);
59 };
60
61 #if HAVE_PTHREAD_MACHDEP_H
62
63 class Cache;
64 template<typename T> struct PerThreadStorage;
65
66 // For now, we only support PerThread<Cache>. We can expand to other types by
67 // using more keys.
68 template<> struct PerThreadStorage<Cache> {
69     static const pthread_key_t key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
70
71     static void* get()
72     {
73         return _pthread_getspecific_direct(key);
74     }
75
76     static void init(void* object, void (*destructor)(void*))
77     {
78         _pthread_setspecific_direct(key, object);
79         pthread_key_init_np(key, destructor);
80     }
81 };
82
83 #else
84
85 template<typename T> struct PerThreadStorage {
86     static bool s_didInitialize;
87     static pthread_key_t s_key;
88     static std::once_flag s_onceFlag;
89     
90     static void* get()
91     {
92         if (!s_didInitialize)
93             return nullptr;
94         return pthread_getspecific(s_key);
95     }
96     
97     static void init(void* object, void (*destructor)(void*))
98     {
99         std::call_once(s_onceFlag, [destructor]() {
100             pthread_key_create(&s_key, destructor);
101             s_didInitialize = true;
102         });
103         pthread_setspecific(s_key, object);
104     }
105 };
106
107 template<typename T> bool PerThreadStorage<T>::s_didInitialize;
108 template<typename T> pthread_key_t PerThreadStorage<T>::s_key;
109 template<typename T> std::once_flag PerThreadStorage<T>::s_onceFlag;
110
111 #endif
112
113 template<typename T>
114 INLINE T* PerThread<T>::getFastCase()
115 {
116     return static_cast<T*>(PerThreadStorage<T>::get());
117 }
118
119 template<typename T>
120 inline T* PerThread<T>::get()
121 {
122     T* t = getFastCase();
123     if (!t)
124         return getSlowCase();
125     return t;
126 }
127
128 template<typename T>
129 void PerThread<T>::destructor(void* p)
130 {
131     T* t = static_cast<T*>(p);
132     delete t;
133 }
134
135 template<typename T>
136 T* PerThread<T>::getSlowCase()
137 {
138     BASSERT(!getFastCase());
139     T* t = new T;
140     PerThreadStorage<T>::init(t, destructor);
141     return t;
142 }
143
144 } // namespace bmalloc
145
146 #endif // PerThread_h