aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.ckati2
-rw-r--r--stats.cc13
-rw-r--r--thread_local.h91
3 files changed, 99 insertions, 7 deletions
diff --git a/Makefile.ckati b/Makefile.ckati
index cd8a0f8..f35824b 100644
--- a/Makefile.ckati
+++ b/Makefile.ckati
@@ -71,7 +71,7 @@ KATI_CXXFLAGS += -O -DNOLOG
#KATI_CXXFLAGS += -pg
ifeq ($(shell uname),Linux)
-KATI_LIBS := -lrt
+KATI_LIBS := -lrt -lpthread
endif
# Rule to build ckati into KATI_BIN_PATH
diff --git a/stats.cc b/stats.cc
index 0e23e84..ec11e7f 100644
--- a/stats.cc
+++ b/stats.cc
@@ -22,12 +22,13 @@
#include "flags.h"
#include "log.h"
#include "stringprintf.h"
+#include "thread_local.h"
#include "timeutil.h"
namespace {
vector<Stats*>* g_stats;
-thread_local double g_start_time = 0.0;
+DEFINE_THREAD_LOCAL(double, g_start_time);
} // namespace
@@ -44,16 +45,16 @@ string Stats::String() const {
}
void Stats::Start() {
- CHECK(!g_start_time);
- g_start_time = GetTime();
+ CHECK(!g_start_time.Ref());
+ g_start_time.Ref() = GetTime();
unique_lock<mutex> lock(mu_);
cnt_++;
}
double Stats::End() {
- CHECK(g_start_time);
- double e = GetTime() - g_start_time;
- g_start_time = 0;
+ CHECK(g_start_time.Ref());
+ double e = GetTime() - g_start_time.Ref();
+ g_start_time.Ref() = 0;
unique_lock<mutex> lock(mu_);
elapsed_ += e;
return e;
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_