1616 * Due to some restrictions of the language implementations, especially, on musl/aarch64,
1717 * they cannot be safely used in profiler.
1818 *
19+ * pthread_(get/set)specific() are not async-signal-safe, according to
20+ * https://man7.org/linux/man-pages/man7/signal-safety.7.html
21+ *
22+ * In POSIX implementation, pthread_setspecific() call can trigger memory allocation
23+ * if the slot is not available.
24+ * Because we depend on the APIs to maintain per-thread data, we need to workaround the
25+ * problem - call pthread_setspecific() at least once before signal is enabled for the
26+ * thread (ideally, the value is set before signal is enabled).
27+ *
1928 * How to use?
2029 * A ThreadLocal should be declared as a static variable, e.g.
2130 *
4049 *
4150 */
4251
52+ #include < unistd.h>
53+
4354// The function to create value if it does not exist
4455typedef void * (*CREATE_FUNC )(void );
4556// Cleanup the value when deleting the key
4657typedef void (*CLEAN_FUNC )(void *);
58+
59+ static constexpr pthread_key_t INVLID_KEY = pthread_key_t (-1 );
60+
4761template <typename T, CREATE_FUNC C = nullptr , CLEAN_FUNC F = nullptr >
4862class ThreadLocal {
4963protected:
5064 pthread_key_t _key;
51- bool _key_valid;
5265
5366public:
5467 ThreadLocal (const ThreadLocal&) = delete ;
5568 ThreadLocal& operator =(const ThreadLocal&) = delete ;
5669
57- ThreadLocal () {
70+ ThreadLocal () : _key( INVLID_KEY ) {
5871 static_assert (sizeof (T) == sizeof (void *),
5972 " ThreadLocal<T> requires sizeof(T)==sizeof(void*); use a pointer type or add a specialization" );
60- _key_valid = pthread_key_create (&_key, F) == 0 ;
73+ pthread_key_create (&_key, F);
6174 // What to do if we can not create a key?
6275 // We probably want to shutdown profiler gracefully, instead of
6376 // aborting user application - We will need this mechanism globally,
6477 // defer to a separate task.
65- assert (_key_valid );
78+ assert (isKeyValid () );
6679 }
6780
6881 ~ThreadLocal () {
69- if (_key_valid ) {
82+ if (isKeyValid () ) {
7083 pthread_key_delete (_key);
7184 } else {
7285 assert (false && " Invalid pthread key" );
7386 }
7487 }
7588
89+ bool isKeyValid () const {
90+ return _key != INVLID_KEY ;
91+ }
92+
7693 /* *
7794 * set(nullptr) will result in the value being recreated when get() is called
7895 * when CREATE_FUNC is not nullptr.
7996 * Note: caller is responsible to free old value, which mirrors thread_local
8097 */
8198 void set (T value) {
82- assert (_key_valid && " Invalid pthread key" );
99+ assert (isKeyValid () && " Invalid pthread key" );
83100 int err = pthread_setspecific (_key, reinterpret_cast <const void *>(value));
84101 assert (err == 0 );
85102 }
86103
87104 T get () {
88- assert (_key_valid && " Invalid pthread key" );
105+ assert (isKeyValid () && " Invalid pthread key" );
89106 void * p = pthread_getspecific (_key);
90107 if (p == nullptr && C != nullptr ) {
91108 p = C ();
@@ -96,7 +113,7 @@ class ThreadLocal {
96113
97114 // Clear the value
98115 void clear () {
99- assert (_key_valid && " Invalid pthread key" );
116+ assert (isKeyValid () && " Invalid pthread key" );
100117 void * p = pthread_getspecific (_key);
101118 if (p == nullptr ) return ;
102119 int err = pthread_setspecific (_key, nullptr );
@@ -112,41 +129,44 @@ template <>
112129class ThreadLocal <double > {
113130protected:
114131 pthread_key_t _key;
115- bool _key_valid;
116132
117133public:
118134 ThreadLocal (const ThreadLocal&) = delete ;
119135 ThreadLocal& operator =(const ThreadLocal&) = delete ;
120136
121- ThreadLocal () {
137+ ThreadLocal () : _key( INVLID_KEY ) {
122138 // Only support 64-bit platforms, double and void* are the same size
123139 static_assert (sizeof (void *) == 8 );
124140 static_assert (sizeof (double ) == 8 );
125- _key_valid = pthread_key_create (&_key, nullptr ) == 0 ;
141+ pthread_key_create (&_key, nullptr );
126142 // What to do if we can not create a key?
127- assert (_key_valid && " Invalid pthread key" );
143+ assert (isKeyValid () && " Invalid pthread key" );
128144 }
129145
130146 ~ThreadLocal () {
131- if (_key_valid ) {
147+ if (isKeyValid () ) {
132148 pthread_key_delete (_key);
133149 } else {
134- assert (_key_valid && " Invalid pthread key" );
150+ assert (isKeyValid () && " Invalid pthread key" );
135151 }
136152 }
137153
154+ bool isKeyValid () const {
155+ return _key != INVLID_KEY ;
156+ }
157+
138158 // double <--> u64 cast, preserve bit format
139159 // Can use std::bit_cast after upgrade C++ version to 20
140160 void set (double value) {
141- assert (_key_valid && " Invalid pthread key" );
161+ assert (isKeyValid () && " Invalid pthread key" );
142162 u64 val;
143163 memcpy (&val, &value, sizeof (value));
144164 int err = pthread_setspecific (_key, reinterpret_cast <const void *>(val));
145165 assert (err == 0 );
146166 }
147167
148- double get () {
149- assert (_key_valid && " Invalid pthread key" );
168+ double get () const {
169+ assert (isKeyValid () && " Invalid pthread key" );
150170 void * p = pthread_getspecific (_key);
151171 if (p == nullptr ) {
152172 return 0.0 ;
@@ -159,10 +179,69 @@ class ThreadLocal<double> {
159179 }
160180
161181 void clear () {
162- assert (_key_valid && " Invalid pthread key" );
182+ assert (isKeyValid () && " Invalid pthread key" );
163183 int err = pthread_setspecific (_key, nullptr );
164184 assert (err == 0 );
165185 }
166186};
167187
188+ class JVMThread ;
189+
190+ /* *
191+ * This thread local mirrors JVM's Thread::current(). The value is set by JVM
192+ * and it is read-only variable.
193+ */
194+ template <>
195+ class ThreadLocal <JVMThread*> {
196+ protected:
197+ pthread_key_t _key;
198+
199+ public:
200+ ThreadLocal (const ThreadLocal&) = delete ;
201+ ThreadLocal& operator =(const ThreadLocal&) = delete ;
202+
203+ ThreadLocal () : _key(INVLID_KEY ) {
204+ }
205+
206+ void initialize (void * current_thread) {
207+ // Called from known JavaThread, it should never be nullptr.
208+ if (current_thread == nullptr ) {
209+ assert (false && " Should not reach here" );
210+ }
211+
212+ long max_keys = sysconf (_SC_THREAD_KEYS_MAX);
213+
214+ for (long i = 0 ; i < max_keys; i++) {
215+ if (pthread_getspecific ((pthread_key_t )i) == current_thread) {
216+ _key = pthread_key_t (i);
217+ break ;
218+ }
219+ }
220+
221+ assert (isKeyValid () && " Invalid thread key" );
222+ }
223+
224+ bool isKeyValid () const {
225+ return _key != INVLID_KEY ;
226+ }
227+
228+ pthread_key_t key () const {
229+ return _key;
230+ }
231+
232+ void set (JVMThread* value) {
233+ assert (false && " Should not reach here, value is set by JVM" );
234+ }
235+
236+ void * get () const {
237+ assert (isKeyValid () && " Invalid pthread key" );
238+ return pthread_getspecific (_key);
239+ }
240+
241+ void clear () {
242+ assert (false && " Should not reach here" );
243+ }
244+ };
245+
246+
168247#endif // _THREADLOCAL_H
0 commit comments