aboutsummaryrefslogtreecommitdiff
path: root/thread_local.h
diff options
context:
space:
mode:
Diffstat (limited to 'thread_local.h')
-rw-r--r--thread_local.h91
1 files changed, 91 insertions, 0 deletions
diff --git a/thread_local.h b/thread_local.h
new file mode 100644
index 0000000..3bbf663
--- /dev/null
+++ b/thread_local.h
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A simple cross platform thread local storage implementation.
+//
+// This is a drop-in replacement of __thread keyword. If your compiler
+// toolchain supports __thread keyword, the user of this code should
+// be as fast as the code which uses __thread. Chrome's
+// base::ThreadLocalPointer and base::ThreadLocalStorage cannot be as
+// fast as __thread.
+// TODO(crbug.com/249345): If pthread_getspecific is slow for our use,
+// expose bionic's internal TLS and stop using pthread_getspecific
+// based implementation.
+//
+// Usage:
+//
+// Before (linux):
+//
+// __thread Foo* foo;
+// foo = new Foo();
+// foo->func();
+//
+//
+// After:
+//
+// DEFINE_THREAD_LOCAL(Foo*, foo);
+// foo.Ref() = new Foo();
+// foo.Ref()->func();
+//
+// Thread local PODs are zero-initialized.
+// Thread local non-PODs are initialized with the default constructor.
+
+#ifndef THREAD_LOCAL_H_
+#define THREAD_LOCAL_H_
+
+#include <errno.h>
+#include <pthread.h>
+
+#include "log.h"
+
+// Thread local storage implementation which uses pthread.
+// Note that DEFINE_THREAD_LOCAL creates a global variable just like
+// thread local storage based on __thread keyword. So we should not use
+// constructor in ThreadLocal class to avoid static initializator.
+template <typename Type>
+void ThreadLocalDestructor(void* ptr) {
+ delete reinterpret_cast<Type>(ptr);
+}
+
+template<typename Type, pthread_key_t* key>
+void ThreadLocalInit() {
+ if (pthread_key_create(key, ThreadLocalDestructor<Type>))
+ ERROR("Failed to create a pthread key for TLS errno=%d", errno);
+}
+
+template<typename Type, pthread_key_t* key, pthread_once_t* once>
+class ThreadLocal {
+ public:
+ Type& Ref() {
+ return *GetPointer();
+ }
+ Type Get() {
+ return Ref();
+ }
+ void Set(const Type& value) {
+ Ref() = value;
+ }
+ Type* GetPointer() {
+ pthread_once(once, ThreadLocalInit<Type*, key>);
+ Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key));
+ if (value) return value;
+ // new Type() for PODs means zero initialization.
+ value = new Type();
+ int error = pthread_setspecific(*key, value);
+ if (error != 0)
+ ERROR("Failed to set a TLS: error=%d", error);
+ return value;
+ }
+};
+
+// We need a namespace for name##_key and name##_once since template parameters
+// do not accept unnamed values such as static global variables.
+#define DEFINE_THREAD_LOCAL(Type, name) \
+ namespace { \
+ pthread_once_t name##_once = PTHREAD_ONCE_INIT; \
+ pthread_key_t name##_key; \
+ } \
+ ThreadLocal<Type, &name##_key, &name##_once> name;
+
+#endif // THREAD_LOCAL_H_