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