blob: d9d5191aef5cca625f6e30c1fae7611fa65c0e69 [file] [log] [blame]
Shinichiro Hamaji4197da62016-01-25 16:06:29 +09001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// A simple cross platform thread local storage implementation.
6//
7// This is a drop-in replacement of __thread keyword. If your compiler
8// toolchain supports __thread keyword, the user of this code should
9// be as fast as the code which uses __thread. Chrome's
10// base::ThreadLocalPointer and base::ThreadLocalStorage cannot be as
11// fast as __thread.
12// TODO(crbug.com/249345): If pthread_getspecific is slow for our use,
13// expose bionic's internal TLS and stop using pthread_getspecific
14// based implementation.
15//
16// Usage:
17//
18// Before (linux):
19//
20// __thread Foo* foo;
21// foo = new Foo();
22// foo->func();
23//
24//
25// After:
26//
27// DEFINE_THREAD_LOCAL(Foo*, foo);
28// foo.Ref() = new Foo();
29// foo.Ref()->func();
30//
31// Thread local PODs are zero-initialized.
32// Thread local non-PODs are initialized with the default constructor.
33
34#ifndef THREAD_LOCAL_H_
35#define THREAD_LOCAL_H_
36
37#include <errno.h>
38#include <pthread.h>
39
40#include "log.h"
41
Shinichiro Hamaji545b6a22016-02-15 18:43:47 +090042#ifdef __linux__
43
44#define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name
45#define TLS_REF(x) x
46
47#else
48
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090049// Thread local storage implementation which uses pthread.
50// Note that DEFINE_THREAD_LOCAL creates a global variable just like
51// thread local storage based on __thread keyword. So we should not use
52// constructor in ThreadLocal class to avoid static initializator.
53template <typename Type>
54void ThreadLocalDestructor(void* ptr) {
55 delete reinterpret_cast<Type>(ptr);
56}
57
Dan Willemsen3ce083f2017-10-11 22:17:48 -070058template <typename Type, pthread_key_t* key>
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090059void ThreadLocalInit() {
60 if (pthread_key_create(key, ThreadLocalDestructor<Type>))
61 ERROR("Failed to create a pthread key for TLS errno=%d", errno);
62}
63
Dan Willemsen3ce083f2017-10-11 22:17:48 -070064template <typename Type, pthread_key_t* key, pthread_once_t* once>
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090065class ThreadLocal {
66 public:
Dan Willemsen3ce083f2017-10-11 22:17:48 -070067 Type& Ref() { return *GetPointer(); }
68 Type Get() { return Ref(); }
69 void Set(const Type& value) { Ref() = value; }
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090070 Type* GetPointer() {
71 pthread_once(once, ThreadLocalInit<Type*, key>);
72 Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key));
Dan Willemsen3ce083f2017-10-11 22:17:48 -070073 if (value)
74 return value;
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090075 // new Type() for PODs means zero initialization.
76 value = new Type();
77 int error = pthread_setspecific(*key, value);
78 if (error != 0)
79 ERROR("Failed to set a TLS: error=%d", error);
80 return value;
81 }
82};
83
84// We need a namespace for name##_key and name##_once since template parameters
85// do not accept unnamed values such as static global variables.
Dan Willemsen3ce083f2017-10-11 22:17:48 -070086#define DEFINE_THREAD_LOCAL(Type, name) \
87 namespace { \
88 pthread_once_t name##_once = PTHREAD_ONCE_INIT; \
89 pthread_key_t name##_key; \
90 } \
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090091 ThreadLocal<Type, &name##_key, &name##_once> name;
92
Shinichiro Hamaji545b6a22016-02-15 18:43:47 +090093#define TLS_REF(x) x.Ref()
94
95#endif
96
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090097#endif // THREAD_LOCAL_H_